mirror of
https://github.com/leafo/moonscript.git
synced 2024-11-22 02:44:23 +00:00
160 lines
3.4 KiB
Lua
Executable File
160 lines
3.4 KiB
Lua
Executable File
#!/usr/bin/lua
|
|
|
|
module("moonscript", package.seeall)
|
|
|
|
require "moonscript.parse"
|
|
require "moonscript.compile"
|
|
require "moonscript.util"
|
|
|
|
require "alt_getopt"
|
|
|
|
require "lpeg"
|
|
|
|
-- moonloader and repl
|
|
local opts, ind = alt_getopt.get_opts(arg, "ch", { help = "h" })
|
|
|
|
local help = [=[Usage: %s [options] [script [args]]
|
|
|
|
-c Compile in memory, don't write .lua files
|
|
-h Print this message
|
|
]=]
|
|
|
|
local function print_help(err)
|
|
if err then print("Error: "..err) end
|
|
print(help:format(arg[0]))
|
|
os.exit()
|
|
end
|
|
|
|
if opts.h then print_help() end
|
|
|
|
local script = arg[ind]
|
|
if not script then
|
|
print_help("repl not yet supported")
|
|
return
|
|
end
|
|
|
|
local dirsep = "/"
|
|
local function create_moonpath(package_path)
|
|
local paths = util.split(package_path, ";")
|
|
for i=1,#paths do
|
|
local p = paths[i]:match("^(.-)%.lua$")
|
|
if p then
|
|
paths[i] = p..".moon"
|
|
end
|
|
end
|
|
return table.concat(paths, ";")
|
|
end
|
|
|
|
local line_tables = {}
|
|
local function moon_chunk(file, file_path)
|
|
local text = file:read"*a"
|
|
local tree, err = parse.string(text)
|
|
if not tree then error("Parse error: "..err) end
|
|
local code, ltable, pos = compile.tree(tree)
|
|
if not code then
|
|
error(compile.format_error(ltable, pos, text))
|
|
end
|
|
|
|
line_tables[file_path] = ltable
|
|
|
|
return load(function()
|
|
local out = code
|
|
code = nil
|
|
return out
|
|
end, file_path)
|
|
end
|
|
|
|
local function moon_loader(name)
|
|
name_path = name:gsub("%.", dirsep)
|
|
paths = util.split(package.moonpath, ";")
|
|
|
|
local file, file_path
|
|
for i=1,#paths do
|
|
file_path = paths[i]:gsub("?", name_path)
|
|
file = io.open(file_path)
|
|
if file then break end
|
|
end
|
|
|
|
if not file then
|
|
return nil, "Could not find moon file"
|
|
end
|
|
|
|
return moon_chunk(file, file_path)
|
|
end
|
|
|
|
if not package.moonpath then
|
|
package.moonpath = create_moonpath(package.path)
|
|
end
|
|
|
|
table.insert(package.loaders, 2, moon_loader)
|
|
|
|
local lookup_text = {}
|
|
local function lookup_line(fname, pos)
|
|
if not lookup_text[fname] then
|
|
local f = io.open(fname)
|
|
lookup_text[fname] = f:read"*a"
|
|
f:close()
|
|
end
|
|
|
|
local sub = lookup_text[fname]:sub(1, pos)
|
|
local count = 1
|
|
for _ in sub:gmatch("\n") do
|
|
count = count + 1
|
|
end
|
|
return count
|
|
end
|
|
|
|
local function reverse_line(fname, line_table, line)
|
|
for i = line,0,-1 do
|
|
if line_table[i] then
|
|
return lookup_line(fname, line_table[i])
|
|
end
|
|
end
|
|
return "unknown"
|
|
end
|
|
|
|
local function rewrite_traceback(text, err)
|
|
local header_text = "stack traceback:"
|
|
|
|
local Header, Line = lpeg.V"Header", lpeg.V"Line"
|
|
local Break = lpeg.S"\n"
|
|
local g = lpeg.P {
|
|
Header,
|
|
Header = header_text * Break * lpeg.Ct(Line^1),
|
|
Line = "\t" * lpeg.C((1 -Break)^0) * (Break + -1)
|
|
}
|
|
|
|
local match = g:match(text)
|
|
table.insert(match, 1, err)
|
|
for i, trace in pairs(match) do
|
|
local fname, line, msg = trace:match('^%[string "(.-)"]:(%d+): (.*)$')
|
|
if fname then
|
|
if line_tables[fname] then
|
|
local table = line_tables[fname]
|
|
match[i] = fname .. ":" ..
|
|
reverse_line(fname, table, line) .. ": " .. msg
|
|
end
|
|
end
|
|
end
|
|
|
|
return header_text .. "\n\t" .. table.concat(match, "\n\t")
|
|
end
|
|
|
|
local file, err = io.open(script)
|
|
if not file then error(err) end
|
|
|
|
local new_arg = {
|
|
[-1] = arg[0],
|
|
[0] = arg[ind],
|
|
select(ind + 1, unpack(arg))
|
|
}
|
|
|
|
local chunk = moon_chunk(file, script)
|
|
getfenv(chunk).arg = new_arg
|
|
|
|
local runner = coroutine.create(chunk)
|
|
local success, err = coroutine.resume(runner, unpack(new_arg))
|
|
if not success then
|
|
print(rewrite_traceback(debug.traceback(runner), err))
|
|
end
|