From 58d86153534db005f0f73ccfeef9885496ff5bb0 Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Wed, 19 Jul 2023 01:46:12 -0300 Subject: [PATCH] fix: improve checks of enum and record as soft keywords. Fixes #634. --- spec/declaration/enum_spec.lua | 7 +++++++ spec/declaration/record_spec.lua | 7 +++++++ tl.lua | 17 +++++++++++------ tl.tl | 29 +++++++++++++++++------------ 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/spec/declaration/enum_spec.lua b/spec/declaration/enum_spec.lua index 18556a04b..e3c6a10ce 100644 --- a/spec/declaration/enum_spec.lua +++ b/spec/declaration/enum_spec.lua @@ -104,4 +104,11 @@ describe("enum declaration", function() ]], { { y = 2, msg = "syntax error: this syntax is no longer valid; declare nested enum inside a record" }, })) + + it("accepts enum as soft keyword", util.check([[ + local enum = 2 + local t = { + enum = enum, + } + ]])) end) diff --git a/spec/declaration/record_spec.lua b/spec/declaration/record_spec.lua index d787e0b58..3c58abed7 100644 --- a/spec/declaration/record_spec.lua +++ b/spec/declaration/record_spec.lua @@ -52,6 +52,13 @@ for i, name in ipairs({"records", "arrayrecords"}) do { y = 2, msg = "syntax error: this syntax is no longer valid; declare nested record inside a record" }, })) + it("accepts record as soft keyword", util.check([[ + local record = 2 + local t = { + record = record, + } + ]])) + it("can be declared with 'global type'", util.check([[ global type Point = record ]]..pick(i, "", "{Point}")..[[ x: number diff --git a/tl.lua b/tl.lua index fbe13ac6a..3884c19c0 100644 --- a/tl.lua +++ b/tl.lua @@ -1480,14 +1480,19 @@ end local function parse_table_value(ps, i) local next_word = ps.tokens[i].tk - local e if next_word == "record" then - i = failskip(ps, i, "syntax error: this syntax is no longer valid; declare nested record inside a record", skip_record) - elseif next_word == "enum" then + local skip_i, e = skip(ps, i, skip_record) + if e then + fail(ps, i, "syntax error: this syntax is no longer valid; declare nested record inside a record") + return skip_i, new_node(ps.tokens, i, "error_node") + end + elseif next_word == "enum" and ps.tokens[i + 1].kind == "string" then i = failskip(ps, i, "syntax error: this syntax is no longer valid; declare nested enum inside a record", skip_enum) - else - i, e = parse_expression(ps, i) + return i, new_node(ps.tokens, i - 1, "error_node") end + + local e + i, e = parse_expression(ps, i) if not e then e = new_node(ps.tokens, i - 1, "error_node") end @@ -3022,7 +3027,7 @@ local function parse_type_constructor(ps, i, node_name, type_name, parse_body) end local function skip_type_declaration(ps, i) - return (parse_type_declaration(ps, i - 1, "local_type")) + return parse_type_declaration(ps, i - 1, "local_type") end local function parse_local(ps, i) diff --git a/tl.tl b/tl.tl index 76df6a0cf..427fd14af 100644 --- a/tl.tl +++ b/tl.tl @@ -1450,9 +1450,9 @@ local function verify_kind(ps: ParseState, i: integer, kind: TokenKind, node_kin return fail(ps, i, "syntax error, expected " .. kind) end -local type SkipFunction = function(ParseState, integer): integer +local type SkipFunction = function(ParseState, integer): integer, Node -local function skip(ps: ParseState, i: integer, skip_fn: SkipFunction): integer +local function skip(ps: ParseState, i: integer, skip_fn: SkipFunction): integer, Node local err_ps: ParseState = { filename = ps.filename, tokens = ps.tokens, @@ -1480,14 +1480,19 @@ end local function parse_table_value(ps: ParseState, i: integer): integer, Node, integer local next_word = ps.tokens[i].tk - local e: Node if next_word == "record" then - i = failskip(ps, i, "syntax error: this syntax is no longer valid; declare nested record inside a record", skip_record) - elseif next_word == "enum" then + local skip_i, e = skip(ps, i, skip_record) + if e then + fail(ps, i, "syntax error: this syntax is no longer valid; declare nested record inside a record") + return skip_i, new_node(ps.tokens, i, "error_node") + end + elseif next_word == "enum" and ps.tokens[i + 1].kind == "string" then i = failskip(ps, i, "syntax error: this syntax is no longer valid; declare nested enum inside a record", skip_enum) - else - i, e = parse_expression(ps, i) + return i, new_node(ps.tokens, i - 1, "error_node") end + + local e: Node + i, e = parse_expression(ps, i) if not e then e = new_node(ps.tokens, i - 1, "error_node") end @@ -2083,7 +2088,7 @@ do local key: Node i = i + 1 if ps.tokens[i].kind ~= "identifier" then - local skipped = skip(ps, i, parse_type) + local skipped = skip(ps, i, parse_type as SkipFunction) if skipped > i + 1 then fail(ps, i, "syntax error, cannot declare a type here (missing 'local' or 'global'?)") return skipped, failstore(tkop, e1) @@ -2725,7 +2730,7 @@ parse_record_body = function(ps: ParseState, i: integer, def: Type, node: Node, i = i + 1 elseif ps.tokens[i].tk == "{" then if def.typename == "arrayrecord" then - i = failskip(ps, i, "duplicated declaration of array element type in record", parse_type) + i = failskip(ps, i, "duplicated declaration of array element type in record", parse_type as SkipFunction) else i = i + 1 local t: Type @@ -2958,7 +2963,7 @@ local function parse_variable_declarations(ps: ParseState, i: integer, node_name return failskip(ps, i + 1, "syntax error: this syntax is no longer valid; use '" .. scope .. " enum " .. asgn.vars[1].tk .. "'", skip_enum) elseif next_word == "functiontype" then local scope = node_name == "local_declaration" and "local" or "global" - return failskip(ps, i + 1, "syntax error: this syntax is no longer valid; use '" .. scope .. " type " .. asgn.vars[1].tk .. " = function('...", parse_function_type) + return failskip(ps, i + 1, "syntax error: this syntax is no longer valid; use '" .. scope .. " type " .. asgn.vars[1].tk .. " = function('...", parse_function_type as SkipFunction) end i, asgn = parse_assignment_expression_list(ps, i, asgn) @@ -3021,8 +3026,8 @@ local function parse_type_constructor(ps: ParseState, i: integer, node_name: Nod return i, asgn end -local function skip_type_declaration(ps: ParseState, i: integer): integer - return (parse_type_declaration(ps, i - 1, "local_type")) +local function skip_type_declaration(ps: ParseState, i: integer): integer, Node + return parse_type_declaration(ps, i - 1, "local_type") end local function parse_local(ps: ParseState, i: integer): integer, Node