diff --git a/candran/can-parser/parser.lua b/candran/can-parser/parser.lua index 9964c08..615e006 100644 --- a/candran/can-parser/parser.lua +++ b/candran/can-parser/parser.lua @@ -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{ } -- goto str | `Label{ } -- ::str:: | `Return{ } -- 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"_"; diff --git a/candran/can-parser/pp.lua b/candran/can-parser/pp.lua index 649db38..744c107 100644 --- a/candran/can-parser/pp.lua +++ b/candran/can-parser/pp.lua @@ -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]) .. " }" diff --git a/candran/can-parser/validator.lua b/candran/can-parser/validator.lua index ec15a63..6e7bd8d 100644 --- a/candran/can-parser/validator.lua +++ b/candran/can-parser/validator.lua @@ -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{ } return traverse_goto(env, stm) elseif tag == "Label" then -- `Label{ } diff --git a/compiler/lua54.can b/compiler/lua54.can index e9c6d98..e111df0 100644 --- a/compiler/lua54.can +++ b/compiler/lua54.can @@ -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 diff --git a/compiler/lua55.can b/compiler/lua55.can index a55d1c7..08c87c8 100644 --- a/compiler/lua55.can +++ b/compiler/lua55.can @@ -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{ } Goto = (t) return "goto "..lua(t, "Id")