1
0
Fork 0
mirror of https://github.com/Reuh/candran.git synced 2025-10-27 17:59:30 +00:00

Added let and continue

This commit is contained in:
Étienne Fildadut 2017-08-23 14:06:34 +02:00
parent 5194cfb115
commit c0f7934d92
10 changed files with 316 additions and 119 deletions

View file

@ -1,4 +1,4 @@
Copyright 2017 Étienne "Reuh" Fildadut Copyright (c) 2017 Étienne "Reuh" Fildadut
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View file

@ -32,7 +32,9 @@ end)
```` ````
#### Quick setup #### Quick setup
Install LPegLabel (```luarocks install LPegLabel```), download this repository and use Candran through the scripts in ```bin/``` or use it as a library with the self-contained ```candran.lua```. Install Candran automatically using LuaRocks: ```sudo luarocks install candran```.
Or manually install LPegLabel (```luarocks install LPegLabel```), download this repository and use Candran through the scripts in ```bin/``` or use it as a library with the self-contained ```candran.lua```.
The language The language
------------ ------------

View file

@ -10,7 +10,7 @@
#import("lib.lua-parser.parser") #import("lib.lua-parser.parser")
local candran = { local candran = {
VERSION = "0.3.1" VERSION = "0.4.0"
} }
--- Default options. --- Default options.

View file

@ -168,15 +168,35 @@ return newline()
end end
local required = {} local required = {}
local requireStr = "" local requireStr = ""
local function addRequire(str, name, field) local function addRequire(mod, name, field)
if not required[str] then if not required[mod] then
requireStr = requireStr .. "local " .. options["requirePrefix"] .. name .. (" = require(%q)"):format(str) .. (field and "." .. field or "") .. options["newline"] requireStr = requireStr .. "local " .. options["requirePrefix"] .. name .. (" = require(%q)"):format(mod) .. (field and "." .. field or "") .. options["newline"]
required[str] = true required[mod] = true
end end
end end
local function getRequire(name) local function getRequire(name)
return options["requirePrefix"] .. name return options["requirePrefix"] .. name
end end
local function any(list, tags)
local tagsCheck = {}
for _, tag in ipairs(tags) do
tagsCheck[tag] = true
end
for _, node in ipairs(list) do
if tagsCheck[node["tag"]] then
return node
end
end
return nil
end
local namedNodes = {}
local function wrap(name, prefix, suffix)
local node = namedNodes[name]
if not node then
error("not inside a " .. name)
end
node["prefix"], node["suffix"] = prefix .. newline(), newline() .. suffix
end
local tags local tags
local function lua(ast, forceTag, ...) local function lua(ast, forceTag, ...)
if options["mapLines"] and ast["pos"] then if options["mapLines"] and ast["pos"] then
@ -184,6 +204,13 @@ lastInputPos = ast["pos"]
end end
return tags[forceTag or ast["tag"]](ast, ...) return tags[forceTag or ast["tag"]](ast, ...)
end end
local function namedLua(name, ast, ...)
local old = namedNodes[name]
namedNodes[name] = ast
local code = lua(ast, ...)
namedNodes[name] = old
return (ast["prefix"] or "") .. code .. (ast["suffix"] or "")
end
tags = setmetatable({ tags = setmetatable({
["Block"] = function(t) ["Block"] = function(t)
local r = "" local r = ""
@ -239,9 +266,9 @@ end
return r return r
end end
end, ["While"] = function(t) end, ["While"] = function(t)
return "while " .. lua(t[1]) .. " do" .. indent() .. lua(t[2]) .. unindent() .. "end" return "while " .. lua(t[1]) .. " do" .. indent() .. namedLua("loop", t[2]) .. unindent() .. "end"
end, ["Repeat"] = function(t) end, ["Repeat"] = function(t)
return "repeat" .. indent() .. lua(t[1]) .. unindent() .. "until " .. lua(t[2]) return "repeat" .. indent() .. namedLua("loop", t[1]) .. unindent() .. "until " .. lua(t[2])
end, ["If"] = function(t) end, ["If"] = function(t)
local r = "if " .. lua(t[1]) .. " then" .. indent() .. lua(t[2]) .. unindent() local r = "if " .. lua(t[1]) .. " then" .. indent() .. lua(t[2]) .. unindent()
for i = 3, # t - 1, 2 do for i = 3, # t - 1, 2 do
@ -256,16 +283,29 @@ local r = "for " .. lua(t[1]) .. " = " .. lua(t[2]) .. ", " .. lua(t[3])
if # t == 5 then if # t == 5 then
return r .. ", " .. lua(t[4]) .. " do" .. indent() .. lua(t[5]) .. unindent() .. "end" return r .. ", " .. lua(t[4]) .. " do" .. indent() .. lua(t[5]) .. unindent() .. "end"
else else
return r .. " do" .. indent() .. lua(t[4]) .. unindent() .. "end" return r .. " do" .. indent() .. namedLua("loop", t[4]) .. unindent() .. "end"
end end
end, ["Forin"] = function(t) end, ["Forin"] = function(t)
return "for " .. lua(t[1], "_lhs") .. " in " .. lua(t[2], "_lhs") .. " do" .. indent() .. lua(t[3]) .. unindent() .. "end" return "for " .. lua(t[1], "_lhs") .. " in " .. lua(t[2], "_lhs") .. " do" .. indent() .. namedLua("loop", t[3]) .. unindent() .. "end"
end, ["Local"] = function(t) end, ["Local"] = function(t)
local r = "local " .. lua(t[1], "_lhs") local r = "local " .. lua(t[1], "_lhs")
if t[2][1] then if t[2][1] then
r = r .. " = " .. lua(t[2], "_lhs") r = r .. " = " .. lua(t[2], "_lhs")
end end
return r return r
end, ["Let"] = function(t)
local nameList = lua(t[1], "_lhs")
local r = "local " .. nameList
if t[2][1] then
if any(t[2], {
"Function", "Table", "Paren"
}) then
r = r .. newline() .. nameList .. " = " .. lua(t[2], "_lhs")
else
r = r .. " = " .. lua(t[2], "_lhs")
end
end
return r
end, ["Localrec"] = function(t) end, ["Localrec"] = function(t)
return "local function " .. lua(t[1][1]) .. lua(t[2][1], "_functionWithoutKeyword") return "local function " .. lua(t[1][1]) .. lua(t[2][1], "_functionWithoutKeyword")
end, ["Goto"] = function(t) end, ["Goto"] = function(t)
@ -276,6 +316,9 @@ end, ["Return"] = function(t)
return "return " .. lua(t, "_lhs") return "return " .. lua(t, "_lhs")
end, ["Break"] = function() end, ["Break"] = function()
return "break" return "break"
end, ["Continue"] = function()
wrap("loop", "repeat", "until true")
return "break"
end, ["Nil"] = function() end, ["Nil"] = function()
return "nil" return "nil"
end, ["Dots"] = function() end, ["Dots"] = function()
@ -372,7 +415,8 @@ end, ["_opid"] = {
}, { ["__index"] = function(self, key) }, { ["__index"] = function(self, key)
error("don't know how to compile a " .. tostring(key) .. " to Lua 5.3") error("don't know how to compile a " .. tostring(key) .. " to Lua 5.3")
end }) end })
return requireStr .. lua(ast) .. newline() local code = lua(ast) .. newline()
return requireStr .. code
end end
end end
local lua53 = _() or lua53 local lua53 = _() or lua53
@ -416,15 +460,35 @@ return newline()
end end
local required = {} local required = {}
local requireStr = "" local requireStr = ""
local function addRequire(str, name, field) local function addRequire(mod, name, field)
if not required[str] then if not required[mod] then
requireStr = requireStr .. "local " .. options["requirePrefix"] .. name .. (" = require(%q)"):format(str) .. (field and "." .. field or "") .. options["newline"] requireStr = requireStr .. "local " .. options["requirePrefix"] .. name .. (" = require(%q)"):format(mod) .. (field and "." .. field or "") .. options["newline"]
required[str] = true required[mod] = true
end end
end end
local function getRequire(name) local function getRequire(name)
return options["requirePrefix"] .. name return options["requirePrefix"] .. name
end end
local function any(list, tags)
local tagsCheck = {}
for _, tag in ipairs(tags) do
tagsCheck[tag] = true
end
for _, node in ipairs(list) do
if tagsCheck[node["tag"]] then
return node
end
end
return nil
end
local namedNodes = {}
local function wrap(name, prefix, suffix)
local node = namedNodes[name]
if not node then
error("not inside a " .. name)
end
node["prefix"], node["suffix"] = prefix .. newline(), newline() .. suffix
end
local tags local tags
local function lua(ast, forceTag, ...) local function lua(ast, forceTag, ...)
if options["mapLines"] and ast["pos"] then if options["mapLines"] and ast["pos"] then
@ -432,6 +496,13 @@ lastInputPos = ast["pos"]
end end
return tags[forceTag or ast["tag"]](ast, ...) return tags[forceTag or ast["tag"]](ast, ...)
end end
local function namedLua(name, ast, ...)
local old = namedNodes[name]
namedNodes[name] = ast
local code = lua(ast, ...)
namedNodes[name] = old
return (ast["prefix"] or "") .. code .. (ast["suffix"] or "")
end
tags = setmetatable({ tags = setmetatable({
["Block"] = function(t) ["Block"] = function(t)
local r = "" local r = ""
@ -487,9 +558,9 @@ end
return r return r
end end
end, ["While"] = function(t) end, ["While"] = function(t)
return "while " .. lua(t[1]) .. " do" .. indent() .. lua(t[2]) .. unindent() .. "end" return "while " .. lua(t[1]) .. " do" .. indent() .. namedLua("loop", t[2]) .. unindent() .. "end"
end, ["Repeat"] = function(t) end, ["Repeat"] = function(t)
return "repeat" .. indent() .. lua(t[1]) .. unindent() .. "until " .. lua(t[2]) return "repeat" .. indent() .. namedLua("loop", t[1]) .. unindent() .. "until " .. lua(t[2])
end, ["If"] = function(t) end, ["If"] = function(t)
local r = "if " .. lua(t[1]) .. " then" .. indent() .. lua(t[2]) .. unindent() local r = "if " .. lua(t[1]) .. " then" .. indent() .. lua(t[2]) .. unindent()
for i = 3, # t - 1, 2 do for i = 3, # t - 1, 2 do
@ -504,16 +575,29 @@ local r = "for " .. lua(t[1]) .. " = " .. lua(t[2]) .. ", " .. lua(t[3])
if # t == 5 then if # t == 5 then
return r .. ", " .. lua(t[4]) .. " do" .. indent() .. lua(t[5]) .. unindent() .. "end" return r .. ", " .. lua(t[4]) .. " do" .. indent() .. lua(t[5]) .. unindent() .. "end"
else else
return r .. " do" .. indent() .. lua(t[4]) .. unindent() .. "end" return r .. " do" .. indent() .. namedLua("loop", t[4]) .. unindent() .. "end"
end end
end, ["Forin"] = function(t) end, ["Forin"] = function(t)
return "for " .. lua(t[1], "_lhs") .. " in " .. lua(t[2], "_lhs") .. " do" .. indent() .. lua(t[3]) .. unindent() .. "end" return "for " .. lua(t[1], "_lhs") .. " in " .. lua(t[2], "_lhs") .. " do" .. indent() .. namedLua("loop", t[3]) .. unindent() .. "end"
end, ["Local"] = function(t) end, ["Local"] = function(t)
local r = "local " .. lua(t[1], "_lhs") local r = "local " .. lua(t[1], "_lhs")
if t[2][1] then if t[2][1] then
r = r .. " = " .. lua(t[2], "_lhs") r = r .. " = " .. lua(t[2], "_lhs")
end end
return r return r
end, ["Let"] = function(t)
local nameList = lua(t[1], "_lhs")
local r = "local " .. nameList
if t[2][1] then
if any(t[2], {
"Function", "Table", "Paren"
}) then
r = r .. newline() .. nameList .. " = " .. lua(t[2], "_lhs")
else
r = r .. " = " .. lua(t[2], "_lhs")
end
end
return r
end, ["Localrec"] = function(t) end, ["Localrec"] = function(t)
return "local function " .. lua(t[1][1]) .. lua(t[2][1], "_functionWithoutKeyword") return "local function " .. lua(t[1][1]) .. lua(t[2][1], "_functionWithoutKeyword")
end, ["Goto"] = function(t) end, ["Goto"] = function(t)
@ -524,6 +608,9 @@ end, ["Return"] = function(t)
return "return " .. lua(t, "_lhs") return "return " .. lua(t, "_lhs")
end, ["Break"] = function() end, ["Break"] = function()
return "break" return "break"
end, ["Continue"] = function()
wrap("loop", "repeat", "until true")
return "break"
end, ["Nil"] = function() end, ["Nil"] = function()
return "nil" return "nil"
end, ["Dots"] = function() end, ["Dots"] = function()
@ -647,7 +734,8 @@ tags["_opid"]["bnot"] = function(right)
addRequire("bit", "bnot", "bnot") addRequire("bit", "bnot", "bnot")
return getRequire("bnot") .. "(" .. lua(right) .. ")" return getRequire("bnot") .. "(" .. lua(right) .. ")"
end end
return requireStr .. lua(ast) .. newline() local code = lua(ast) .. newline()
return requireStr .. code
end end
end end
local lua53 = _() or lua53 local lua53 = _() or lua53
@ -898,6 +986,13 @@ return nil, syntaxerror(env["errorinfo"], stm["pos"], msg)
end end
return true return true
end end
local function traverse_continue(env, stm)
if not insideloop(env) then
local msg = "<continue> not inside a loop"
return nil, syntaxerror(env["errorinfo"], stm["pos"], msg)
end
return true
end
local function traverse_forin(env, stm) local function traverse_forin(env, stm)
begin_loop(env) begin_loop(env)
new_scope(env) new_scope(env)
@ -1112,7 +1207,7 @@ elseif tag == "Fornum" then
return traverse_fornum(env, stm) return traverse_fornum(env, stm)
elseif tag == "Forin" then elseif tag == "Forin" then
return traverse_forin(env, stm) return traverse_forin(env, stm)
elseif tag == "Local" then elseif tag == "Local" or tag == "Let" then
return traverse_let(env, stm) return traverse_let(env, stm)
elseif tag == "Localrec" then elseif tag == "Localrec" then
return traverse_letrec(env, stm) return traverse_letrec(env, stm)
@ -1124,6 +1219,8 @@ elseif tag == "Return" then
return traverse_return(env, stm) return traverse_return(env, stm)
elseif tag == "Break" then elseif tag == "Break" then
return traverse_break(env, stm) return traverse_break(env, stm)
elseif tag == "Continue" then
return traverse_continue(env, stm)
elseif tag == "Call" then elseif tag == "Call" then
return traverse_call(env, stm) return traverse_call(env, stm)
elseif tag == "Invoke" then elseif tag == "Invoke" then
@ -1552,6 +1649,8 @@ local labels = {
}, { }, {
"ErrDefLocal", "expected a function definition or assignment after local" "ErrDefLocal", "expected a function definition or assignment after local"
}, { }, {
"ErrDefLet", "expected a function definition or assignment after let"
}, {
"ErrNameLFunc", "expected a function name after 'function'" "ErrNameLFunc", "expected a function name after 'function'"
}, { }, {
"ErrEListLAssign", "expected one or more expressions after '='" "ErrEListLAssign", "expected one or more expressions after '='"
@ -1766,7 +1865,7 @@ return t1
end end
local G = { local G = {
V("Lua"), ["Lua"] = V("Shebang") ^ - 1 * V("Skip") * V("Block") * expect(P(- 1), "Extra"), ["Shebang"] = P("#!") * (P(1) - P("\ V("Lua"), ["Lua"] = V("Shebang") ^ - 1 * V("Skip") * V("Block") * expect(P(- 1), "Extra"), ["Shebang"] = P("#!") * (P(1) - P("\
")) ^ 0, ["Block"] = tagC("Block", V("Stat") ^ 0 * V("RetStat") ^ - 1), ["Stat"] = V("IfStat") + V("DoStat") + V("WhileStat") + V("RepeatStat") + V("ForStat") + V("LocalStat") + V("FuncStat") + V("BreakStat") + V("LabelStat") + V("GoToStat") + V("FuncCall") + V("Assignment") + sym(";") + - V("BlockEnd") * throw("InvalidStat"), ["BlockEnd"] = P("return") + "end" + "elseif" + "else" + "until" + - 1, ["IfStat"] = tagC("If", V("IfPart") * V("ElseIfPart") ^ 0 * V("ElsePart") ^ - 1 * expect(kw("end"), "EndIf")), ["IfPart"] = kw("if") * expect(V("Expr"), "ExprIf") * expect(kw("then"), "ThenIf") * V("Block"), ["ElseIfPart"] = kw("elseif") * expect(V("Expr"), "ExprEIf") * expect(kw("then"), "ThenEIf") * V("Block"), ["ElsePart"] = kw("else") * V("Block"), ["DoStat"] = kw("do") * V("Block") * expect(kw("end"), "EndDo") / tagDo, ["WhileStat"] = tagC("While", kw("while") * expect(V("Expr"), "ExprWhile") * V("WhileBody")), ["WhileBody"] = expect(kw("do"), "DoWhile") * V("Block") * expect(kw("end"), "EndWhile"), ["RepeatStat"] = tagC("Repeat", kw("repeat") * V("Block") * expect(kw("until"), "UntilRep") * expect(V("Expr"), "ExprRep")), ["ForStat"] = kw("for") * expect(V("ForNum") + V("ForIn"), "ForRange") * expect(kw("end"), "EndFor"), ["ForNum"] = tagC("Fornum", V("Id") * sym("=") * V("NumRange") * V("ForBody")), ["NumRange"] = expect(V("Expr"), "ExprFor1") * expect(sym(","), "CommaFor") * expect(V("Expr"), "ExprFor2") * (sym(",") * expect(V("Expr"), "ExprFor3")) ^ - 1, ["ForIn"] = tagC("Forin", V("NameList") * expect(kw("in"), "InFor") * expect(V("ExprList"), "EListFor") * V("ForBody")), ["ForBody"] = expect(kw("do"), "DoFor") * V("Block"), ["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("NameList") * (sym("=") * expect(V("ExprList"), "EListLAssign") + Ct(Cc()))), ["Assignment"] = tagC("Set", V("VarList") * V("BinOp") ^ - 1 * (sym("=") / "=") * V("BinOp") ^ - 1 * expect(V("ExprList"), "EListAssign")), ["FuncStat"] = tagC("Set", kw("function") * expect(V("FuncName"), "FuncName") * V("FuncBody")) / fixFuncStat, ["FuncName"] = Cf(V("Id") * (sym(".") * expect(V("StrId"), "NameFunc1")) ^ 0, insertIndex) * (sym(":") * expect(V("StrId"), "NameFunc2")) ^ - 1 / markMethod, ["FuncBody"] = tagC("Function", V("FuncParams") * V("Block") * expect(kw("end"), "EndFunc")), ["FuncParams"] = expect(sym("("), "OParenPList") * V("ParList") * expect(sym(")"), "CParenPList"), ["ParList"] = V("NamedParList") * (sym(",") * expect(tagC("Dots", sym("...")), "ParList")) ^ - 1 / addDots + Ct(tagC("Dots", sym("..."))) + Ct(Cc()), ["NamedParList"] = tagC("NamedParList", commaSep(V("NamedPar"))), ["NamedPar"] = tagC("ParPair", V("ParKey") * expect(sym("="), "EqField") * expect(V("Expr"), "ExprField")) + V("Id"), ["ParKey"] = V("Id") * # ("=" * - P("=")), ["LabelStat"] = tagC("Label", sym("::") * expect(V("Name"), "Label") * expect(sym("::"), "CloseLabel")), ["GoToStat"] = tagC("Goto", kw("goto") * expect(V("Name"), "Goto")), ["BreakStat"] = tagC("Break", kw("break")), ["RetStat"] = tagC("Return", kw("return") * commaSep(V("Expr"), "RetList") ^ - 1 * sym(";") ^ - 1), ["NameList"] = tagC("NameList", commaSep(V("Id"))), ["VarList"] = tagC("VarList", commaSep(V("VarExpr"), "VarList")), ["ExprList"] = tagC("ExpList", commaSep(V("Expr"), "ExprList")), ["Expr"] = V("OrExpr"), ["OrExpr"] = chainOp(V("AndExpr"), V("OrOp"), "OrExpr"), ["AndExpr"] = chainOp(V("RelExpr"), V("AndOp"), "AndExpr"), ["RelExpr"] = chainOp(V("BOrExpr"), V("RelOp"), "RelExpr"), ["BOrExpr"] = chainOp(V("BXorExpr"), V("BOrOp"), "BOrExpr"), ["BXorExpr"] = chainOp(V("BAndExpr"), V("BXorOp"), "BXorExpr"), ["BAndExpr"] = chainOp(V("ShiftExpr"), V("BAndOp"), "BAndExpr"), ["ShiftExpr"] = chainOp(V("ConcatExpr"), V("ShiftOp"), "ShiftExpr"), ["ConcatExpr"] = V("AddExpr") * (V("ConcatOp") * expect(V("ConcatExpr"), "ConcatExpr")) ^ - 1 / binaryOp, ["AddExpr"] = chainOp(V("MulExpr"), V("AddOp"), "AddExpr"), ["MulExpr"] = chainOp(V("UnaryExpr"), V("MulOp"), "MulExpr"), ["UnaryExpr"] = V("UnaryOp") * expect(V("UnaryExpr"), "UnaryExpr") / unaryOp + V("PowExpr"), ["PowExpr"] = V("SimpleExpr") * (V("PowOp") * expect(V("UnaryExpr"), "PowExpr")) ^ - 1 / binaryOp, ["SimpleExpr"] = tagC("Number", V("Number")) + tagC("String", V("String")) + tagC("Nil", kw("nil")) + tagC("Boolean", kw("false") * Cc(false)) + tagC("Boolean", kw("true") * Cc(true)) + tagC("Dots", sym("...")) + V("FuncDef") + V("Table") + V("SuffixedExpr"), ["FuncCall"] = Cmt(V("SuffixedExpr"), function(s, i, exp) ")) ^ 0, ["Block"] = tagC("Block", V("Stat") ^ 0 * V("RetStat") ^ - 1), ["Stat"] = V("IfStat") + V("DoStat") + V("WhileStat") + V("RepeatStat") + V("ForStat") + V("LocalStat") + V("LetStat") + V("FuncStat") + V("BreakStat") + V("ContinueStat") + V("LabelStat") + V("GoToStat") + V("FuncCall") + V("Assignment") + sym(";") + - V("BlockEnd") * throw("InvalidStat"), ["BlockEnd"] = P("return") + "end" + "elseif" + "else" + "until" + - 1, ["IfStat"] = tagC("If", V("IfPart") * V("ElseIfPart") ^ 0 * V("ElsePart") ^ - 1 * expect(kw("end"), "EndIf")), ["IfPart"] = kw("if") * expect(V("Expr"), "ExprIf") * expect(kw("then"), "ThenIf") * V("Block"), ["ElseIfPart"] = kw("elseif") * expect(V("Expr"), "ExprEIf") * expect(kw("then"), "ThenEIf") * V("Block"), ["ElsePart"] = kw("else") * V("Block"), ["DoStat"] = kw("do") * V("Block") * expect(kw("end"), "EndDo") / tagDo, ["WhileStat"] = tagC("While", kw("while") * expect(V("Expr"), "ExprWhile") * V("WhileBody")), ["WhileBody"] = expect(kw("do"), "DoWhile") * V("Block") * expect(kw("end"), "EndWhile"), ["RepeatStat"] = tagC("Repeat", kw("repeat") * V("Block") * expect(kw("until"), "UntilRep") * expect(V("Expr"), "ExprRep")), ["ForStat"] = kw("for") * expect(V("ForNum") + V("ForIn"), "ForRange") * expect(kw("end"), "EndFor"), ["ForNum"] = tagC("Fornum", V("Id") * sym("=") * V("NumRange") * V("ForBody")), ["NumRange"] = expect(V("Expr"), "ExprFor1") * expect(sym(","), "CommaFor") * expect(V("Expr"), "ExprFor2") * (sym(",") * expect(V("Expr"), "ExprFor3")) ^ - 1, ["ForIn"] = tagC("Forin", V("NameList") * expect(kw("in"), "InFor") * expect(V("ExprList"), "EListFor") * V("ForBody")), ["ForBody"] = expect(kw("do"), "DoFor") * V("Block"), ["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("NameList") * (sym("=") * expect(V("ExprList"), "EListLAssign") + Ct(Cc()))), ["LetStat"] = kw("let") * expect(V("LetAssign"), "DefLet"), ["LetAssign"] = tagC("Let", V("NameList") * (sym("=") * expect(V("ExprList"), "EListLAssign") + Ct(Cc()))), ["Assignment"] = tagC("Set", V("VarList") * V("BinOp") ^ - 1 * (sym("=") / "=") * V("BinOp") ^ - 1 * expect(V("ExprList"), "EListAssign")), ["FuncStat"] = tagC("Set", kw("function") * expect(V("FuncName"), "FuncName") * V("FuncBody")) / fixFuncStat, ["FuncName"] = Cf(V("Id") * (sym(".") * expect(V("StrId"), "NameFunc1")) ^ 0, insertIndex) * (sym(":") * expect(V("StrId"), "NameFunc2")) ^ - 1 / markMethod, ["FuncBody"] = tagC("Function", V("FuncParams") * V("Block") * expect(kw("end"), "EndFunc")), ["FuncParams"] = expect(sym("("), "OParenPList") * V("ParList") * expect(sym(")"), "CParenPList"), ["ParList"] = V("NamedParList") * (sym(",") * expect(tagC("Dots", sym("...")), "ParList")) ^ - 1 / addDots + Ct(tagC("Dots", sym("..."))) + Ct(Cc()), ["NamedParList"] = tagC("NamedParList", commaSep(V("NamedPar"))), ["NamedPar"] = tagC("ParPair", V("ParKey") * expect(sym("="), "EqField") * expect(V("Expr"), "ExprField")) + V("Id"), ["ParKey"] = V("Id") * # ("=" * - P("=")), ["LabelStat"] = tagC("Label", sym("::") * expect(V("Name"), "Label") * expect(sym("::"), "CloseLabel")), ["GoToStat"] = tagC("Goto", kw("goto") * expect(V("Name"), "Goto")), ["BreakStat"] = tagC("Break", kw("break")), ["ContinueStat"] = tagC("Continue", kw("continue")), ["RetStat"] = tagC("Return", kw("return") * commaSep(V("Expr"), "RetList") ^ - 1 * sym(";") ^ - 1), ["NameList"] = tagC("NameList", commaSep(V("Id"))), ["VarList"] = tagC("VarList", commaSep(V("VarExpr"), "VarList")), ["ExprList"] = tagC("ExpList", commaSep(V("Expr"), "ExprList")), ["Expr"] = V("OrExpr"), ["OrExpr"] = chainOp(V("AndExpr"), V("OrOp"), "OrExpr"), ["AndExpr"] = chainOp(V("RelExpr"), V("AndOp"), "AndExpr"), ["RelExpr"] = chainOp(V("BOrExpr"), V("RelOp"), "RelExpr"), ["BOrExpr"] = chainOp(V("BXorExpr"), V("BOrOp"), "BOrExpr"), ["BXorExpr"] = chainOp(V("BAndExpr"), V("BXorOp"), "BXorExpr"), ["BAndExpr"] = chainOp(V("ShiftExpr"), V("BAndOp"), "BAndExpr"), ["ShiftExpr"] = chainOp(V("ConcatExpr"), V("ShiftOp"), "ShiftExpr"), ["ConcatExpr"] = V("AddExpr") * (V("ConcatOp") * expect(V("ConcatExpr"), "ConcatExpr")) ^ - 1 / binaryOp, ["AddExpr"] = chainOp(V("MulExpr"), V("AddOp"), "AddExpr"), ["MulExpr"] = chainOp(V("UnaryExpr"), V("MulOp"), "MulExpr"), ["UnaryExpr"] = V("UnaryOp") * expect(V("UnaryExpr"), "UnaryExpr") / unaryOp + V("PowExpr"), ["PowExpr"] = V("SimpleExpr") * (V("PowOp") * expect(V("UnaryExpr"), "PowExpr")) ^ - 1 / binaryOp, ["SimpleExpr"] = tagC("Number", V("Number")) + tagC("String", V("String")) + tagC("Nil", kw("nil")) + tagC("Boolean", kw("false") * Cc(false)) + tagC("Boolean", kw("true") * Cc(true)) + tagC("Dots", sym("...")) + V("FuncDef") + V("Table") + V("SuffixedExpr"), ["FuncCall"] = Cmt(V("SuffixedExpr"), function(s, i, exp)
return exp["tag"] == "Call" or exp["tag"] == "Invoke", exp return exp["tag"] == "Call" or exp["tag"] == "Invoke", exp
end), ["VarExpr"] = Cmt(V("SuffixedExpr"), function(s, i, exp) end), ["VarExpr"] = Cmt(V("SuffixedExpr"), function(s, i, exp)
return exp["tag"] == "Id" or exp["tag"] == "Index", exp return exp["tag"] == "Id" or exp["tag"] == "Index", exp
@ -1807,7 +1906,7 @@ return parser
end end
local parser = _() or parser local parser = _() or parser
package["loaded"]["lib.lua-parser.parser"] = parser or true package["loaded"]["lib.lua-parser.parser"] = parser or true
local candran = { ["VERSION"] = "0.3.1" } local candran = { ["VERSION"] = "0.4.0" }
local default = { local default = {
["target"] = "lua53", ["indentation"] = "", ["newline"] = "\ ["target"] = "lua53", ["indentation"] = "", ["newline"] = "\
", ["requirePrefix"] = "CANDRAN_", ["mapLines"] = true, ["chunkname"] = "nil", ["rewriteErrors"] = true ", ["requirePrefix"] = "CANDRAN_", ["mapLines"] = true, ["chunkname"] = "nil", ["rewriteErrors"] = true

View file

@ -1,10 +1,13 @@
return function(code, ast, options) return function(code, ast, options)
local lastInputPos = 1 --- Line mapping
local prevLinePos = 1 local lastInputPos = 1 -- last token position in the input code
local lastSource = "nil" local prevLinePos = 1 -- last token position in the previous line of code in the input code
local lastLine = 1 local lastSource = "nil" -- last found code source name (from the original file)
local lastLine = 1 -- last found line number (from the original file)
--- Newline management
local indentLevel = 0 local indentLevel = 0
-- Returns a newline.
local function newline() local function newline()
local r = options.newline .. string.rep(options.indentation, indentLevel) local r = options.newline .. string.rep(options.indentation, indentLevel)
if options.mapLines then if options.mapLines then
@ -26,44 +29,83 @@ return function(code, ast, options)
end end
return r return r
end end
-- Returns a newline and add one level of indentation.
local function indent() local function indent()
indentLevel += 1 indentLevel += 1
return newline() return newline()
end end
-- Returns a newline and remove one level of indentation.
local function unindent() local function unindent()
indentLevel -= 1 indentLevel -= 1
return newline() return newline()
end end
local required = {} --- Module management
local required = {} -- { ["module"] = true, ... }
local requireStr = "" local requireStr = ""
local function addRequire(str, name, field) -- Add the module "mod" to the list of modules to require, and load its field "field" (or the whole module if nil) into the variable "name".
if not required[str] then local function addRequire(mod, name, field)
requireStr ..= "local " .. options.requirePrefix .. name .. (" = require(%q)"):format(str) .. (field and "."..field or "") .. options.newline if not required[mod] then
required[str] = true requireStr ..= "local " .. options.requirePrefix .. name .. (" = require(%q)"):format(mod) .. (field and "."..field or "") .. options.newline
required[mod] = true
end end
end end
-- Returns the required module variable name.
local function getRequire(name) local function getRequire(name)
return options.requirePrefix .. name return options.requirePrefix .. name
end end
--- AST traversal helpers
-- Returns the first node from the list "list" which tag is in the list "tags", or nil if there were none.
local function any(list, tags)
local tagsCheck = {}
for _, tag in ipairs(tags) do
tagsCheck[tag] = true
end
for _, node in ipairs(list) do
if tagsCheck[node.tag] then
return node
end
end
return nil
end
--- Modification helpers
local namedNodes = {} -- { ["name"] = ast, ... }
-- Wrap the compiled code of a named node with suffix and prefix.
local function wrap(name, prefix, suffix)
local node = namedNodes[name]
if not node then error("not inside a " .. name) end
node.prefix, node.suffix = prefix .. newline(), newline() .. suffix
end
--- Lua compiler
local tags local tags
-- Recursively returns the compiled AST Lua code, set "forceTag" to override the tag type and pass additional arguments to the tag constructor if needed.
local function lua(ast, forceTag, ...) local function lua(ast, forceTag, ...)
if options.mapLines and ast.pos then if options.mapLines and ast.pos then
lastInputPos = ast.pos lastInputPos = ast.pos
end end
return tags[forceTag or ast.tag](ast, ...) return tags[forceTag or ast.tag](ast, ...)
end end
-- Same as lua(), but gives the AST node a name which can be used for further access & modification.
local function namedLua(name, ast, ...)
local old = namedNodes[name]
namedNodes[name] = ast
local code = lua(ast, ...)
namedNodes[name] = old
return (ast.prefix or "") .. code .. (ast.suffix or "")
end
-- Tag constructors
tags = setmetatable({ tags = setmetatable({
-- block: { stat* } -- -- block: { stat* } --
Block = function(t) Block = (t)
local r = "" local r = ""
for i=1, #t-1, 1 do for i=1, #t-1, 1 do
r = r .. lua(t[i]) .. newline() r ..= lua(t[i]) .. newline()
end end
if t[#t] then if t[#t] then
r = r .. lua(t[#t]) r ..= lua(t[#t])
end end
return r return r
end, end,
@ -71,11 +113,11 @@ return function(code, ast, options)
-- stat -- -- stat --
-- Do{ stat* } -- Do{ stat* }
Do = function(t) Do = (t)
return "do" .. indent() .. lua(t, "Block") .. unindent() .. "end" return "do" .. indent() .. lua(t, "Block") .. unindent() .. "end"
end, end,
-- Set{ {lhs+} (opid? = opid?)? {expr+} } -- Set{ {lhs+} (opid? = opid?)? {expr+} }
Set = function(t) Set = (t)
if #t == 2 then if #t == 2 then
return lua(t[1], "_lhs") .. " = " .. lua(t[2], "_lhs") return lua(t[1], "_lhs") .. " = " .. lua(t[2], "_lhs")
elseif #t == 3 then elseif #t == 3 then
@ -84,82 +126,100 @@ return function(code, ast, options)
if t[3] == "=" then if t[3] == "=" then
local r = lua(t[1], "_lhs") .. " = " .. lua({ t[2], t[1][1], t[4][1] }, "Op") local r = lua(t[1], "_lhs") .. " = " .. lua({ t[2], t[1][1], t[4][1] }, "Op")
for i=2, math.min(#t[4], #t[1]), 1 do for i=2, math.min(#t[4], #t[1]), 1 do
r = r .. ", " .. lua({ t[2], t[1][i], t[4][i] }, "Op") r ..= ", " .. lua({ t[2], t[1][i], t[4][i] }, "Op")
end end
return r return r
else else
local r = lua(t[1], "_lhs") .. " = " .. lua({ t[3], t[4][1], t[1][1] }, "Op") local r = lua(t[1], "_lhs") .. " = " .. lua({ t[3], t[4][1], t[1][1] }, "Op")
for i=2, math.min(#t[4], #t[1]), 1 do for i=2, math.min(#t[4], #t[1]), 1 do
r = r .. ", " .. lua({ t[3], t[4][i], t[1][i] }, "Op") r ..= ", " .. lua({ t[3], t[4][i], t[1][i] }, "Op")
end end
return r return r
end end
else -- You are mad. else -- You are mad.
local r = lua(t[1], "_lhs") .. " = " .. lua({ t[2], t[1][1], { tag = "Op", t[4], t[5][1], t[1][1] } }, "Op") local r = lua(t[1], "_lhs") .. " = " .. lua({ t[2], t[1][1], { tag = "Op", t[4], t[5][1], t[1][1] } }, "Op")
for i=2, math.min(#t[5], #t[1]), 1 do for i=2, math.min(#t[5], #t[1]), 1 do
r = r .. ", " .. lua({ t[2], t[1][i], { tag = "Op", t[4], t[5][i], t[1][i] } }, "Op") r ..= ", " .. lua({ t[2], t[1][i], { tag = "Op", t[4], t[5][i], t[1][i] } }, "Op")
end end
return r return r
end end
end, end,
-- While{ expr block } -- While{ expr block }
While = function(t) While = (t)
return "while " .. lua(t[1]) .. " do" .. indent() .. lua(t[2]) .. unindent() .. "end" return "while " .. lua(t[1]) .. " do" .. indent() .. namedLua("loop", t[2]) .. unindent() .. "end"
end, end,
-- Repeat{ block expr } -- Repeat{ block expr }
Repeat = function(t) Repeat = (t)
return "repeat".. indent() .. lua(t[1]) .. unindent() .. "until " .. lua(t[2]) return "repeat".. indent() .. namedLua("loop", t[1]) .. unindent() .. "until " .. lua(t[2])
end, end,
-- If{ (expr block)+ block? } -- If{ (expr block)+ block? }
If = function(t) If = (t)
local r = "if " .. lua(t[1]) .. " then" .. indent() .. lua(t[2]) .. unindent() local r = "if " .. lua(t[1]) .. " then" .. indent() .. lua(t[2]) .. unindent()
for i=3, #t-1, 2 do for i=3, #t-1, 2 do
r = r .. "elseif " .. lua(t[i]) .. " then" .. indent() .. lua(t[i+1]) .. unindent() r ..= "elseif " .. lua(t[i]) .. " then" .. indent() .. lua(t[i+1]) .. unindent()
end end
if #t % 2 == 1 then if #t % 2 == 1 then
r = r .. "else" .. indent() .. lua(t[#t]) .. unindent() r ..= "else" .. indent() .. lua(t[#t]) .. unindent()
end end
return r .. "end" return r .. "end"
end, end,
-- Fornum{ ident expr expr expr? block } -- Fornum{ ident expr expr expr? block }
Fornum = function(t) Fornum = (t)
local r = "for " .. lua(t[1]) .. " = " .. lua(t[2]) .. ", " .. lua(t[3]) local r = "for " .. lua(t[1]) .. " = " .. lua(t[2]) .. ", " .. lua(t[3])
if #t == 5 then if #t == 5 then
return r .. ", " .. lua(t[4]) .. " do" .. indent() .. lua(t[5]) .. unindent() .. "end" return r .. ", " .. lua(t[4]) .. " do" .. indent() .. lua(t[5]) .. unindent() .. "end"
else else
return r .. " do" .. indent() .. lua(t[4]) .. unindent() .. "end" return r .. " do" .. indent() .. namedLua("loop", t[4]) .. unindent() .. "end"
end end
end, end,
-- Forin{ {ident+} {expr+} block } -- Forin{ {ident+} {expr+} block }
Forin = function(t) Forin = (t)
return "for " .. lua(t[1], "_lhs") .. " in " .. lua(t[2], "_lhs") .. " do" .. indent() .. lua(t[3]) .. unindent() .. "end" return "for " .. lua(t[1], "_lhs") .. " in " .. lua(t[2], "_lhs") .. " do" .. indent() .. namedLua("loop", t[3]) .. unindent() .. "end"
end, end,
-- Local{ {ident+} {expr+}? } -- Local{ {ident+} {expr+}? }
Local = function(t) Local = (t)
local r = "local "..lua(t[1], "_lhs") local r = "local "..lua(t[1], "_lhs")
if t[2][1] then if t[2][1] then
r = r .. " = "..lua(t[2], "_lhs") r ..= " = "..lua(t[2], "_lhs")
end
return r
end,
-- Let{ {ident+} {expr+}? }
Let = (t)
local nameList = lua(t[1], "_lhs")
local r = "local " .. nameList
if t[2][1] then
if any(t[2], { "Function", "Table", "Paren" }) then -- predeclaration doesn't matter otherwise
r ..= newline() .. nameList .. " = " .. lua(t[2], "_lhs")
else
r ..= " = " .. lua(t[2], "_lhs")
end
end end
return r return r
end, end,
-- Localrec{ ident expr } -- Localrec{ ident expr }
Localrec = function(t) Localrec = (t)
return "local function "..lua(t[1][1])..lua(t[2][1], "_functionWithoutKeyword") return "local function "..lua(t[1][1])..lua(t[2][1], "_functionWithoutKeyword")
end, end,
-- Goto{ <string> } -- Goto{ <string> }
Goto = function(t) Goto = (t)
return "goto " .. lua(t[1], "Id") return "goto " .. lua(t[1], "Id")
end, end,
-- Label{ <string> } -- Label{ <string> }
Label = function(t) Label = (t)
return "::" .. lua(t[1], "Id") .. "::" return "::" .. lua(t[1], "Id") .. "::"
end, end,
-- Return{ <expr*> } -- Return{ <expr*> }
Return = function(t) Return = (t)
return "return "..lua(t, "_lhs") return "return "..lua(t, "_lhs")
end, end,
-- Break -- Break
Break = function() Break = ()
return "break"
end,
-- Continue
Continue = ()
wrap("loop", "repeat", "until true")
return "break" return "break"
end, end,
-- apply (below) -- apply (below)
@ -167,27 +227,27 @@ return function(code, ast, options)
-- expr -- -- expr --
-- Nil -- Nil
Nil = function() Nil = ()
return "nil" return "nil"
end, end,
-- Dots -- Dots
Dots = function() Dots = ()
return "..." return "..."
end, end,
-- Boolean{ <boolean> } -- Boolean{ <boolean> }
Boolean = function(t) Boolean = (t)
return tostring(t[1]) return tostring(t[1])
end, end,
-- Number{ <number> } -- Number{ <number> }
Number = function(t) Number = (t)
return tostring(t[1]) return tostring(t[1])
end, end,
-- String{ <string> } -- String{ <string> }
String = function(t) String = (t)
return ("%q"):format(t[1]) return ("%q"):format(t[1])
end, end,
-- Function{ { ( `ParPair{ Id expr } | `Id{ <string> } )* `Dots? } block } -- Function{ { ( `ParPair{ Id expr } | `Id{ <string> } )* `Dots? } block }
_functionWithoutKeyword = function(t) _functionWithoutKeyword = (t)
local r = "(" local r = "("
local decl = {} local decl = {}
if t[1][1] then if t[1][1] then
@ -196,9 +256,9 @@ return function(code, ast, options)
indentLevel += 1 indentLevel += 1
table.insert(decl, id .. " = " .. id .. " == nil and " .. lua(t[1][1][2]) .. " or " .. id) table.insert(decl, id .. " = " .. id .. " == nil and " .. lua(t[1][1][2]) .. " or " .. id)
indentLevel -= 1 indentLevel -= 1
r = r .. id r ..= id
else else
r = r .. lua(t[1][1]) r ..= lua(t[1][1])
end end
for i=2, #t[1], 1 do for i=2, #t[1], 1 do
if t[1][i].tag == "ParPair" then if t[1][i].tag == "ParPair" then
@ -206,26 +266,26 @@ return function(code, ast, options)
indentLevel += 1 indentLevel += 1
table.insert(decl, "if " .. id .. " == nil then " .. id .. " = " .. lua(t[1][i][2]) .. " end") table.insert(decl, "if " .. id .. " == nil then " .. id .. " = " .. lua(t[1][i][2]) .. " end")
indentLevel -= 1 indentLevel -= 1
r = r .. ", " ..id r ..= ", " ..id
else else
r = r .. ", " .. lua(t[1][i]) r ..= ", " .. lua(t[1][i])
end end
end end
end end
r = r .. ")" .. indent() r ..= ")" .. indent()
for _, d in ipairs(decl) do for _, d in ipairs(decl) do
r = r .. d .. newline() r ..= d .. newline()
end end
return r .. lua(t[2]) .. unindent() .. "end" return r .. lua(t[2]) .. unindent() .. "end"
end, end,
Function = function(t) Function = (t)
return "function" .. lua(t, "_functionWithoutKeyword") return "function" .. lua(t, "_functionWithoutKeyword")
end, end,
-- Table{ ( `Pair{ expr expr } | expr )* } -- Table{ ( `Pair{ expr expr } | expr )* }
Pair = function(t) Pair = (t)
return "[" .. lua(t[1]) .. "] = " .. lua(t[2]) return "[" .. lua(t[1]) .. "] = " .. lua(t[2])
end, end,
Table = function(t) Table = (t)
if #t == 0 then if #t == 0 then
return "{}" return "{}"
elseif #t == 1 then elseif #t == 1 then
@ -235,7 +295,7 @@ return function(code, ast, options)
end end
end, end,
-- Op{ opid expr expr? } -- Op{ opid expr expr? }
Op = function(t) Op = (t)
local r local r
if #t == 2 then if #t == 2 then
if type(tags._opid[t[1]]) == "string" then if type(tags._opid[t[1]]) == "string" then
@ -253,7 +313,7 @@ return function(code, ast, options)
return r return r
end, end,
-- Paren{ expr } -- Paren{ expr }
Paren = function(t) Paren = (t)
return "(" .. lua(t[1]) .. ")" return "(" .. lua(t[1]) .. ")"
end, end,
-- apply (below) -- apply (below)
@ -262,23 +322,23 @@ return function(code, ast, options)
-- apply -- -- apply --
-- Call{ expr expr* } -- Call{ expr expr* }
Call = function(t) Call = (t)
return lua(t[1]) .. "(" .. lua(t, "_lhs", 2) .. ")" return lua(t[1]) .. "(" .. lua(t, "_lhs", 2) .. ")"
end, end,
-- Invoke{ expr `String{ <string> } expr* } -- Invoke{ expr `String{ <string> } expr* }
Invoke = function(t) Invoke = (t)
return lua(t[1])..":"..lua(t[2], "Id").."("..lua(t, "_lhs", 3)..")" return lua(t[1])..":"..lua(t[2], "Id").."("..lua(t, "_lhs", 3)..")"
end, end,
-- lhs -- -- lhs --
_lhs = function(t, start) _lhs = (t, start)
start = start or 1 start = start or 1
local r local r
if t[start] then if t[start] then
r = lua(t[start]) r = lua(t[start])
for i=start+1, #t, 1 do for i=start+1, #t, 1 do
r = r .. ", "..lua(t[i]) r ..= ", "..lua(t[i])
end end
else else
r = "" r = ""
@ -286,11 +346,11 @@ return function(code, ast, options)
return r return r
end, end,
-- Id{ <string> } -- Id{ <string> }
Id = function(t) Id = (t)
return t[1] return t[1]
end, end,
-- Index{ expr expr } -- Index{ expr expr }
Index = function(t) Index = (t)
return lua(t[1]).."["..lua(t[2]).."]" return lua(t[1]).."["..lua(t[2]).."]"
end, end,
@ -303,12 +363,13 @@ return function(code, ast, options)
["and"] = "and", ["or"] = "or", unm = "-", len = "#", bnot = "~", ["not"] = "not" ["and"] = "and", ["or"] = "or", unm = "-", len = "#", bnot = "~", ["not"] = "not"
} }
}, { }, {
__index = function(self, key) __index = (self, key)
error("don't know how to compile a "..tostring(key).." to Lua 5.3") error("don't know how to compile a "..tostring(key).." to Lua 5.3")
end end
}) })
#placeholder("patch") #placeholder("patch")
return requireStr .. lua(ast) .. newline() local code = lua(ast) .. newline()
return requireStr .. code
end end

View file

@ -40,23 +40,6 @@ local a = new Thing()
-> ->
(TODO: define how classes work. May even use ClassCommons) (TODO: define how classes work. May even use ClassCommons)
* continue keyword for loops
while true do
stuff()
if thing then
continue
end
end
->
while true do
repeat
stuff()
if thing then
break
end
until true
end
* list comprehension * list comprehension
local a = [x for x in pairs(stuff)] local a = [x for x in pairs(stuff)]
local a = [x for x in pairs(stuff) if x == true] local a = [x for x in pairs(stuff) if x == true]
@ -91,6 +74,8 @@ local a = if x == true then
return a return a
end end
With implicits returns?...
local stuff = for ... (accumulate in a table) local stuff = for ... (accumulate in a table)
* try / except|catch / finally / else / other keywords * try / except|catch / finally / else / other keywords
@ -139,11 +124,6 @@ local x, y $= pos
And in implicit assignments: And in implicit assignments:
for i, {x, y} in ipairs(positions) do for i, {x, y} in ipairs(positions) do
* local short alias
let a -> local a
or
var a
* Other potential inspiration * Other potential inspiration
https://love2d.org/forums/viewtopic.php?f=3&t=82650&sid=b6d9a8dec64afcc1c67806cb5ba65458 https://love2d.org/forums/viewtopic.php?f=3&t=82650&sid=b6d9a8dec64afcc1c67806cb5ba65458
https://www.ruby-lang.org/fr/ https://www.ruby-lang.org/fr/

View file

@ -15,11 +15,13 @@ stat:
| `Fornum{ ident expr expr expr? block } -- for ident = e, e[, e] do b end | `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 | `Forin{ {ident+} {expr+} block } -- for i1, i2... in e1, e2... do b end
| `Local{ {ident+} {expr+}? } -- local i1, i2... = e1, e2... | `Local{ {ident+} {expr+}? } -- local i1, i2... = e1, e2...
| `Let{ {ident+} {expr+}? } -- let i1, i2... = e1, e2...
| `Localrec{ ident expr } -- only used for 'local function' | `Localrec{ ident expr } -- only used for 'local function'
| `Goto{ <string> } -- goto str | `Goto{ <string> } -- goto str
| `Label{ <string> } -- ::str:: | `Label{ <string> } -- ::str::
| `Return{ <expr*> } -- return e1, e2... | `Return{ <expr*> } -- return e1, e2...
| `Break -- break | `Break -- break
| `Continue -- continue
| apply | apply
expr: expr:
@ -93,6 +95,7 @@ local labels = {
{ "ErrDoFor", "expected 'do' after the range of the for loop" }, { "ErrDoFor", "expected 'do' after the range of the for loop" },
{ "ErrDefLocal", "expected a function definition or assignment after local" }, { "ErrDefLocal", "expected a function definition or assignment after local" },
{ "ErrDefLet", "expected a function definition or assignment after let" },
{ "ErrNameLFunc", "expected a function name after 'function'" }, { "ErrNameLFunc", "expected a function name after 'function'" },
{ "ErrEListLAssign", "expected one or more expressions after '='" }, { "ErrEListLAssign", "expected one or more expressions after '='" },
{ "ErrEListAssign", "expected one or more expressions after '='" }, { "ErrEListAssign", "expected one or more expressions after '='" },
@ -272,7 +275,7 @@ local G = { V"Lua",
Block = tagC("Block", V"Stat"^0 * V"RetStat"^-1); Block = tagC("Block", V"Stat"^0 * V"RetStat"^-1);
Stat = V"IfStat" + V"DoStat" + V"WhileStat" + V"RepeatStat" + V"ForStat" Stat = V"IfStat" + V"DoStat" + V"WhileStat" + V"RepeatStat" + V"ForStat"
+ V"LocalStat" + V"FuncStat" + V"BreakStat" + V"LabelStat" + V"GoToStat" + V"LocalStat" + V"LetStat" + V"FuncStat" + V"BreakStat" + V"ContinueStat" + V"LabelStat" + V"GoToStat"
+ V"FuncCall" + V"Assignment" + sym(";") + -V"BlockEnd" * throw("InvalidStat"); + V"FuncCall" + V"Assignment" + sym(";") + -V"BlockEnd" * throw("InvalidStat");
BlockEnd = P"return" + "end" + "elseif" + "else" + "until" + -1; BlockEnd = P"return" + "end" + "elseif" + "else" + "until" + -1;
@ -296,6 +299,10 @@ local G = { V"Lua",
LocalStat = kw("local") * expect(V"LocalFunc" + V"LocalAssign", "DefLocal"); LocalStat = kw("local") * expect(V"LocalFunc" + V"LocalAssign", "DefLocal");
LocalFunc = tagC("Localrec", kw("function") * expect(V"Id", "NameLFunc") * V"FuncBody") / fixFuncStat; LocalFunc = tagC("Localrec", kw("function") * expect(V"Id", "NameLFunc") * V"FuncBody") / fixFuncStat;
LocalAssign = tagC("Local", V"NameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc()))); LocalAssign = tagC("Local", V"NameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc())));
LetStat = kw("let") * expect(V"LetAssign", "DefLet");
LetAssign = tagC("Let", V"NameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc())));
Assignment = tagC("Set", V"VarList" * V"BinOp"^-1 * (sym("=") / "=") * V"BinOp"^-1 * expect(V"ExprList", "EListAssign")); Assignment = tagC("Set", V"VarList" * V"BinOp"^-1 * (sym("=") / "=") * V"BinOp"^-1 * expect(V"ExprList", "EListAssign"));
FuncStat = tagC("Set", kw("function") * expect(V"FuncName", "FuncName") * V"FuncBody") / fixFuncStat; FuncStat = tagC("Set", kw("function") * expect(V"FuncName", "FuncName") * V"FuncBody") / fixFuncStat;
@ -312,10 +319,11 @@ local G = { V"Lua",
+ V"Id"; + V"Id";
ParKey = V"Id" * #("=" * -P"="); ParKey = V"Id" * #("=" * -P"=");
LabelStat = tagC("Label", sym("::") * expect(V"Name", "Label") * expect(sym("::"), "CloseLabel")); LabelStat = tagC("Label", sym("::") * expect(V"Name", "Label") * expect(sym("::"), "CloseLabel"));
GoToStat = tagC("Goto", kw("goto") * expect(V"Name", "Goto")); GoToStat = tagC("Goto", kw("goto") * expect(V"Name", "Goto"));
BreakStat = tagC("Break", kw("break")); BreakStat = tagC("Break", kw("break"));
RetStat = tagC("Return", kw("return") * commaSep(V"Expr", "RetList")^-1 * sym(";")^-1); ContinueStat = tagC("Continue", kw("continue"));
RetStat = tagC("Return", kw("return") * commaSep(V"Expr", "RetList")^-1 * sym(";")^-1);
NameList = tagC("NameList", commaSep(V"Id")); NameList = tagC("NameList", commaSep(V"Id"));
VarList = tagC("VarList", commaSep(V"VarExpr", "VarList")); VarList = tagC("VarList", commaSep(V"VarExpr", "VarList"));

View file

@ -162,6 +162,14 @@ local function traverse_break (env, stm)
return true return true
end end
local function traverse_continue (env, stm)
if not insideloop(env) then
local msg = "<continue> not inside a loop"
return nil, syntaxerror(env.errorinfo, stm.pos, msg)
end
return true
end
local function traverse_forin (env, stm) local function traverse_forin (env, stm)
begin_loop(env) begin_loop(env)
new_scope(env) new_scope(env)
@ -344,7 +352,8 @@ function traverse_stm (env, stm)
return traverse_fornum(env, stm) return traverse_fornum(env, stm)
elseif tag == "Forin" then -- `Forin{ {ident+} {expr+} block } elseif tag == "Forin" then -- `Forin{ {ident+} {expr+} block }
return traverse_forin(env, stm) return traverse_forin(env, stm)
elseif tag == "Local" then -- `Local{ {ident+} {expr+}? } elseif tag == "Local" or -- `Local{ {ident+} {expr+}? }
tag == "Let" then -- `Let{ {ident+} {expr+}? }
return traverse_let(env, stm) return traverse_let(env, stm)
elseif tag == "Localrec" then -- `Localrec{ ident expr } elseif tag == "Localrec" then -- `Localrec{ ident expr }
return traverse_letrec(env, stm) return traverse_letrec(env, stm)
@ -356,6 +365,8 @@ function traverse_stm (env, stm)
return traverse_return(env, stm) return traverse_return(env, stm)
elseif tag == "Break" then elseif tag == "Break" then
return traverse_break(env, stm) return traverse_break(env, stm)
elseif tag == "Continue" then
return traverse_continue(env, stm)
elseif tag == "Call" then -- `Call{ expr expr* } elseif tag == "Call" then -- `Call{ expr expr* }
return traverse_call(env, stm) return traverse_call(env, stm)
elseif tag == "Invoke" then -- `Invoke{ expr `String{ <string> } expr* } elseif tag == "Invoke" then -- `Invoke{ expr `String{ <string> } expr* }

View file

@ -1,6 +1,6 @@
package = "Candran" package = "candran"
version = "0.3.1-1" version = "0.4.0-1"
description = { description = {
summary = "A simple Lua dialect and preprocessor.", summary = "A simple Lua dialect and preprocessor.",
@ -9,15 +9,15 @@ description = {
Unlike Moonscript, Candran tries to stay close to the Lua syntax. Unlike Moonscript, Candran tries to stay close to the Lua syntax.
]], ]],
license = "MIT", license = "MIT",
homepage = "https://github.com/Reuh/Candran", homepage = "https://github.com/Reuh/candran",
--issues_url = "https://github.com/Reuh/Candran", -- LuaRocks 3.0 --issues_url = "https://github.com/Reuh/candran", -- LuaRocks 3.0
maintainer = "Étienne 'Reuh' Fildadut <fildadut@reuh.eu>", maintainer = "Étienne 'Reuh' Fildadut <fildadut@reuh.eu>",
--labels = {} -- LuaRocks 3.0 --labels = {} -- LuaRocks 3.0
} }
source = { source = {
url = "git://github.com/Reuh/Candran", url = "git://github.com/Reuh/candran",
tag = "v0.3.1" tag = "v0.4.0"
} }
dependencies = { dependencies = {

View file

@ -0,0 +1,36 @@
package = "candran"
version = "scm-1"
description = {
summary = "A simple Lua dialect and preprocessor.",
detailed = [[
Candran is a dialect of the Lua 5.3 programming language which compiles to Lua 5.3 and Lua 5.1/LuaJit. It adds a preprocessor and several useful syntax additions.
Unlike Moonscript, Candran tries to stay close to the Lua syntax.
]],
license = "MIT",
homepage = "https://github.com/Reuh/candran",
--issues_url = "https://github.com/Reuh/candran", -- LuaRocks 3.0
maintainer = "Étienne 'Reuh' Fildadut <fildadut@reuh.eu>",
--labels = {} -- LuaRocks 3.0
}
source = {
url = "git://github.com/Reuh/candran"
}
dependencies = {
"lua >= 5.1",
"lpeglabel >= 1.0.0"
}
build = {
type = "builtin",
modules = {
candran = "candran.lua"
},
install = {
bin = { "bin/can", "bin/canc" }
}
--copy_directories = { "doc", "test" }
}