mirror of
https://github.com/Reuh/candran.git
synced 2026-02-04 02:08:40 +00:00
feat: implement global keyword in lua55 writer
This commit is contained in:
parent
e2a1c51c2d
commit
73e3f95636
5 changed files with 62 additions and 13 deletions
|
|
@ -1,5 +1,5 @@
|
|||
--[[
|
||||
This module implements a parser for Lua 5.3 with LPeg,
|
||||
This module implements a parser for Lua 5.5 with LPeg,
|
||||
and generates an Abstract Syntax Tree that is similar to the one generated by Metalua.
|
||||
For more information about Metalua, please, visit:
|
||||
https://github.com/fab13n/metalua-parser
|
||||
|
|
@ -15,8 +15,11 @@ stat:
|
|||
| `Fornum{ ident expr expr expr? block } -- for ident = e, e[, e] do b end
|
||||
| `Forin{ {ident+} {expr+} block } -- for i1, i2... in e1, e2... do b end
|
||||
| `Local{ {attributeident+} {expr+}? } -- local i1, i2... = e1, e2...
|
||||
| `Global{ {attributeident+} {expr+}? } -- global i1, i2... = e1, e2...
|
||||
| `Let{ {ident+} {expr+}? } -- let i1, i2... = e1, e2...
|
||||
| `Localrec{ {ident} {expr} } -- only used for 'local function'
|
||||
| `Globalrec{ {ident} {expr} } -- only used for 'global function'
|
||||
| `GlobalAll{ attribute? } -- only used for 'global *'
|
||||
| `Goto{ <string> } -- goto str
|
||||
| `Label{ <string> } -- ::str::
|
||||
| `Return{ <expr*> } -- return e1, e2...
|
||||
|
|
@ -112,6 +115,7 @@ local labels = {
|
|||
{ "ErrEListFor", "expected one or more expressions after 'in'" },
|
||||
{ "ErrDoFor", "expected 'do' after the range of the for loop" },
|
||||
|
||||
{ "ErrDefGlobal", "expected a function definition or assignment after global" },
|
||||
{ "ErrDefLocal", "expected a function definition or assignment after local" },
|
||||
{ "ErrDefLet", "expected an assignment after let" },
|
||||
{ "ErrDefClose", "expected an assignment after close" },
|
||||
|
|
@ -340,10 +344,10 @@ end
|
|||
local function searchEndRec (block, isRecCall) -- recursively search potential "end" keyword wrongly consumed by a short anonymous function on stat end (yeah, too late to change the syntax to something easier to parse)
|
||||
for i, stat in ipairs(block) do
|
||||
-- Non recursive statements
|
||||
if stat.tag == "Set" or stat.tag == "Push" or stat.tag == "Return" or stat.tag == "Local" or stat.tag == "Let" or stat.tag == "Localrec" then
|
||||
if stat.tag == "Set" or stat.tag == "Push" or stat.tag == "Return" or stat.tag == "Local" or stat.tag == "Let" or stat.tag == "Localrec" or stat.tag == "Global" or stat.tag == "Globalrec" then
|
||||
local exprlist
|
||||
|
||||
if stat.tag == "Set" or stat.tag == "Local" or stat.tag == "Let" or stat.tag == "Localrec" then
|
||||
if stat.tag == "Set" or stat.tag == "Local" or stat.tag == "Let" or stat.tag == "Localrec" or stat.tag == "Global" or stat.tag == "Globalrec" then
|
||||
exprlist = stat[#stat]
|
||||
elseif stat.tag == "Push" or stat.tag == "Return" then
|
||||
exprlist = stat
|
||||
|
|
@ -515,7 +519,7 @@ local G = { V"Lua",
|
|||
|
||||
Block = tagC("Block", (V"Stat" + -V"BlockEnd" * throw("InvalidStat"))^0 * ((V"RetStat" + V"ImplicitPushStat") * sym(";")^-1)^-1);
|
||||
Stat = V"IfStat" + V"DoStat" + V"WhileStat" + V"RepeatStat" + V"ForStat"
|
||||
+ V"LocalStat" + V"FuncStat" + V"BreakStat" + V"LabelStat" + V"GoToStat"
|
||||
+ V"LocalStat" + V"GlobalStat" + V"FuncStat" + V"BreakStat" + V"LabelStat" + V"GoToStat"
|
||||
+ V"LetStat" + V"ConstStat" + V"CloseStat"
|
||||
+ V"FuncCall" + V"Assignment"
|
||||
+ V"ContinueStat" + V"PushStat"
|
||||
|
|
@ -542,6 +546,12 @@ local G = { V"Lua",
|
|||
ForIn = tagC("Forin", V"DestructuringNameList" * expect(kw("in"), "InFor") * expect(V"ExprList", "EListFor") * V"ForBody");
|
||||
ForBody = expectBlockOrSingleStatWithStartEnd(kw("do"), "DoFor", "EndFor");
|
||||
|
||||
GlobalStat = kw("global") * expect(V"GlobalFunc" + V"GlobalAssign", "DefGlobal");
|
||||
GlobalFunc = tagC("Globalrec", kw("function") * expect(V"Id", "NameLFunc") * V"FuncBody") / fixFuncStat;
|
||||
GlobalAssign = tagC("Global", V"AttributeNameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc())))
|
||||
+ tagC("Global", V"DestructuringNameList" * sym("=") * expect(V"ExprList", "EListLAssign"))
|
||||
+ tagC("GlobalAll", V "Attribute"^-1 * sym("*")),
|
||||
|
||||
LocalStat = kw("local") * expect(V"LocalFunc" + V"LocalAssign", "DefLocal");
|
||||
LocalFunc = tagC("Localrec", kw("function") * expect(V"Id", "NameLFunc") * V"FuncBody") / fixFuncStat;
|
||||
LocalAssign = tagC("Local", V"AttributeNameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc())))
|
||||
|
|
@ -551,9 +561,9 @@ local G = { V"Lua",
|
|||
LetAssign = tagC("Let", V"NameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc())))
|
||||
+ tagC("Let", V"DestructuringNameList" * sym("=") * expect(V"ExprList", "EListLAssign"));
|
||||
|
||||
ConstStat = kw("const") * expect(V"AttributeAssign" / setAttribute("const"), "DefConst");
|
||||
CloseStat = kw("close") * expect(V"AttributeAssign" / setAttribute("close"), "DefClose");
|
||||
AttributeAssign = tagC("Local", V"NameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc())))
|
||||
ConstStat = kw("const") * expect(V "LocalAssignNoAttribute" / setAttribute("const"), "DefConst"),
|
||||
CloseStat = kw("close") * expect(V "LocalAssignNoAttribute" / setAttribute("close"), "DefClose"),
|
||||
LocalAssignNoAttribute = tagC("Local", V"NameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc())))
|
||||
+ tagC("Local", V"DestructuringNameList" * sym("=") * expect(V"ExprList", "EListLAssign"));
|
||||
|
||||
Assignment = tagC("Set", (V"VarList" + V"DestructuringNameList") * V"BinOp"^-1 * (P"=" / "=") * ((V"BinOp" - P"-") + #(P"-" * V"Space") * V"BinOp")^-1 * V"Skip" * expect(V"ExprList", "EListAssign"));
|
||||
|
|
@ -677,7 +687,7 @@ local G = { V"Lua",
|
|||
Reserved = V"Keywords" * -V"IdRest";
|
||||
Keywords = P"and" + "break" + "do" + "elseif" + "else" + "end"
|
||||
+ "false" + "for" + "function" + "goto" + "if" + "in"
|
||||
+ "local" + "nil" + "not" + "or" + "repeat" + "return"
|
||||
+ "local" + "global" + "nil" + "not" + "or" + "repeat" + "return"
|
||||
+ "then" + "true" + "until" + "while";
|
||||
Ident = V"IdStart" * V"IdRest"^0;
|
||||
IdStart = alpha + P"_";
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ function stm2str (stm)
|
|||
str = str .. explist2str(stm[2]) .. ", "
|
||||
str = str .. block2str(stm[3])
|
||||
str = str .. " }"
|
||||
elseif tag == "Local" then -- `Local{ {ident+} {expr+}? }
|
||||
elseif tag == "Local" or tag == "Global" then -- `Local|Global{ {ident+} {expr+}? }
|
||||
str = str .. "{ "
|
||||
str = str .. varlist2str(stm[1])
|
||||
if #stm[2] > 0 then
|
||||
|
|
@ -254,7 +254,7 @@ function stm2str (stm)
|
|||
str = str .. ", " .. "{ }"
|
||||
end
|
||||
str = str .. " }"
|
||||
elseif tag == "Localrec" then -- `Localrec{ ident expr }
|
||||
elseif tag == "Localrec" or tag == "Globalrec" then -- `Localrec|Globalrec{ ident expr }
|
||||
str = str .. "{ "
|
||||
str = str .. "{ " .. var2str(stm[1][1]) .. " }, "
|
||||
str = str .. "{ " .. exp2str(stm[2][1]) .. " }"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
--[[
|
||||
This module impements a validator for the AST
|
||||
This module impements a validator for the AST.
|
||||
|
||||
TODO/Checks that could be added in the future:
|
||||
- Check if attributes are valid in declarations: in AttributeNameList, PrefixedAttributeNameList, and GlobalAll
|
||||
- Check global variable declarations
|
||||
]]
|
||||
local scope = require "candran.can-parser.scope"
|
||||
|
||||
|
|
@ -395,10 +399,14 @@ function traverse_stm (env, stm)
|
|||
elseif tag == "Forin" then -- `Forin{ {ident+} {expr+} block }
|
||||
return traverse_forin(env, stm)
|
||||
elseif tag == "Local" or -- `Local{ {ident+} {expr+}? }
|
||||
tag == "Let" then -- `Let{ {ident+} {expr+}? }
|
||||
tag == "Let" or -- `Let{ {ident+} {expr+}? }
|
||||
tag == "Global" then -- `Global{ {ident+} {expr+}? }
|
||||
return traverse_let(env, stm)
|
||||
elseif tag == "Localrec" then -- `Localrec{ ident expr }
|
||||
elseif tag == "Localrec" or -- `Localrec{ ident expr }
|
||||
tag == "Globalrec" then -- `Globalrec{ ident expr }
|
||||
return traverse_letrec(env, stm)
|
||||
elseif tag == "GlobalAll" then -- GlobalAll{ attribute? }
|
||||
return true
|
||||
elseif tag == "Goto" then -- `Goto{ <string> }
|
||||
return traverse_goto(env, stm)
|
||||
elseif tag == "Label" then -- `Label{ <string> }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,15 @@
|
|||
targetName = "Lua 5.4"
|
||||
|
||||
tags.Global = (t)
|
||||
error("NYI")
|
||||
end
|
||||
tags.Globalrec = (t)
|
||||
error("NYI")
|
||||
end
|
||||
tags.GlobalAll = (t)
|
||||
error("NYI")
|
||||
end
|
||||
|
||||
#placeholder("patch")
|
||||
|
||||
#local patch = output
|
||||
|
|
|
|||
|
|
@ -471,6 +471,15 @@ return function(code, ast, options, macros={functions={}, variables={}})
|
|||
end
|
||||
return r..DESTRUCTURING_ASSIGN(destructured)
|
||||
end,
|
||||
-- Global{ {attributeident+} {expr+}? }
|
||||
Global = (t)
|
||||
local destructured = {}
|
||||
local r = "global "..push("destructuring", destructured)..lua(t[1])..pop("destructuring")
|
||||
if t[2][1] then
|
||||
r ..= " = "..lua(t[2], "_lhs")
|
||||
end
|
||||
return r..DESTRUCTURING_ASSIGN(destructured)
|
||||
end,
|
||||
-- Let{ {ident+} {expr+}? }
|
||||
Let = (t)
|
||||
local destructured = {}
|
||||
|
|
@ -489,6 +498,18 @@ return function(code, ast, options, macros={functions={}, variables={}})
|
|||
Localrec = (t)
|
||||
return "local function "..lua(t[1][1])..lua(t[2][1], "_functionWithoutKeyword")
|
||||
end,
|
||||
-- Globalrec{ {ident} {expr} }
|
||||
Globalrec = (t)
|
||||
return "global function "..lua(t[1][1])..lua(t[2][1], "_functionWithoutKeyword")
|
||||
end,
|
||||
-- GlobalAll{ attribute? }
|
||||
GlobalAll = (t)
|
||||
if #t == 1 then
|
||||
return "global <" .. t[1] .. "> *"
|
||||
else
|
||||
return "global *"
|
||||
end
|
||||
end,
|
||||
-- Goto{ <string> }
|
||||
Goto = (t)
|
||||
return "goto "..lua(t, "Id")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue