Skip to content

Commit

Permalink
pragma: introduce --#pragma syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
hishamhm committed Aug 31, 2024
1 parent b8b5bb8 commit 7a6a19f
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 0 deletions.
29 changes: 29 additions & 0 deletions spec/pragma/invalid_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
local util = require("spec.util")

describe("invalid pragma", function()
it("rejects invalid pragma", util.check_syntax_error([[
--#invalid_pragma on
]], {
{ y = 1, msg = "invalid token '--#invalid_pragma'" }
}))

it("pragmas currently do not accept punctuation", util.check_syntax_error([[
--#pragma something(other)
]], {
{ y = 1, msg = "invalid token '('" },
{ y = 1, msg = "invalid token ')'" },
}))

it("pragma arguments need to be in a single line", util.check_syntax_error([[
--#pragma arity
on
local function f(x: integer, y: integer)
print(x + y)
end
print(f(10))
]], {
{ msg = "expected pragma value" }
}))
end)
64 changes: 64 additions & 0 deletions tl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,8 @@ end








Expand Down Expand Up @@ -838,6 +840,9 @@ do









Expand Down Expand Up @@ -874,6 +879,9 @@ do
["number hexfloat"] = "number",
["number power"] = "number",
["number powersign"] = "$ERR invalid_number$",
["pragma"] = "pragma",
["pragma any"] = nil,
["pragma word"] = "pragma_identifier",
}

local keywords = {
Expand Down Expand Up @@ -1267,11 +1275,39 @@ do
elseif state == "got --" then
if c == "[" then
state = "got --["
elseif c == "#" then
state = "pragma"
else
fwd = false
state = "comment short"
drop_token()
end
elseif state == "pragma" then
if not lex_word[c] then
end_token_prev("pragma")
if tokens[nt].tk ~= "--#pragma" then
add_syntax_error()
end
fwd = false
state = "pragma any"
end
elseif state == "pragma any" then
if c == "\n" then
state = "any"
elseif lex_word[c] then
state = "pragma word"
begin_token()
elseif not lex_space[c] then
begin_token()
end_token_here("$ERR invalid$")
add_syntax_error()
end
elseif state == "pragma word" then
if not lex_word[c] then
end_token_prev("pragma_identifier")
fwd = false
state = (c == "\n") and "any" or "pragma any"
end
elseif state == "got 0" then
if c == "x" or c == "X" then
state = "number hex"
Expand Down Expand Up @@ -4220,7 +4256,27 @@ do
return parse_function(ps, i, "record")
end

local function parse_pragma(ps, i)
i = i + 1
local pragma = new_node(ps, i, "pragma")

if ps.tokens[i].kind ~= "pragma_identifier" then
return fail(ps, i, "expected pragma name")
end
pragma.pkey = ps.tokens[i].tk
i = i + 1

if ps.tokens[i].kind ~= "pragma_identifier" then
return fail(ps, i, "expected pragma value")
end
pragma.pvalue = ps.tokens[i].tk
i = i + 1

return i, pragma
end

local parse_statement_fns = {
["--#pragma"] = parse_pragma,
["::"] = parse_label,
["do"] = parse_do,
["if"] = parse_if,
Expand Down Expand Up @@ -4589,6 +4645,7 @@ local no_recurse_node = {
["break"] = true,
["label"] = true,
["number"] = true,
["pragma"] = true,
["string"] = true,
["boolean"] = true,
["integer"] = true,
Expand Down Expand Up @@ -5547,6 +5604,8 @@ function tl.pretty_print_ast(ast, gen_target, mode)
return out
end,
},
["pragma"] = {},


["variable"] = emit_exactly_visitor_cbs,
["identifier"] = emit_exactly_visitor_cbs,
Expand Down Expand Up @@ -12274,6 +12333,11 @@ self:expand_type(node, values, elements) })
return node.newtype
end,
},
["pragma"] = {
after = function(_self, _node, _children)
return NONE
end,
},
["error_node"] = {
after = function(_self, node, _children)
return a_type(node, "invalid", {})
Expand Down
69 changes: 69 additions & 0 deletions tl.tl
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,8 @@ local enum TokenKind
"identifier"
"number"
"integer"
"pragma"
"pragma_identifier"
"$ERR unfinished_comment$"
"$ERR invalid_string$"
"$ERR invalid_number$"
Expand Down Expand Up @@ -840,6 +842,9 @@ do
"number hexfloat"
"number power"
"number powersign"
"pragma"
"pragma word"
"pragma any"
end

local last_token_kind <total>: {LexState:TokenKind} = {
Expand Down Expand Up @@ -874,6 +879,9 @@ do
["number hexfloat"] = "number",
["number power"] = "number",
["number powersign"] = "$ERR invalid_number$",
["pragma"] = "pragma",
["pragma any"] = nil, -- never in a token
["pragma word"] = "pragma_identifier", -- never in a token
}

local keywords: {string:boolean} = {
Expand Down Expand Up @@ -1267,11 +1275,39 @@ do
elseif state == "got --" then
if c == "[" then
state = "got --["
elseif c == "#" then
state = "pragma"
else
fwd = false
state = "comment short"
drop_token()
end
elseif state == "pragma" then
if not lex_word[c] then
end_token_prev("pragma")
if tokens[nt].tk ~= "--#pragma" then
add_syntax_error()
end
fwd = false
state = "pragma any"
end
elseif state == "pragma any" then
if c == "\n" then
state = "any"
elseif lex_word[c] then
state = "pragma word"
begin_token()
elseif not lex_space[c] then
begin_token()
end_token_here("$ERR invalid$")
add_syntax_error()
end
elseif state == "pragma word" then
if not lex_word[c] then
end_token_prev("pragma_identifier")
fwd = false
state = (c == "\n") and "any" or "pragma any"
end
elseif state == "got 0" then
if c == "x" or c == "X" then
state = "number hex"
Expand Down Expand Up @@ -1902,6 +1938,7 @@ local enum NodeKind
"macroexp"
"local_macroexp"
"interface"
"pragma"
"error_node"
end

Expand Down Expand Up @@ -2100,6 +2137,10 @@ local record Node
itemtype: Type
decltuple: TupleType

-- pragma
pkey: string
pvalue: string

opt: boolean

debug_type: Type
Expand Down Expand Up @@ -4220,7 +4261,27 @@ local function parse_record_function(ps: ParseState, i: integer): integer, Node
return parse_function(ps, i, "record")
end

local function parse_pragma(ps: ParseState, i: integer): integer, Node
i = i + 1 -- skip "--#pragma"
local pragma = new_node(ps, i, "pragma")

if ps.tokens[i].kind ~= "pragma_identifier" then
return fail(ps, i, "expected pragma name")
end
pragma.pkey = ps.tokens[i].tk
i = i + 1

if ps.tokens[i].kind ~= "pragma_identifier" then
return fail(ps, i, "expected pragma value")
end
pragma.pvalue = ps.tokens[i].tk
i = i + 1

return i, pragma
end

local parse_statement_fns: {string : function(ParseState, integer):(integer, Node)} = {
["--#pragma"] = parse_pragma,
["::"] = parse_label,
["do"] = parse_do,
["if"] = parse_if,
Expand Down Expand Up @@ -4589,6 +4650,7 @@ local no_recurse_node: {NodeKind : boolean} = {
["break"] = true,
["label"] = true,
["number"] = true,
["pragma"] = true,
["string"] = true,
["boolean"] = true,
["integer"] = true,
Expand Down Expand Up @@ -5547,6 +5609,8 @@ function tl.pretty_print_ast(ast: Node, gen_target: GenTarget, mode?: boolean |
return out
end,
},
["pragma"] = {
},

["variable"] = emit_exactly_visitor_cbs,
["identifier"] = emit_exactly_visitor_cbs,
Expand Down Expand Up @@ -12274,6 +12338,11 @@ do
return node.newtype
end,
},
["pragma"] = {
after = function(_self: TypeChecker, _node: Node, _children: {Type}): Type
return NONE
end,
},
["error_node"] = {
after = function(_self: TypeChecker, node: Node, _children: {Type}): Type
return an_invalid(node)
Expand Down

0 comments on commit 7a6a19f

Please sign in to comment.