mirror of
https://github.com/leafo/moonscript.git
synced 2024-11-22 02:44:23 +00:00
simple stack rewriting
This commit is contained in:
parent
f0b3690362
commit
56c3af06d2
68
moon
68
moon
@ -8,6 +8,8 @@ require "moonscript.util"
|
||||
|
||||
require "alt_getopt"
|
||||
|
||||
require "lpeg"
|
||||
|
||||
-- moonloader and repl
|
||||
local opts, ind = alt_getopt.get_opts(arg, "ch", { help = "h" })
|
||||
|
||||
@ -43,11 +45,13 @@ local function create_moonpath(package_path)
|
||||
return table.concat(paths, ";")
|
||||
end
|
||||
|
||||
local line_tables = {}
|
||||
local function moon_chunk(file, file_path)
|
||||
-- print("loading", file_path)
|
||||
local tree, err = parse.string(file:read"*a")
|
||||
if not tree then error("Parse error: "..err) end
|
||||
local code = compile.tree(tree)
|
||||
local code, ltable = compile.tree(tree)
|
||||
|
||||
line_tables[file_path] = ltable
|
||||
|
||||
return load(function()
|
||||
local out = code
|
||||
@ -74,13 +78,64 @@ local function moon_loader(name)
|
||||
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
|
||||
|
||||
@ -92,4 +147,9 @@ local new_arg = {
|
||||
|
||||
local chunk = moon_chunk(file, script)
|
||||
getfenv(chunk).arg = new_arg
|
||||
chunk(unpack(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
|
||||
|
@ -68,3 +68,10 @@ has_value = function(node)
|
||||
end
|
||||
end
|
||||
is_non_atomic = function(node) return non_atomic[ntype(node)] end
|
||||
count_lines = function(str)
|
||||
local count = 1
|
||||
for _ in str:gmatch("\n") do
|
||||
count = count + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
@ -8,6 +8,7 @@ import Set, ntype from data
|
||||
import concat, insert from table
|
||||
|
||||
export indent_char, pretty, returner, moonlib, cascading, non_atomic, has_value, is_non_atomic
|
||||
export count_lines
|
||||
|
||||
indent_char = " "
|
||||
pretty = (lines, indent) ->
|
||||
@ -56,3 +57,9 @@ has_value = (node) ->
|
||||
|
||||
is_non_atomic = (node) ->
|
||||
non_atomic[ntype(node)]
|
||||
|
||||
count_lines = (str) ->
|
||||
count = 1
|
||||
count += 1 for _ in str\gmatch "\n"
|
||||
count
|
||||
|
||||
|
@ -179,6 +179,7 @@ local value_compile = {
|
||||
local Block
|
||||
Block = (function(_parent_0)
|
||||
local _base_0 = {
|
||||
line_table = function(self) return self._posmap end,
|
||||
set = function(self, name, value) self._state[name] = value end,
|
||||
get = function(self, name) return self._state[name] end,
|
||||
set_indent = function(self, depth)
|
||||
@ -220,6 +221,7 @@ Block = (function(_parent_0)
|
||||
end
|
||||
return name
|
||||
end,
|
||||
mark_pos = function(self, node) self._posmap[#self._lines + 1] = node[-1] end,
|
||||
add_lines = function(self, lines)
|
||||
local _item_0 = lines
|
||||
for _index_0=1,#_item_0 do
|
||||
@ -263,6 +265,7 @@ Block = (function(_parent_0)
|
||||
if not fn then
|
||||
error("Failed to compile value: " .. dump.value(node))
|
||||
end
|
||||
self:mark_pos(node)
|
||||
return fn(self, node, ...)
|
||||
end,
|
||||
values = function(self, values, delim)
|
||||
@ -336,6 +339,7 @@ Block = (function(_parent_0)
|
||||
self.parent = parent
|
||||
self:set_indent(self.parent and self.parent.indent + 1 or 0)
|
||||
self._lines = { }
|
||||
self._posmap = { }
|
||||
self._names = { }
|
||||
self._state = { }
|
||||
if self.parent then
|
||||
@ -360,5 +364,5 @@ tree = function(tree)
|
||||
local line = _item_0[_index_0]
|
||||
scope:stm(line)
|
||||
end
|
||||
return scope:render()
|
||||
return scope:render(), scope:line_table()
|
||||
end
|
||||
|
@ -163,6 +163,7 @@ class Block
|
||||
new: (@parent) =>
|
||||
@set_indent @parent and @parent.indent + 1 or 0
|
||||
@_lines = {}
|
||||
@_posmap = {}
|
||||
@_names = {}
|
||||
@_state = {}
|
||||
|
||||
@ -170,6 +171,9 @@ class Block
|
||||
setmetatable @_state, { __index: @parent._state }
|
||||
setmetatable @_names, { __index: @parent._names }
|
||||
|
||||
line_table: =>
|
||||
@_posmap
|
||||
|
||||
set: (name, value) =>
|
||||
@_state[name] = value
|
||||
|
||||
@ -203,6 +207,9 @@ class Block
|
||||
@put_name name if not dont_put
|
||||
name
|
||||
|
||||
mark_pos: (node) =>
|
||||
@_posmap[#@_lines + 1] = node[-1]
|
||||
|
||||
add_lines: (lines) =>
|
||||
insert @_lines, line for line in *lines
|
||||
nil
|
||||
@ -244,6 +251,7 @@ class Block
|
||||
return tostring node if type(node) != "table"
|
||||
fn = value_compile[node[1]]
|
||||
error "Failed to compile value: "..dump.value node if not fn
|
||||
@mark_pos node
|
||||
fn self, node, ...
|
||||
|
||||
values: (values, delim) =>
|
||||
@ -303,5 +311,8 @@ build_compiler = ->
|
||||
tree = (tree) ->
|
||||
scope = Block!
|
||||
scope\stm line for line in *tree
|
||||
scope\render!
|
||||
|
||||
-- print util.dump scope._posmap
|
||||
|
||||
scope\render!, scope\line_table!
|
||||
|
||||
|
@ -11,7 +11,9 @@ local function flat_value(op, depth)
|
||||
table.insert(items, flat_value(item, depth+1))
|
||||
end
|
||||
|
||||
return "{"..table.concat(items, ", ").."}"
|
||||
local pos = op[-1]
|
||||
|
||||
return "{"..(pos and "["..pos.."] " or "")..table.concat(items, ", ").."}"
|
||||
end
|
||||
|
||||
function value(op)
|
||||
|
@ -75,6 +75,17 @@ local function mark(name)
|
||||
end
|
||||
end
|
||||
|
||||
local function insert_pos(pos, value)
|
||||
if type(value) == "table" then
|
||||
value[-1] = pos
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function pos(patt)
|
||||
return (lpeg.Cp() * patt) / insert_pos
|
||||
end
|
||||
|
||||
local function got(what)
|
||||
return Cmt("", function(str, pos, ...)
|
||||
local cap = {...}
|
||||
@ -294,10 +305,10 @@ local build_grammar = wrap(function()
|
||||
ChainValue =
|
||||
((Chain + DotChain + Callable) * Ct(ExpList^0)) / flatten_func,
|
||||
|
||||
Value =
|
||||
Value = pos(
|
||||
SimpleValue +
|
||||
Ct(KeyValueList) / mark"table" +
|
||||
ChainValue,
|
||||
ChainValue),
|
||||
|
||||
SliceValue = SimpleValue + ChainValue,
|
||||
|
||||
@ -405,7 +416,6 @@ local build_grammar = wrap(function()
|
||||
print("stopped at", line_no)
|
||||
error(err)
|
||||
end
|
||||
|
||||
|
||||
if not tree then
|
||||
local line_no = pos_to_line(last_pos)
|
||||
|
Loading…
Reference in New Issue
Block a user