Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New name for Parser:syntax_error() #586

Merged
merged 1 commit into from
Jun 12, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
96 changes: 48 additions & 48 deletions src/pallene/parser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ function Parser:advance()
repeat
tok, err = self.lexer:next()
if not tok then
self:syntax_error(self.lexer:loc(), "%s", err)
self:abort_parsing()
self:abort_with_syntax_error(self.lexer:loc(), "%s", err)
end
if tok.name == "COMMENT" then
table.insert(self.comment_regions, { tok.loc.pos, tok.end_pos })
Expand Down Expand Up @@ -223,26 +222,26 @@ function Parser:Program()
assert(stat._tag == "ast.Stat.Decl")

if #stat.decls > 1 or #stat.exps > 1 then
self:syntax_error(stat.loc,
self:recoverable_syntax_error(stat.loc,
"cannot use a multiple-assignment to declare the module table")
else
local decl = stat.decls[1]; assert(decl)
local exp = stat.exps[1]
local ast_typ = decl.type

if ast_typ and not (ast_typ._tag == "ast.Type.Name" and ast_typ.name == "module") then
self:syntax_error(ast_typ.loc,
self:recoverable_syntax_error(ast_typ.loc,
"if the module variable has a type annotation, it must be exactly 'module'")
end

if not (exp and exp._tag == "ast.Exp.InitList" and #exp.fields == 0) then
self:syntax_error(stat.loc, "the module initializer must be exactly {}")
self:recoverable_syntax_error(stat.loc, "the module initializer must be exactly {}")
end

modname = decl.name
end
else
self:syntax_error(start_loc,
self:recoverable_syntax_error(start_loc,
"must begin with a module declaration; local <modname> = {}")
end

Expand All @@ -259,7 +258,7 @@ function Parser:Program()
if stat._tag == "ast.Stat.Assign" then
for _, var in ipairs(stat.vars) do
if var._tag ~= "ast.Var.Dot" then
self:syntax_error(var.loc,
self:recoverable_syntax_error(var.loc,
"toplevel assignments are only possible with module fields")
end
end
Expand All @@ -277,7 +276,7 @@ function Parser:Program()
-- return <modname>
if return_stat then
if #return_stat.exps ~= 1 then
self:syntax_error(return_stat.loc,
self:recoverable_syntax_error(return_stat.loc,
"the module return statement must return a single value")
else
local exp = return_stat.exps[1]
Expand All @@ -287,20 +286,20 @@ function Parser:Program()
exp.var.name == modname)
then
-- The type checker also needs to check that this name has not been shadowed
self:syntax_error(exp.loc,
self:recoverable_syntax_error(exp.loc,
"must return exactly the module variable '%s'", modname)
end
end

if not self:peek("EOF") then
self:syntax_error(self.next.loc,
self:recoverable_syntax_error(self.next.loc,
"the module return statement must be the last thing in the file")
end
else
if self:peek("EOF") then
local loc = self.next.loc
local what = (modname or "<modname>")
self:syntax_error(loc, "must end by returning the module table; return %s", what)
self:recoverable_syntax_error(loc, "must end by returning the module table; return %s", what)
else
self:unexpected_token_error("a toplevel element")
end
Expand Down Expand Up @@ -348,7 +347,7 @@ function Parser:Toplevel()

for _, stat in ipairs(stats) do
if not is_allowed_toplevel[stat._tag] then
self:syntax_error(stat.loc,
self:recoverable_syntax_error(stat.loc,
"toplevel statements can only be Returns, Declarations or Assignments")
end
end
Expand Down Expand Up @@ -540,11 +539,11 @@ function Parser:find_letrecs(stats)
local declared_names = {}
for _, decl in ipairs(forw_decls) do
if decl.type then
self:syntax_error(decl.loc,
self:recoverable_syntax_error(decl.loc,
"type annotations are not allowed in a function forward declaration")
end
if declared_names[decl.name] then
self:syntax_error(decl.loc,
self:recoverable_syntax_error(decl.loc,
"duplicate forward declaration for '%s'", decl.name)
end
declared_names[decl.name] = true
Expand All @@ -554,7 +553,7 @@ function Parser:find_letrecs(stats)
for _, func in ipairs(funcs) do
if not func.module then
if not declared_names[func.name] then
self:syntax_error(func.loc,
self:recoverable_syntax_error(func.loc,
"function '%s' was not forward declared", func.name)
end
defined_names[func.name] = true
Expand All @@ -563,7 +562,7 @@ function Parser:find_letrecs(stats)

for _, decl in ipairs(forw_decls) do
if not defined_names[decl.name] then
self:syntax_error(decl.loc,
self:recoverable_syntax_error(decl.loc,
"missing a function definition for '%s'", decl.name)
end
end
Expand Down Expand Up @@ -610,12 +609,10 @@ function Parser:FuncStat(is_local)
local method = false
if is_local then
if self:peek(".") then
self:syntax_error(self.next.loc, "local function name has a '.'")
self:abort_parsing()
self:abort_with_syntax_error(self.next.loc, "local function name has a '.'")
end
if self:peek(":") then
self:syntax_error(self.next.loc, "local function name has a ':'")
self:abort_parsing()
self:abort_with_syntax_error(self.next.loc, "local function name has a ':'")
end
else
local fields = {}
Expand All @@ -625,7 +622,7 @@ function Parser:FuncStat(is_local)

field = fields[1] or false
if fields[2] then
self:syntax_error(self.prev.loc,
self:recoverable_syntax_error(self.prev.loc,
"more than one dot in the function name is not allowed")
end

Expand All @@ -635,9 +632,8 @@ function Parser:FuncStat(is_local)
end

if method then
self:syntax_error(self.prev.loc,
self:abort_with_syntax_error(self.prev.loc,
"Pallene does not yet implement method definitions")
self:abort_parsing()
end

local module, name
Expand All @@ -664,7 +660,7 @@ function Parser:FuncStat(is_local)

for _, decl in ipairs(params) do
if not decl.type then
self:syntax_error(decl.loc,
self:recoverable_syntax_error(decl.loc,
"parameter '%s' is missing a type annotation", decl.name)
end
end
Expand Down Expand Up @@ -771,7 +767,7 @@ function Parser:Stat()
elseif self:peek("break") then
local start = self:advance()
if self.loop_depth == 0 then
self:syntax_error(start.loc, "break statement outside of a loop")
self:recoverable_syntax_error(start.loc, "break statement outside of a loop")
end
return ast.Stat.Break(start.loc)

Expand Down Expand Up @@ -801,9 +797,8 @@ function Parser:Stat()
if exp._tag == "ast.Exp.CallFunc" then
return ast.Stat.Call(exp.loc, exp)
else
self:syntax_error(exp.loc,
self:abort_with_syntax_error(exp.loc,
"this expression in a statement position is not a function call")
self:abort_parsing()
end
end
else
Expand All @@ -820,8 +815,7 @@ function Parser:to_var(exp)
if exp._tag == "ast.Exp.Var" then
return exp.var
else
self:syntax_error(exp.loc, "this expression is not an lvalue")
self:abort_parsing()
self:abort_with_syntax_error(exp.loc, "this expression is not an lvalue")
end
end

Expand Down Expand Up @@ -863,9 +857,8 @@ function Parser:SuffixedExp()
local _ = self:advance()
local _ = self:e("NAME") -- id
local _ = self:FuncArgs() -- args
self:syntax_error(self.prev.loc,
self:recoverable_syntax_error(self.prev.loc,
"Pallene does not yet support method calls")
self:abort_parsing()

elseif self:peek("(") or self:peek("STRING") or self:peek("{") then
local args = self:FuncArgs()
Expand All @@ -885,7 +878,7 @@ function Parser:FuncArgs()
local exps = self:peek(")") and {} or self:ExpList1()
local _ = self:e(")", open)
if #exps > MaxParams then
self:syntax_error(exps[MaxParams + 1].loc,
self:recoverable_syntax_error(exps[MaxParams + 1].loc,
"too many arguments (limit is %d)", MaxParams)
end
return exps
Expand All @@ -896,7 +889,7 @@ function Parser:FuncParams()
local oparen = self:e("(")
local params = self:DeclList()
if #params > MaxParams then
self:syntax_error(params[MaxParams + 1].loc,
self:recoverable_syntax_error(params[MaxParams + 1].loc,
"too many parameters (limit is %d)", MaxParams)
end
local _ = self:e(")", oparen)
Expand All @@ -909,13 +902,15 @@ function Parser:FuncExp()

for _, decl in ipairs(params) do
if decl.type then
self:syntax_error(decl.loc, "Function expressions cannot be type annotated")
self:recoverable_syntax_error(decl.loc,
"Function expressions cannot be type annotated")
end
end

if self:try(":") then
local typ = self:Type()
self:syntax_error(typ.loc, "Function expressions cannot be type annotated")
self:recoverable_syntax_error(typ.loc,
"Function expressions cannot be type annotated")
end

local block = self:FuncBody()
Expand Down Expand Up @@ -1084,17 +1079,21 @@ end
--
-- Syntax errors
--
-- For simple errors that we have a good idea how to recover from them, we report a syntax error and
-- continue parsing. However, if we aren't immediately sure how to recover, we abort. We would
-- rather stop early than potentially create a bunch of spurious errors.

function Parser:syntax_error(loc, fmt, ...)
function Parser:abort_parsing()
trycatch.error("syntax-error")
end

-- For simple errors that we can recover from.
function Parser:recoverable_syntax_error(loc, fmt, ...)
local msg = "syntax error: " .. loc:format_error(fmt, ...)
table.insert(self.errors, msg)
end

function Parser:abort_parsing()
trycatch.error("syntax-error")
-- For syntax errors that we cannot recover from.
function Parser:abort_with_syntax_error(...)
self:recoverable_syntax_error(...)
self:abort_parsing()
end

function Parser:describe_token_name(name)
Expand Down Expand Up @@ -1123,8 +1122,9 @@ end

function Parser:unexpected_token_error(non_terminal)
local where = self:describe_token(self.next)
self:syntax_error(self.next.loc, "unexpected %s while trying to parse %s", where, non_terminal)
self:abort_parsing()
self:abort_with_syntax_error(self.next.loc,
"unexpected %s while trying to parse %s",
where, non_terminal)
end

function Parser:wrong_token_error(expected_name, open_tok)
Expand All @@ -1150,22 +1150,22 @@ function Parser:wrong_token_error(expected_name, open_tok)
local where = self:describe_token(next_tok)

if not open_tok or loc.line == open_tok.loc.line then
self:syntax_error(loc, "expected %s before %s", what, where)
self:abort_with_syntax_error(loc,
"expected %s before %s",
what, where)
else
local owhat = self:describe_token_name(open_tok.name)
local oline = open_tok.loc.line
if is_stolen_delimiter then
self:syntax_error(loc,
self:abort_with_syntax_error(loc,
"expected %s to close %s at line %d, before this less indented %s",
what, owhat, oline, what)
else
self:syntax_error(loc,
self:abort_with_syntax_error(loc,
"expected %s before %s, to close the %s at line %d",
what, where, owhat, oline)
end
end

self:abort_parsing()
end

--
Expand Down