1
0
Fork 0
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:
Étienne Fildadut 2025-11-24 19:11:06 +01:00
parent e2a1c51c2d
commit 73e3f95636
5 changed files with 62 additions and 13 deletions

View file

@ -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"_";

View file

@ -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]) .. " }"

View file

@ -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> }

View file

@ -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

View file

@ -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")