`Function node encountered while traversing faulty AST
Hi,
I'm on branch konekildt. I created an AST containing an error, while traversing it, I got a function instead of an ``Error` node. Here is the code to reproduce.
require 'metalua.compiler'
local walk = require 'metalua.treequery.walk'['block']
local ast = mlc.luastring_to_ast( 'f = function()x end')
local errorhandling = function(node, ...)
table.print(node, 'nohash', 1)
end
local cfg = { error = errorhandling }
walk(cfg, ast)
Here is the output
$ metalua functionerror.lua
`Function{ { },
{ `Error "line 1, char 15: This expression (\"x\") is an identifier; a statement was expected, and only function and method call expressions can be used as statements\n>>> f = function()x end\n>>> ^" },
`Error "A keyword was expected, probably `end'." }
I browsed the code to find where this bug may come from walk.mlua in M.traverse.expr. In the match statement, the faulty function node does not match the guard ``Function{ params, body }` and is treated like an error node.
match x with
| `Paren{ e } -> E(e)
| `Call{...} | `Invoke{...} -> EL(x)
| `Index{ a, b } -> E(a); E(b)
| `Op{ opid, ... } -> E(x[2]); if #x==3 then E(x[3]) end
| `Function{ params, body } -> OS(body); IL(params); B(body); CS(body)
| `Stat{ b, e } -> OS(body); B(b); E(e); CS(body)
| `Id{ name } -> M.occurrence(cfg, x, unpack(ancestors))
| `Table{ ... } ->
for i = 1, #x do match x[i] with
| `Pair{ k, v } -> E(k); E(v)
| v -> E(v)
end end
| `Nil|`Dots|`True|`False|`Number{_}|`String{_} -> -- terminal node
| { tag=tag, ...} if M.tags.expr[tag]-> M.malformed (cfg, x, unpack (ancestors))
| _ -> M.unknown (cfg, x, unpack (ancestors))
end
I think the cause of its malformation comes from funcdef_builder in mlp_stat.lua, where we can see a Function{ {}, {}, {} }` is created in error cases, instead of a Function{ {}, {} }aswalk.traverse.expr` expects it.
local function funcdef_builder(x)
local name = x[1] or gg.earlier_error()
local method = x[2]
local func = x[3] or gg.earlier_error()
if method then
name = { tag="Index", name, method, lineinfo = {
first = name.lineinfo.first,
last = method.lineinfo.last } }
_G.table.insert (func[1], 1, {tag="Id", "self"})
end
local r = { tag="Set", {name}, {func} }
r[1].lineinfo = name.lineinfo
r[2].lineinfo = func.lineinfo
return r
end
So I think I get the bug, but I am not sure of the clean way to fix it, should I:
- Fix the way the ``Function{ {}, {}, {} }
is created infuncdef_builder`? - Catch ``Function
in the error node handling inM.traverse.expr`?
Do you have a better idea?