diff --git a/metalua/grammar/generator.lua b/metalua/grammar/generator.lua index 4633c6e..fc04750 100644 --- a/metalua/grammar/generator.lua +++ b/metalua/grammar/generator.lua @@ -149,17 +149,46 @@ end -- Generate a tracable parsing error (not implemented yet) ------------------------------------------------------------------------------- function M.parse_error(lx, fmt, ...) - local li = lx:lineinfo_left() + local inf = lx:lineinfo_error() local file, line, column, offset, positions - if li then + local p_line, p_column + if inf then + local li = inf.last file, line, column, offset = li.source, li.line, li.column, li.offset - positions = { first = li, last = li } + local first = inf.first + positions = { first = first, last = li } + + local facing = inf.first.facing + local no_invalid_comment = function(comments) + for _, c in ipairs(comments) do + if c[1]:match("%[%[") then + return false + end + end + return true + end + -- in case of a parse error, the consumed token usually facing the one + -- that caused the problem is the last valid one, allowing us to point + -- to the exact location where the invalid token starts + -- there are exceptions to this, identified so far: + -- * there's just one token yet + -- * there are comment(s) after the last valid token + if (facing.line >= first.line and facing.column >= first.column) or + (facing.comments and no_invalid_comment(facing.comments)) + then + p_line, p_column = first.line, first.column + else + p_line, p_column = facing.line, facing.column + end else - line, column, offset = -1, -1, -1 + line, column, offset, p_line, p_column = -1, -1, -1, -1, -1 end local msg = string.format("line %i, char %i: "..fmt, line, column, ...) if file and file~='?' then msg = "file "..file..", "..msg end + local prev_token = string.format("facing: line %i, char %i", p_line, p_column) + msg = string.format("%s\n%s", msg, prev_token) + local src = lx.src if offset>0 and src then diff --git a/metalua/grammar/lexer.lua b/metalua/grammar/lexer.lua index 0a58058..26bd1a2 100644 --- a/metalua/grammar/lexer.lua +++ b/metalua/grammar/lexer.lua @@ -511,6 +511,7 @@ function lexer :next (n) -- TODO: is this used anywhere? I think not. a.lineinfo.last may be nil. --self.lastline = a.lineinfo.last.line end + self.lineinfo_consumed = a.lineinfo self.lineinfo_last_consumed = a.lineinfo.last return a end @@ -574,6 +575,10 @@ function lexer :lineinfo_left() return self.lineinfo_last_consumed end +function lexer :lineinfo_error() + return self.lineinfo_consumed +end + ---------------------------------------------------------------------- -- Create a new lexstream. ----------------------------------------------------------------------