-
Notifications
You must be signed in to change notification settings - Fork 191
Moonscriptrepl
This is a simple interactive MoonScript prompt, which is already useful within its limitations. The main thing is that it cannot detect whether a statement starts a block, so you have to either use a final backslash or tab. If these are detected, then the block continues until an empty line.
If the moondump
module is available (see Pretty Table Dumper it will use that. The Lua `linenoise' module is used on platforms that support it (available through LuaRocks) for basic line editing and history.
mooni
does two hacks to make MoonScript work interactively; the first is to strip the first local
statement from the generated Lua code, so that any created variables are global; the second is to keep track of created globals and force MoonScript to recognize them with a fake local
declaration. The problem is the opposite of the usual 'destructive assignment' issue.
Example session (assumes that moondump
is available):
scratch$ mooni
MoonScript version 0.2.3
Note: use backslash or tab to start a block
> i = 1
> i
1
> [x for x = 1,5]
{1,2,3,4,5}
> #_l
5
> S = (x) -> x*x
> [S x for x = 1,10]
{1,4,9,16,25,36,49,64,81,100}
> for i = 1,5 \
>> print 'hello', i
>>
hello 1
hello 2
hello 3
hello 4
hello 5
Like Lua, it also understands -l
for 'load library' and -e
for 'evaluate expression':
scratch$ mooni -llfs -e 'lfs.currentdir!'
/home/steve/moonscript/scratch
#!/usr/bin/env moon
----- mooni -----
-- A basic MoonScript REPL
--
parse = require "moonscript.parse"
compile = require "moonscript.compile"
append = table.insert
-- need to keep track of what globals have been added during the session
oldg = {k,v for k,v in pairs _G}
_G._FOO = true
-- (this will return their names)
newglobs = -> [k for k in pairs _G when not oldg[k]]
chopline = (txt) -> txt\gsub '^[^\n]+\n','', 1
firstline = (txt) -> txt\match '^[^\n]*'
mytostring = tostring
capture = (ok,...) ->
t = {...}
t.n = select '#',...
return ok,t
eval_lua = (lua_code) ->
chunk,err = load lua_code, 'tmp'
if err -- Lua compile error is rare!
print err
return
ok,res = capture pcall chunk
if not ok -- runtime error
print res[1]
return
elseif #res > 0
-- this allows for overriding basic value printing
_G._l = res[1] -- save last value calculated
out = [mytostring res[i] for i = 1,res.n]
io.write table.concat(out,'\t'),'\n'
old_lua_code = nil
translate = (moon_code) ->
-- Ugly fiddle #2: we force Moonscript code to regard
-- any _new_ globals as known globals
locs = 'local '..table.concat(newglobs!,',')
moon_code = locs..'\n'..moon_code
tree, err = parse.string moon_code
if not tree
print err
return
lua_code, err, pos = compile.tree tree
if not lua_code
print compile.format_error err, pos, moon_code
return
-- our code is ready
-- Fiddle #2 requires us to lose the top local declarations we inserted
lua_code = chopline lua_code
-- Fiddle #1 Moonscript will of course declare any new variables
-- as local. This fiddle removes the 'local'
was_local, rest = lua_code\match '^local (%S+)(.+)'
if was_local
if rest\match '\n' then rest = firstline rest
-- two cases; either a direct local assignmnent or a declaration line
if rest\match '='
lua_code = lua_code\gsub '^local%s+', ''
else
lua_code = chopline lua_code
old_lua_code = lua_code
eval_lua lua_code
opts,i = {},0
nexta = ->
i += 1
arg[i]
while true
a = nexta!
break if not a
flag,rest = a\match '^%-(%a)(%S*)'
if flag == 'l'
lib = (rest and #rest > 0) and rest or nexta!
require lib
elseif flag == 'e'
translate nexta!
os.exit 0
ok,dump = pcall require,'moondump'
if ok
mytostring = dump
_G.tstring = mytostring
normal, block = '> ','>> '
prompt = normal
get_line = nil
ok,LN = pcall require, 'linenoise'
if ok
get_line = ->
line = LN.linenoise prompt
if line and line\match '%S'
LN.addhistory line
line
else
get_line = ->
io.write prompt
io.read!
print 'MoonScript version 0.2.3'
print 'Note: use backslash or tab to start a block'
while true
line = get_line!
if not line then break
-- a line ending with a tab or a backslash starts a block
if line\match '[\t\\]$'
prompt = block
line = line\gsub '\\$',''
code = {line}
line = get_line!
while #line > 0 -- block ends with empty line
append code, line
line = get_line!
prompt = normal
code = table.concat code, '\n'
translate code
elseif line\match '^%?que'
print old_lua_code
else
translate line