1
0
Fork 0
mirror of https://github.com/Reuh/candran.git synced 2025-10-27 17:59:30 +00:00
* Fixed HORRIBLE parsing bugs with short functions and right assignemnt
operators
* Allowed to omit then, do and end for some statements
* Fixed hexa numbers parsing
* Run the Lua 5.3 test suite through Candran, everything that should
work worked! Yay!

Lacks tests and README
This commit is contained in:
Étienne Fildadut 2017-08-31 19:17:34 +02:00
parent 724249555f
commit 70d3aba121
8 changed files with 369 additions and 95 deletions

View file

@ -135,7 +135,7 @@ local function _()
return function(code, ast, options)
local lastInputPos = 1
local prevLinePos = 1
local lastSource = "nil"
local lastSource = options["chunkname"] or "nil"
local lastLine = 1
local indentLevel = 0
local function newline()
@ -449,10 +449,10 @@ end,
return "local function " .. lua(t[1][1]) .. lua(t[2][1], "_functionWithoutKeyword")
end,
["Goto"] = function(t)
return "goto " .. lua(t[1], "Id")
return "goto " .. lua(t, "Id")
end,
["Label"] = function(t)
return "::" .. lua(t[1], "Id") .. "::"
return "::" .. lua(t, "Id") .. "::"
end,
["Return"] = function(t)
local push = peek("push")
@ -509,7 +509,7 @@ if t[1][1] then
if t[1][1]["tag"] == "ParPair" then
local id = lua(t[1][1][1])
indentLevel = indentLevel + (1)
table["insert"](decl, id .. " = " .. id .. " == nil and " .. lua(t[1][1][2]) .. " or " .. id)
table["insert"](decl, "if " .. id .. " == nil then " .. id .. " = " .. lua(t[1][1][2]) .. " end")
indentLevel = indentLevel - (1)
r = r .. (id)
else
@ -616,7 +616,7 @@ end,
["IfExpr"] = function(t)
for i = 2, # t do
local block = t[i]
if block[# block]["tag"] == "Push" then
if block[# block] and block[# block]["tag"] == "Push" then
block[# block]["tag"] = "Return"
end
end
@ -694,7 +694,7 @@ local function _()
return function(code, ast, options)
local lastInputPos = 1
local prevLinePos = 1
local lastSource = "nil"
local lastSource = options["chunkname"] or "nil"
local lastLine = 1
local indentLevel = 0
local function newline()
@ -1008,10 +1008,10 @@ end,
return "local function " .. lua(t[1][1]) .. lua(t[2][1], "_functionWithoutKeyword")
end,
["Goto"] = function(t)
return "goto " .. lua(t[1], "Id")
return "goto " .. lua(t, "Id")
end,
["Label"] = function(t)
return "::" .. lua(t[1], "Id") .. "::"
return "::" .. lua(t, "Id") .. "::"
end,
["Return"] = function(t)
local push = peek("push")
@ -1068,7 +1068,7 @@ if t[1][1] then
if t[1][1]["tag"] == "ParPair" then
local id = lua(t[1][1][1])
indentLevel = indentLevel + (1)
table["insert"](decl, id .. " = " .. id .. " == nil and " .. lua(t[1][1][2]) .. " or " .. id)
table["insert"](decl, "if " .. id .. " == nil then " .. id .. " = " .. lua(t[1][1][2]) .. " end")
indentLevel = indentLevel - (1)
r = r .. (id)
else
@ -1175,7 +1175,7 @@ end,
["IfExpr"] = function(t)
for i = 2, # t do
local block = t[i]
if block[# block]["tag"] == "Push" then
if block[# block] and block[# block]["tag"] == "Push" then
block[# block]["tag"] = "Return"
end
end
@ -2178,7 +2178,7 @@ lpeg["locale"](lpeg)
local P, S, V = lpeg["P"], lpeg["S"], lpeg["V"]
local C, Carg, Cb, Cc = lpeg["C"], lpeg["Carg"], lpeg["Cb"], lpeg["Cc"]
local Cf, Cg, Cmt, Cp, Cs, Ct = lpeg["Cf"], lpeg["Cg"], lpeg["Cmt"], lpeg["Cp"], lpeg["Cs"], lpeg["Ct"]
local Lc, T = lpeg["Lc"], lpeg["T"]
local Rec, T = lpeg["Rec"], lpeg["T"]
local alpha, digit, alnum = lpeg["alpha"], lpeg["digit"], lpeg["alnum"]
local xdigit = lpeg["xdigit"]
local space = lpeg["space"]
@ -2610,52 +2610,176 @@ return {
[2] = t2[1]
}
end
local function fixAnonymousMethodParams(t1, t2)
if t1 == ":" then
t1 = t2
table["insert"](t1, 1, {
local function fixShortFunc(t)
if t[1] == ":" then
table["insert"](t[2], 1, {
["tag"] = "Id",
"self"
})
table["remove"](t, 1)
t["is_method"] = true
end
return t1
t["is_short"] = true
return t
end
local function statToExpr(t)
t["tag"] = t["tag"] .. "Expr"
return t
end
local function fixStructure(t)
local i = 1
while i <= # t do
if type(t[i]) == "table" then
fixStructure(t[i])
for j = # t[i], 1, - 1 do
local stat = t[i][j]
if type(stat) == "table" and stat["move_up_block"] and stat["move_up_block"] > 0 then
table["remove"](t[i], j)
table["insert"](t, i + 1, stat)
if t["tag"] == "Block" or t["tag"] == "Do" then
stat["move_up_block"] = stat["move_up_block"] - 1
end
end
end
end
i = i + 1
end
return t
end
local function searchEndRec(block, isRecCall)
for i, stat in ipairs(block) do
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
local exprlist
if stat["tag"] == "Set" or stat["tag"] == "Local" or stat["tag"] == "Let" or stat["tag"] == "Localrec" then
exprlist = stat[# stat]
elseif stat["tag"] == "Push" or stat["tag"] == "Return" then
exprlist = stat
end
local last = exprlist[# exprlist]
if last["tag"] == "Function" and last["is_short"] and not last["is_method"] and # last[1] == 1 then
local p = i
for j, fstat in ipairs(last[2]) do
p = i + j
table["insert"](block, p, fstat)
if stat["move_up_block"] then
fstat["move_up_block"] = (fstat["move_up_block"] or 0) + stat["move_up_block"]
end
if block["is_singlestatblock"] then
fstat["move_up_block"] = (fstat["move_up_block"] or 0) + 1
end
end
exprlist[# exprlist] = last[1]
exprlist[# exprlist]["tag"] = "Paren"
if not isRecCall then
for j = p + 1, # block, 1 do
block[j]["move_up_block"] = (block[j]["move_up_block"] or 0) + 1
end
end
return block, i
elseif last["tag"]:match("Expr$") then
local r = searchEndRec({ last })
if r then
for j = 2, # r, 1 do
table["insert"](block, i + j - 1, r[j])
end
return block, i
end
elseif last["tag"] == "Function" then
local r = searchEndRec(last[2])
if r then
return block, i
end
end
elseif stat["tag"]:match("^If") or stat["tag"]:match("^While") or stat["tag"]:match("^Repeat") or stat["tag"]:match("^Do") or stat["tag"]:match("^Fornum") or stat["tag"]:match("^Forin") then
local blocks
if stat["tag"]:match("^If") or stat["tag"]:match("^While") or stat["tag"]:match("^Repeat") or stat["tag"]:match("^Fornum") or stat["tag"]:match("^Forin") then
blocks = stat
elseif stat["tag"]:match("^Do") then
blocks = { stat }
end
for _, iblock in ipairs(blocks) do
if iblock["tag"] == "Block" then
local oldLen = # iblock
local newiBlock, newEnd = searchEndRec(iblock, true)
if newiBlock then
local p = i
for j = newEnd + (# iblock - oldLen) + 1, # iblock, 1 do
p = p + 1
table["insert"](block, p, iblock[j])
iblock[j] = nil
end
if not isRecCall then
for j = p + 1, # block, 1 do
block[j]["move_up_block"] = (block[j]["move_up_block"] or 0) + 1
end
end
return block, i
end
end
end
end
end
return nil
end
local function searchEnd(s, p, t)
local r = searchEndRec(fixStructure(t))
if not r then
return false
end
return true, r
end
local function expectBlockOrSingleStatWithStartEnd(start, startLabel, stopLabel, canFollow)
if canFollow then
return (- start * V("SingleStatBlock") * canFollow ^ - 1) + (expect(start, startLabel) * ((V("Block") * (canFollow + kw("end"))) + (Cmt(V("Block"), searchEnd) + throw(stopLabel))))
else
return (- start * V("SingleStatBlock")) + (expect(start, startLabel) * ((V("Block") * kw("end")) + (Cmt(V("Block"), searchEnd) + throw(stopLabel))))
end
end
local function expectBlockWithEnd(label)
return (V("Block") * kw("end")) + (Cmt(V("Block"), searchEnd) + throw(label))
end
local function maybeBlockWithEnd()
return (V("BlockNoErr") * kw("end")) + Cmt(V("BlockNoErr"), searchEnd)
end
local G = {
V("Lua"),
["Lua"] = V("Shebang") ^ - 1 * V("Skip") * V("Block") * expect(P(- 1), "Extra"),
["Lua"] = (V("Shebang") ^ - 1 * V("Skip") * V("Block") * expect(P(- 1), "Extra")) / fixStructure,
["Shebang"] = P("#!") * (P(1) - P("\
")) ^ 0,
["Block"] = tagC("Block", V("Stat") ^ 0 * (V("RetStat") + V("ImplicitPushStat")) ^ - 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") + V("LetStat") + V("ContinueStat") + V("PushStat") + sym(";") + - V("BlockEnd") * throw("InvalidStat"),
["BlockEnd"] = P("return") + "end" + "elseif" + "else" + "until" + "]" + - 1 + V("ImplicitPushStat"),
["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,
["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("FuncCall") + V("Assignment") + V("LetStat") + V("ContinueStat") + V("PushStat") + sym(";"),
["BlockEnd"] = P("return") + "end" + "elseif" + "else" + "until" + "]" + - 1 + V("ImplicitPushStat") + V("Assignment"),
["SingleStatBlock"] = tagC("Block", V("Stat") + V("RetStat") + V("ImplicitPushStat")) / function(t)
t["is_singlestatblock"] = true
return t
end,
["BlockNoErr"] = tagC("Block", V("Stat") ^ 0 * ((V("RetStat") + V("ImplicitPushStat")) * sym(";") ^ - 1) ^ - 1),
["IfStat"] = tagC("If", V("IfPart")),
["IfPart"] = kw("if") * expect(V("Expr"), "ExprIf") * expectBlockOrSingleStatWithStartEnd(kw("then"), "ThenIf", "EndIf", V("ElseIfPart") + V("ElsePart")),
["ElseIfPart"] = kw("elseif") * expect(V("Expr"), "ExprEIf") * expectBlockOrSingleStatWithStartEnd(kw("then"), "ThenEIf", "EndIf", V("ElseIfPart") + V("ElsePart")),
["ElsePart"] = kw("else") * expectBlockWithEnd("EndIf"),
["DoStat"] = kw("do") * expectBlockWithEnd("EndDo") / tagDo,
["WhileStat"] = tagC("While", kw("while") * expect(V("Expr"), "ExprWhile") * V("WhileBody")),
["WhileBody"] = expect(kw("do"), "DoWhile") * V("Block") * expect(kw("end"), "EndWhile"),
["WhileBody"] = expectBlockOrSingleStatWithStartEnd(kw("do"), "DoWhile", "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"),
["ForStat"] = kw("for") * expect(V("ForNum") + V("ForIn"), "ForRange"),
["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"),
["ForBody"] = expectBlockOrSingleStatWithStartEnd(kw("do"), "DoFor", "EndFor"),
["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")),
["Assignment"] = tagC("Set", V("VarList") * V("BinOp") ^ - 1 * (P("=") / "=") * V("BinOp") ^ - 1 * V("Skip") * 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")),
["FuncBody"] = tagC("Function", V("FuncParams") * expectBlockWithEnd("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()),
["ShortFuncDef"] = tagC("Function", V("ShortFuncParams") * maybeBlockWithEnd()) / fixShortFunc,
["ShortFuncParams"] = (sym(":") / ":") ^ - 1 * sym("(") * V("ParList") * sym(")"),
["NamedParList"] = tagC("NamedParList", commaSep(V("NamedPar"))),
["NamedPar"] = tagC("ParPair", V("ParKey") * expect(sym("="), "EqField") * expect(V("Expr"), "ExprField")) + V("Id"),
["ParKey"] = V("Id") * # ("=" * - P("=")),
@ -2663,9 +2787,9 @@ V("Lua"),
["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),
["PushStat"] = tagC("Push", kw("push") * commaSep(V("Expr"), "RetList") ^ - 1 * sym(";") ^ - 1),
["ImplicitPushStat"] = tagC("Push", commaSep(V("Expr"), "RetList") * sym(";") ^ - 1),
["RetStat"] = tagC("Return", kw("return") * commaSep(V("Expr"), "RetList") ^ - 1),
["PushStat"] = tagC("Push", kw("push") * commaSep(V("Expr"), "RetList") ^ - 1),
["ImplicitPushStat"] = tagC("Push", commaSep(V("Expr"), "RetList")),
["NameList"] = tagC("NameList", commaSep(V("Id"))),
["VarList"] = tagC("VarList", commaSep(V("VarExpr"))),
["ExprList"] = tagC("ExpList", commaSep(V("Expr"), "ExprList")),
@ -2682,7 +2806,7 @@ V("Lua"),
["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") + V("TableCompr") + V("StatExpr"),
["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("ShortFuncDef") + V("SuffixedExpr") + V("TableCompr") + V("StatExpr"),
["StatExpr"] = (V("IfStat") + V("DoStat") + V("WhileStat") + V("RepeatStat") + V("ForStat")) / statToExpr,
["FuncCall"] = Cmt(V("SuffixedExpr"), function(s, i, exp)
return exp["tag"] == "Call" or exp["tag"] == "Invoke", exp
@ -2696,9 +2820,7 @@ end),
["Call"] = tagC("Invoke", Cg(sym(":" * - P(":")) * expect(V("StrId"), "NameMeth") * expect(V("FuncArgs"), "MethArgs"))) + tagC("Call", V("FuncArgs")),
["SelfIndex"] = tagC("DotIndex", V("StrId")),
["SelfCall"] = tagC("Invoke", Cg(V("StrId") * V("FuncArgs"))),
["ShortFuncDef"] = tagC("Function", V("ShortFuncParams") * V("Block") * expect(kw("end"), "EndFunc")),
["ShortFuncParams"] = (sym(":") / ":") ^ - 1 * sym("(") * V("ParList") * sym(")") / fixAnonymousMethodParams,
["FuncDef"] = (kw("function") * V("FuncBody")) + V("ShortFuncDef"),
["FuncDef"] = (kw("function") * V("FuncBody")),
["FuncArgs"] = sym("(") * commaSep(V("Expr"), "ArgList") ^ - 1 * expect(sym(")"), "CParenArgs") + V("Table") + tagC("String", V("String")),
["Table"] = tagC("Table", sym("{") * V("FieldList") ^ - 1 * expect(sym("}"), "CBraceTable")),
["FieldList"] = sepBy(V("Field"), V("FieldSep")) * V("FieldSep") ^ - 1,
@ -2721,11 +2843,13 @@ end + P("--") * (P(1) - P("\
["Ident"] = V("IdStart") * V("IdRest") ^ 0,
["IdStart"] = alpha + P("_"),
["IdRest"] = alnum + P("_"),
["Number"] = token((V("Hex") + V("Float") + V("Int")) / tonumber),
["Hex"] = (P("0x") + "0X") * expect(xdigit ^ 1, "DigitHex"),
["Number"] = token(C(V("Hex") + V("Float") + V("Int"))),
["Hex"] = (P("0x") + "0X") * ((xdigit ^ 0 * V("DeciHex")) + (expect(xdigit ^ 1, "DigitHex") * V("DeciHex") ^ - 1)) * V("ExpoHex") ^ - 1,
["Float"] = V("Decimal") * V("Expo") ^ - 1 + V("Int") * V("Expo"),
["Decimal"] = digit ^ 1 * "." * digit ^ 0 + P(".") * - P(".") * expect(digit ^ 1, "DigitDeci"),
["DeciHex"] = P(".") * xdigit ^ 0,
["Expo"] = S("eE") * S("+-") ^ - 1 * expect(digit ^ 1, "DigitExpo"),
["ExpoHex"] = S("pP") * S("+-") ^ - 1 * expect(xdigit ^ 1, "DigitExpo"),
["Int"] = digit ^ 1,
["String"] = token(V("ShortStr") + V("LongStr")),
["ShortStr"] = P("\"") * Cs((V("EscSeq") + (P(1) - S("\"\
@ -2782,7 +2906,7 @@ return parser
end
local parser = _() or parser
package["loaded"]["lib.lua-parser.parser"] = parser or true
local candran = { ["VERSION"] = "0.5.0" }
local candran = { ["VERSION"] = "0.6.0" }
local default = {
["target"] = "lua53",
["indentation"] = "",
@ -2872,7 +2996,7 @@ end
candran["compile"] = function(input, options)
if options == nil then options = {} end
options = util["merge"](default, options)
local ast, errmsg = parser["parse"](input, "candran")
local ast, errmsg = parser["parse"](input, options["chunkname"])
if not ast then
error("Compiler: error while parsing file: " .. errmsg)
end