Fixed some diagnostics warnings

Moved examples to tofix because fixing them is besides the point right
now.
This commit is contained in:
Dawid Sobczak 2023-09-19 11:42:10 +01:00
parent 52164c82e3
commit 858fe11666
166 changed files with 68 additions and 264 deletions

View file

@ -0,0 +1,799 @@
local lua = require "lua-parser"
local peg = require "peg-parser"
local eq = require "equals"
local equals = eq.equals
print("\n\n [[ PARSING LUA TEST SUITE FILES ]] \n\n")
local filenames = {
'all.lua',
'main.lua',
'gc.lua',
'db.lua',
'calls.lua',
'strings.lua',
'literals.lua',
'tpack.lua',
'attrib.lua',
'locals.lua',
'constructs.lua',
'code.lua',
'big.lua',
'nextvar.lua',
'pm.lua',
'utf8.lua',
'api.lua',
'events.lua',
'vararg.lua',
'closure.lua',
'coroutine.lua',
'goto.lua',
'errors.lua',
'math.lua',
'sort.lua',
'bitwise.lua',
'verybig.lua',
'files.lua',
}
local errs = 0
for k,v in ipairs(filenames) do
local filename = "lua-5.3.4-tests/"..v
local f = assert(io.open(filename, "r"))
local t = f:read("*all")
local res, err = lua.parse(t)
local s = "OK"
if not res then s = "FAIL" end -- only check if succesful since grammar ensures whole file is read
print("Testing file '"..v.."': ["..s.."]")
if not res then
errs = errs + 1
print("Error: "..err[1]["msg"])
end
f:close()
end
assert(errs == 0)
print("\n\n Test suite files compiled successfully")
print("\n\n [[ TESTING ERROR LABELS ]] ")
local pr = peg.print_r
-- test errors
local s,res, err
local ErrExtra="unexpected character(s), expected EOF"
s = [[ return; ! ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrExtra)
local ErrInvalidStat="unexpected token, invalid start of statement"
s = [[ ! ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrInvalidStat)
local ErrEndIf="expected 'end' to close the if statement"
s = [[ if c then b=1 ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrEndIf)
local ErrExprIf="expected a condition after 'if'"
s = [[ if then b=1 end]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrExprIf)
local ErrThenIf="expected 'then' after the condition"
s = [[ if c b=1 end ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrThenIf)
local ErrExprEIf="expected a condition after 'elseif'"
s = [[ if a then b=1 elseif then d=1 end ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrExprEIf)
local ErrThenEIf="expected 'then' after the condition"
s = [[ if a b=1 end]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrThenEIf)
local ErrEndDo="expected 'end' to close the do block"
s = [[ do x=1 ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrEndDo)
local ErrExprWhile="expected a condition after 'while'"
s = [[ while do c=1 end]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrExprWhile)
local ErrDoWhile="expected 'do' after the condition"
s = [[ while a c=1 end ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrDoWhile)
local ErrEndWhile="expected 'end' to close the while loop"
s = [[ while a do b=1]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrEndWhile)
local ErrUntilRep="expected 'until' at the end of the repeat loop"
s = [[ repeat c=1 ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrUntilRep)
local ErrExprRep="expected a conditions after 'until'"
s = [[ repeat c=1 until ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrExprRep)
local ErrForRange="expected a numeric or generic range after 'for'"
s = [[ for 3,4 do x=1 end]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrForRange)
local ErrEndFor="expected 'end' to close the for loop"
s = [[ for c=1,3 do a=1 ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrEndFor)
local ErrExprFor1="expected a starting expression for the numeric range"
s = [[ for a=,4 do a=1 end]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrExprFor1)
local ErrCommaFor="expected ',' to split the start and end of the range"
s = [[ for a=4 5 do a=1 end]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrCommaFor)
local ErrExprFor2="expected an ending expression for the numeric range"
s = [[ for a=4, do a=1 end]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrExprFor2)
local ErrExprFor3="expected a step expression for the numeric range after ','"
s = [[ for a=1,2, do a=1 end ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrExprFor3)
local ErrInFor="expected '=' or 'in' after the variable(s)"
s = [[ for a of 1 do a=1 end]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrInFor)
local ErrEListFor="expected one or more expressions after 'in'"
s = [[ for a in do a=1 end ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrEListFor)
local ErrDoFor="expected 'do' after the range of the for loop"
s = [[ for a=1,2 a=1 end ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrDoFor)
local ErrDefLocal="expected a function definition or assignment after local"
s = [[ local return c ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrDefLocal)
local ErrNameLFunc="expected a function name after 'function'"
s = [[ local function() c=1 end ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrNameLFunc)
local ErrEListLAssign="expected one or more expressions after '='"
s = [[ local a = return b ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrEListLAssign)
local ErrEListAssign="expected one or more expressions after '='"
s = [[ a = return b ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrEListAssign)
local ErrFuncName="expected a function name after 'function'"
s = [[ function () a=1 end ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrFuncName)
local ErrNameFunc1="expected a function name after '.'"
s = [[ function a.() a=1 end ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrNameFunc1)
local ErrNameFunc2="expected a method name after ':'"
s = [[ function a:() a=1 end ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrNameFunc2)
local ErrOParenPList="expected '(' for the parameter list"
s = [[ function a b=1 end]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrOParenPList)
local ErrCParenPList="expected ')' to close the parameter list"
s = [[
function a(
b=1
end
]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrCParenPList)
local ErrEndFunc="expected 'end' to close the function body"
s = [[ function a() b=1 ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrEndFunc)
local ErrParList="expected a variable name or '...' after ','"
s = [[ function a(b, ) b=1 end ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrParList)
local ErrLabel="expected a label name after '::'"
s = [[ :: return b ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrLabel)
local ErrCloseLabel="expected '::' after the label"
s = [[ :: abc return a]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrCloseLabel)
local ErrGoto="expected a label after 'goto'"
s = [[ goto return c]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrGoto)
local ErrVarList="expected a variable name after ','"
s = [[ abc,
= 3]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrVarList)
local ErrExprList="expected an expression after ','"
s = [[ return a,;]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrExprList)
local ErrOrExpr="expected an expression after 'or'"
s = [[ return a or; ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrOrExpr)
local ErrAndExpr="expected an expression after 'and'"
s = [[ return a and;]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrAndExpr)
local ErrRelExpr="expected an expression after the relational operator"
s = [[ return a >;]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrRelExpr)
local ErrBitwiseExpr="expected an expression after bitwise operator"
s = [[ return b & ; ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrBitwiseExpr)
local ErrConcatExpr="expected an expression after '..'"
s = [[ print(a..) ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrConcatExpr)
local ErrAddExpr="expected an expression after the additive operator"
s = [[ return a - ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrAddExpr)
local ErrMulExpr="expected an expression after the multiplicative operator"
s = [[ return a/ ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrMulExpr)
local ErrUnaryExpr="expected an expression after the unary operator"
s = [[ return # ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrUnaryExpr)
local ErrPowExpr="expected an expression after '^'"
s = [[ return a^ ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrPowExpr)
local ErrExprParen="expected an expression after '('"
s = [[ return a + () ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrExprParen)
local ErrCParenExpr="expected ')' to close the expression"
s = [[ return a + (a ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrCParenExpr)
local ErrNameIndex="expected a field name after '.'"
s = [[ return a. ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrNameIndex)
local ErrExprIndex="expected an expression after '['"
s = [[ return a [ ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrExprIndex)
local ErrCBracketIndex="expected ']' to close the indexing expression"
s = [[ return a[1 ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrCBracketIndex)
local ErrNameMeth="expected a method name after ':'"
s = [[ return a: ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrNameMeth)
local ErrMethArgs="expected some arguments for the method call (or '()')"
s = [[ a:b ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrMethArgs)
local ErrCParenArgs="expected ')' to close the argument list"
s = [[ return a(c ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrCParenArgs)
local ErrCBraceTable="expected '}' to close the table constructor"
s = [[ return { ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrCBraceTable)
local ErrEqField="expected '=' after the table key"
s = [[ a = {[b] b} ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrEqField)
local ErrExprField="expected an expression after '='"
s = [[ a = {[a] = } ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrExprField)
local ErrExprFKey="expected an expression after '[' for the table key"
s = [[ a = {[ = b} ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrExprFKey)
local ErrCBracketFKey="expected ']' to close the table key"
s = [[ a = {[a = b} ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrCBracketFKey)
local ErrDigitHex="expected one or more hexadecimal digits after '0x'"
s = [[ a = 0x ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrDigitHex)
local ErrDigitDeci="expected one or more digits after the decimal point"
s = [[ a = . ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrDigitDeci)
local ErrDigitExpo="expected one or more digits for the exponent"
s = [[ a = 1.0e ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrDigitExpo)
local ErrQuote="unclosed string"
s = [[ a = ";]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrQuote)
local ErrHexEsc="expected exactly two hexadecimal digits after '\\x'"
s = [[ a = "a\x1" ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrHexEsc)
local ErrOBraceUEsc="expected '{' after '\\u'"
s = [[ a = "a\u" ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrOBraceUEsc)
local ErrDigitUEsc="expected one or more hexadecimal digits for the UTF-8 code point"
s = [[ a = "\u{}"]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrDigitUEsc)
local ErrCBraceUEsc="expected '}' after the code point"
s = [[ a = "\u{12" ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrCBraceUEsc)
local ErrEscSeq="invalid escape sequence"
s = [[ a = "\;" ]]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrEscSeq)
local ErrCloseLStr="unclosed long string"
s = [==[ a = [[ abc return; ]==]
print("Parsing '"..s.."'")
res, err = lua.parse(s)
assert(err[1]["msg"] == ErrCloseLStr)
print("\n\n All error labels generated successfully")
print("\n\n [[ TESTING AST GENERATION ]]\n\n ")
-- TODO: AST
s = [[
if abc > 123 then
abc=123
end]]
rez = {
rule='chunk',
pos=3,
{
rule='block',
pos=3,
{
rule='stat',
pos=3,
'if',
{
rule='exp',
pos=6,
{
rule='exp',
{
rule='exp',
{
rule='expTokens',
pos=6,
{
rule='prefixexp',
pos=6,
{
rule='varOrExp',
pos=6,
{
rule='var',
pos=6,
{
rule='NAME',
pos=6,
'abc',
},
},
},
},
},
},
{
rule='operatorComparison',
pos=10,
'>',
},
{
rule='expTokens',
pos=12,
{
rule='number',
pos=12,
{
rule='INT',
pos=12,
'123',
},
},
},
},
},
'then',
{
rule='block',
pos=23,
{
rule='stat',
pos=23,
{
rule='varlist',
pos=23,
{
rule='var',
pos=23,
{
rule='NAME',
pos=23,
'abc',
},
},
},
'=',
{
rule='explist',
pos=27,
{
rule='exp',
pos=27,
{
rule='expTokens',
pos=27,
{
rule='number',
pos=27,
{
rule='INT',
pos=27,
'123',
},
},
},
},
},
},
},
'end',
},
},
}
print("Parsing '"..s.."'")
res, err = lua.parse(s)
peg.print_t(res)
assert(equals(res,rez))
s = [[
local a = [=[ long string ]=]
-- aaa
return a
--[==[ hi
]==]
]]
rez = {
rule='chunk',
pos=3,
{
rule='block',
pos=3,
{
rule='stat',
pos=3,
'local',
{
rule='localAssign',
pos=9,
{
rule='namelist',
pos=9,
{
rule='NAME',
pos=9,
'a',
},
},
'=',
{
rule='explist',
pos=13,
{
rule='exp',
pos=13,
{
rule='expTokens',
pos=13,
{
rule='string',
pos=13,
' long string ',
},
},
},
},
},
},
{
rule='retstat',
pos=41,
'return',
{
rule='explist',
pos=48,
{
rule='exp',
pos=48,
{
rule='expTokens',
pos=48,
{
rule='prefixexp',
pos=48,
{
rule='varOrExp',
pos=48,
{
rule='var',
pos=48,
{
rule='NAME',
pos=48,
'a',
},
},
},
},
},
},
},
},
},
}
print("Parsing '"..s.."'")
res, err = lua.parse(s)
peg.print_t(res)
assert(equals(res,rez))
print("\n\n All AST's generated successfully")
print("\n\nAll tests passed!")

View file

@ -0,0 +1,291 @@
--[==[
Parser for Lua 5.3
Based on https://github.com/antlr/grammars-v4/blob/master/lua/Lua.g4 and https://github.com/andremm/lua-parser/blob/master/lua-parser/parser.lua
]==]
package.path = package.path .. ";../?.lua"
local pg = require "parser-gen"
function equals(s,i,a,b) return #a == #b end
function fixexp (...)
local exp = {...}
local len = #exp
if len > 1 then
exp.rule = "exp"
exp[len].rule = "exp"
return exp
elseif exp[1] then
if exp[1].rule == "expTokens" then
return exp[1]
else
return exp[1][1]
end
end
end
function fold (...)
local exp = {...}
local len = #exp
if len > 1 then
local folded = { rule = "exp", fixexp(exp[1]) }
for i = 2, len, 2 do
folded = { rule = "exp", folded, exp[i], fixexp(exp[i+1]) }
end
return folded
elseif exp[1] then
return exp[1][1]
end
end
-- from https://github.com/andremm/lua-parser/blob/master/lua-parser/parser.lua
local labels = {
ErrExtra="unexpected character(s), expected EOF",
ErrInvalidStat={"unexpected token, invalid start of statement",[[ (!%nl .)* ]]},
ErrEndIf="expected 'end' to close the if statement",
ErrExprIf="expected a condition after 'if'",
ErrThenIf="expected 'then' after the condition",
ErrExprEIf="expected a condition after 'elseif'",
ErrThenEIf="expected 'then' after the condition",
ErrEndDo="expected 'end' to close the do block",
ErrExprWhile="expected a condition after 'while'",
ErrDoWhile="expected 'do' after the condition",
ErrEndWhile="expected 'end' to close the while loop",
ErrUntilRep="expected 'until' at the end of the repeat loop",
ErrExprRep="expected a conditions after 'until'",
ErrForRange="expected a numeric or generic range after 'for'",
ErrEndFor="expected 'end' to close the for loop",
ErrExprFor1="expected a starting expression for the numeric range",
ErrCommaFor="expected ',' to split the start and end of the range",
ErrExprFor2="expected an ending expression for the numeric range",
ErrExprFor3={"expected a step expression for the numeric range after ','",[[ (!'do' !%nl .)* ]]},
ErrInFor="expected '=' or 'in' after the variable(s)",
ErrEListFor="expected one or more expressions after 'in'",
ErrDoFor="expected 'do' after the range of the for loop",
ErrDefLocal="expected a function definition or assignment after local",
ErrNameLFunc="expected a function name after 'function'",
ErrEListLAssign="expected one or more expressions after '='",
ErrEListAssign="expected one or more expressions after '='",
ErrFuncName="expected a function name after 'function'",
ErrNameFunc1="expected a function name after '.'",
ErrNameFunc2="expected a method name after ':'",
ErrOParenPList="expected '(' for the parameter list",
ErrCParenPList="expected ')' to close the parameter list",
ErrEndFunc="expected 'end' to close the function body",
ErrParList="expected a variable name or '...' after ','",
ErrLabel="expected a label name after '::'",
ErrCloseLabel="expected '::' after the label",
ErrGoto="expected a label after 'goto'",
ErrVarList={"expected a variable name after ','",[[ (!'=' !%nl .)* ]]},
ErrExprList="expected an expression after ','",
ErrOrExpr="expected an expression after 'or'",
ErrAndExpr="expected an expression after 'and'",
ErrRelExpr="expected an expression after the relational operator",
ErrBitwiseExpr="expected an expression after bitwise operator",
ErrConcatExpr="expected an expression after '..'",
ErrAddExpr="expected an expression after the additive operator",
ErrMulExpr="expected an expression after the multiplicative operator",
ErrUnaryExpr="expected an expression after the unary operator",
ErrPowExpr="expected an expression after '^'",
ErrExprParen="expected an expression after '('",
ErrCParenExpr="expected ')' to close the expression",
ErrNameIndex="expected a field name after '.'",
ErrExprIndex="expected an expression after '['",
ErrCBracketIndex="expected ']' to close the indexing expression",
ErrNameMeth="expected a method name after ':'",
ErrMethArgs="expected some arguments for the method call (or '()')",
ErrCParenArgs="expected ')' to close the argument list",
ErrCBraceTable="expected '}' to close the table constructor",
ErrEqField="expected '=' after the table key",
ErrExprField="expected an expression after '='",
ErrExprFKey={"expected an expression after '[' for the table key",[[ (!']' !%nl .)* ]] },
ErrCBracketFKey={"expected ']' to close the table key",[[ (!'=' !%nl .)* ]]},
ErrDigitHex="expected one or more hexadecimal digits after '0x'",
ErrDigitDeci="expected one or more digits after the decimal point",
ErrDigitExpo="expected one or more digits for the exponent",
ErrQuote="unclosed string",
ErrHexEsc={"expected exactly two hexadecimal digits after '\\x'",[[ (!('"' / "'" / %nl) .)* ]]},
ErrOBraceUEsc="expected '{' after '\\u'",
ErrDigitUEsc={"expected one or more hexadecimal digits for the UTF-8 code point",[[ (!'}' !%nl .)* ]]},
ErrCBraceUEsc={"expected '}' after the code point",[[ (!('"' / "'") .)* ]]},
ErrEscSeq={"invalid escape sequence",[[ (!('"' / "'" / %nl) .)* ]]},
ErrCloseLStr="unclosed long string",
ErrEqAssign="expected '=' after variable list in assign statement"
}
pg.setlabels(labels)
local grammar = pg.compile([==[
chunk <- block (!.)^ErrExtra
block <- stat* retstat?
stat <- ';' /
functioncall /
varlist '='^ErrEqAssign explist^ErrEListAssign /
'break' /
'goto' NAME^ErrGoto /
'do' block 'end'^ErrEndDo /
'while' exp^ErrExprWhile 'do'^ErrDoWhile block 'end'^ErrEndWhile /
'repeat' block 'until'^ErrUntilRep exp^ErrExprRep /
'if' exp^ErrExprIf 'then'^ErrThenIf block ('elseif' exp^ErrExprEIf 'then'^ErrThenEIf block)* ('else' block)? 'end'^ErrEndIf /
'for' (forNum / forIn)^ErrForRange 'do'^ErrDoFor block 'end'^ErrEndFor /
'function' funcname^ErrFuncName funcbody /
'local' (localAssign / localFunc)^ErrDefLocal /
label /
!blockEnd %{ErrInvalidStat}
blockEnd <- 'return' / 'end' / 'elseif' / 'else' / 'until' / !.
retstat <- 'return' explist? ';'?
forNum <- NAME '=' exp^ErrExprFor1 ','^ErrCommaFor exp^ErrExprFor2 (',' exp^ErrExprFor3)?
forIn <- namelist 'in'^ErrInFor explist^ErrEListFor
localFunc <- 'function' NAME^ErrNameLFunc funcbody
localAssign <- namelist ('=' explist^ErrEListLAssign)?
label <- '::' NAME^ErrLabel '::'^ErrCloseLabel
funcname <- NAME ('.' NAME^ErrNameFunc1)* (':' NAME^ErrNameFunc2)?
varlist <- var (',' var^ErrVarList)*
namelist <- NAME (',' NAME)*
explist <- exp (',' exp^ErrExprList )*
exp <- expOR -> fixexp
expOR <- (expAND (operatorOr expAND^ErrOrExpr)*) -> fold
expAND <- (expREL (operatorAnd expREL^ErrAndExpr)*) -> fold
expREL <- (expBIT (operatorComparison expBIT^ErrRelExpr)*) -> fold
expBIT <- (expCAT (operatorBitwise expCAT^ErrBitwiseExpr)*) -> fold
expCAT <- (expADD (operatorStrcat expCAT^ErrConcatExpr)?) -> fixexp
expADD <- (expMUL (operatorAddSub expMUL^ErrAddExpr)*) -> fold
expMUL <- (expUNA (operatorMulDivMod expUNA^ErrMulExpr)*) -> fold
expUNA <- ((operatorUnary expUNA^ErrUnaryExpr) / expPOW) -> fixexp
expPOW <- (expTokens (operatorPower expUNA^ErrPowExpr)?) -> fixexp
expTokens <- 'nil' / 'false' / 'true' /
number /
string /
'...' /
'function' funcbody /
tableconstructor /
prefixexp
prefixexp <- varOrExp nameAndArgs*
functioncall <- varOrExp nameAndArgs+
varOrExp <- var / brackexp
brackexp <- '(' exp^ErrExprParen ')'^ErrCParenExpr
var <- (NAME / brackexp varSuffix) varSuffix*
varSuffix <- nameAndArgs* ('[' exp^ErrExprIndex ']'^ErrCBracketIndex / '.' !'.' NAME^ErrNameIndex)
nameAndArgs <- (':' !':' NAME^ErrNameMeth args^ErrMethArgs) /
args
args <- '(' explist? ')'^ErrCParenArgs / tableconstructor / string
funcbody <- '('^ErrOParenPList parlist? ')'^ErrCParenPList block 'end'^ErrEndFunc
parlist <- namelist (',' '...'^ErrParList)? / '...'
tableconstructor<- '{' fieldlist? '}'^ErrCBraceTable
fieldlist <- field (fieldsep field)* fieldsep?
field <- !OPEN '[' exp^ErrExprFKey ']'^ErrCBracketFKey '='^ErrEqField exp^ErrExprField /
NAME '=' exp /
exp
fieldsep <- ',' / ';'
operatorOr <- 'or'
operatorAnd <- 'and'
operatorComparison<- '<=' / '>=' / '~=' / '==' / '<' !'<' / '>' !'>'
operatorStrcat <- !'...' '..'
operatorAddSub <- '+' / '-'
operatorMulDivMod<- '*' / '%' / '//' / '/'
operatorBitwise <- '&' / '|' / !'~=' '~' / '<<' / '>>'
operatorUnary <- 'not' / '#' / '-' / !'~=' '~'
operatorPower <- '^'
number <- FLOAT / HEX_FLOAT / HEX / INT
string <- NORMALSTRING / CHARSTRING / LONGSTRING
-- lexer
fragment
RESERVED <- KEYWORDS !IDREST
fragment
IDREST <- [a-zA-Z_0-9]
fragment
KEYWORDS <- 'and' / 'break' / 'do' / 'elseif' / 'else' / 'end' /
'false' / 'for' / 'function' / 'goto' / 'if' / 'in' /
'local' / 'nil' / 'not' / 'or' / 'repeat' / 'return' /
'then' / 'true' / 'until' / 'while'
NAME <- !RESERVED [a-zA-Z_] [a-zA-Z_0-9]*
fragment
NORMALSTRING <- '"' {( ESC / [^"\] )*} '"'^ErrQuote
fragment
CHARSTRING <- "'" {( ESC / [^\'] )*} "'"^ErrQuote
fragment
LONGSTRING <- (OPEN {(!CLOSEEQ .)*} CLOSE^ErrCloseLStr) -> 1 -- capture only the string
fragment
OPEN <- '[' {:openEq: EQUALS :} '[' %nl?
fragment
CLOSE <- ']' {EQUALS} ']'
fragment
EQUALS <- '='*
fragment
CLOSEEQ <- (CLOSE =openEq) => equals
INT <- DIGIT+
HEX <- '0' [xX] HEXDIGIT+^ErrDigitHex
FLOAT <- DIGIT+ '.' DIGIT* ExponentPart? /
'.' !'.' DIGIT+^ErrDigitDeci ExponentPart? /
DIGIT+ ExponentPart
HEX_FLOAT <- '0' [xX] HEXDIGIT+ '.' HEXDIGIT* HexExponentPart? /
'0' [xX] '.' HEXDIGIT+ HexExponentPart? /
'0' [xX] HEXDIGIT+^ErrDigitHex HexExponentPart
fragment
ExponentPart <- [eE] [+-]? DIGIT+^ErrDigitExpo
fragment
HexExponentPart <- [pP] [+-]? DIGIT+^ErrDigitExpo
fragment
ESC <- '\' [abfnrtvz"'\] /
'\' %nl /
DECESC /
HEXESC/
UTFESC/
'\' %{ErrEscSeq}
fragment
DECESC <- '\' ( DIGIT DIGIT? / [0-2] DIGIT DIGIT)
fragment
HEXESC <- '\' 'x' (HEXDIGIT HEXDIGIT)^ErrHexEsc
fragment
UTFESC <- '\' 'u' '{'^ErrOBraceUEsc HEXDIGIT+^ErrDigitUEsc '}'^ErrCBraceUEsc
fragment
DIGIT <- [0-9]
fragment
HEXDIGIT <- [0-9a-fA-F]
fragment
COMMENT <- '--' LONGSTRING -> 0 -- skip this
fragment
LINE_COMMENT <- '--' COM_TYPES ( %nl / !.)
fragment
COM_TYPES <- '[' '='* [^[=%nl] [^%nl]* /
'[' '='* /
[^[%nl] [^%nl]* /
''
fragment
SHEBANG <- '#' '!' [^%nl]*
SKIP <- %nl / %s / COMMENT / LINE_COMMENT / SHEBANG
fragment
HELPER <- RESERVED / '(' / ')' -- for sync expression
SYNC <- ((!HELPER !SKIP .)+ / .?) SKIP* -- either sync to reserved keyword or skip characters and consume them
]==],{ equals = equals, fixexp = fixexp, fold = fold })
local errnr = 1
local function err (desc, line, col, sfail, recexp)
print("Syntax error #"..errnr..": "..desc.." at line "..line.."(col "..col..")")
errnr = errnr+1
end
local function parse (input)
errnr = 1
local ast, errs = pg.parse(input,grammar,err)
return ast, errs
end
return {parse=parse}

View file

@ -0,0 +1,55 @@
package.path = package.path .. ";../?.lua"
local pg = require "parser-gen"
local peg = require "peg-parser"
local errs = {errMissingThen = "Missing Then"}
pg.setlabels(errs)
local grammar = pg.compile([[
program <- stmtsequence !.
stmtsequence <- statement (';' statement)*
statement <- ifstmt / repeatstmt / assignstmt / readstmt / writestmt
ifstmt <- 'if' exp 'then'^errMissingThen stmtsequence elsestmt? 'end'
elsestmt <- ('else' stmtsequence)
repeatstmt <- 'repeat' stmtsequence 'until' exp
assignstmt <- IDENTIFIER ':=' exp
readstmt <- 'read' IDENTIFIER
writestmt <- 'write' exp
exp <- simpleexp (COMPARISONOP simpleexp)*
COMPARISONOP <- '<' / '='
simpleexp <- term (ADDOP term)*
ADDOP <- [+-]
term <- factor (MULOP factor)*
MULOP <- [*/]
factor <- '(' exp ')' / NUMBER / IDENTIFIER
NUMBER <- '-'? [0-9]+
KEYWORDS <- 'if' / 'repeat' / 'read' / 'write' / 'then' / 'else' / 'end' / 'until'
RESERVED <- KEYWORDS ![a-zA-Z]
IDENTIFIER <- !RESERVED [a-zA-Z]+
HELPER <- ';' / %nl / %s / KEYWORDS / !.
SYNC <- (!HELPER .)*
]], _, true)
local errors = 0
local function printerror(desc,line,col,sfail,trec)
errors = errors+1
print("Error #"..errors..": "..desc.." on line "..line.."(col "..col..")")
end
local function parse(input)
errors = 0
result, errors = pg.parse(input,grammar,printerror)
return result, errors
end
if arg[1] then
-- argument must be in quotes if it contains spaces
res, errs = parse(arg[1])
peg.print_t(res)
peg.print_r(errs)
end
local ret = {parse=parse}
return ret