From 781fd9653ed0a89dd8f3d8ccfab63e249f1edb07 Mon Sep 17 00:00:00 2001 From: Andre Murbach Maidl Date: Sun, 4 Oct 2015 20:10:05 -0300 Subject: Adding Typed Lua parser --- examples/typedlua/tllexer.lua | 80 +++++++++++++++ examples/typedlua/tlp.lua | 18 ++++ examples/typedlua/tlparser.lua | 228 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 326 insertions(+) create mode 100644 examples/typedlua/tllexer.lua create mode 100644 examples/typedlua/tlp.lua create mode 100644 examples/typedlua/tlparser.lua (limited to 'examples') diff --git a/examples/typedlua/tllexer.lua b/examples/typedlua/tllexer.lua new file mode 100644 index 0000000..bcfa802 --- /dev/null +++ b/examples/typedlua/tllexer.lua @@ -0,0 +1,80 @@ +local tllexer = {} + +local lpeg = require "lpeglabel" +lpeg.locale(lpeg) + +local function setffp (s, i, t) + if not t.ffp or i > t.ffp then + t.ffp = i + end + return false +end + +local function updateffp () + return lpeg.Cmt(lpeg.Carg(1), setffp) +end + +tllexer.Shebang = lpeg.P("#") * (lpeg.P(1) - lpeg.P("\n"))^0 * lpeg.P("\n") + +local Space = lpeg.space^1 + +local Equals = lpeg.P("=")^0 +local Open = "[" * lpeg.Cg(Equals, "init") * "[" * lpeg.P("\n")^-1 +local Close = "]" * lpeg.C(Equals) * "]" +local CloseEQ = lpeg.Cmt(Close * lpeg.Cb("init"), + function (s, i, a, b) return a == b end) + +local LongString = Open * (lpeg.P(1) - CloseEQ)^0 * Close / + function (s, o) return s end + +local Comment = lpeg.P("--") * LongString / + function () return end + + lpeg.P("--") * (lpeg.P(1) - lpeg.P("\n"))^0 + +tllexer.Skip = (Space + Comment)^0 + +local idStart = lpeg.alpha + lpeg.P("_") +local idRest = lpeg.alnum + lpeg.P("_") + +local Keywords = lpeg.P("and") + "break" + "do" + "elseif" + "else" + "end" + + "false" + "for" + "function" + "goto" + "if" + "in" + + "local" + "nil" + "not" + "or" + "repeat" + "return" + + "then" + "true" + "until" + "while" + +tllexer.Reserved = Keywords * -idRest + +local Identifier = idStart * idRest^0 + +tllexer.Name = -tllexer.Reserved * Identifier * -idRest + +function tllexer.token (pat) + return pat * tllexer.Skip + updateffp() * lpeg.P(false) +end + +function tllexer.symb (str) + return tllexer.token(lpeg.P(str)) +end + +function tllexer.kw (str) + return tllexer.token(lpeg.P(str) * -idRest) +end + +local Hex = (lpeg.P("0x") + lpeg.P("0X")) * lpeg.xdigit^1 +local Expo = lpeg.S("eE") * lpeg.S("+-")^-1 * lpeg.digit^1 +local Float = (((lpeg.digit^1 * lpeg.P(".") * lpeg.digit^0) + + (lpeg.P(".") * lpeg.digit^1)) * Expo^-1) + + (lpeg.digit^1 * Expo) +local Int = lpeg.digit^1 + +tllexer.Number = Hex + Float + Int + +local ShortString = lpeg.P('"') * + ((lpeg.P('\\') * lpeg.P(1)) + (lpeg.P(1) - lpeg.P('"')))^0 * + lpeg.P('"') + + lpeg.P("'") * + ((lpeg.P("\\") * lpeg.P(1)) + (lpeg.P(1) - lpeg.P("'")))^0 * + lpeg.P("'") + +tllexer.String = LongString + ShortString + +return tllexer diff --git a/examples/typedlua/tlp.lua b/examples/typedlua/tlp.lua new file mode 100644 index 0000000..4605751 --- /dev/null +++ b/examples/typedlua/tlp.lua @@ -0,0 +1,18 @@ +local tlparser = require "tlparser" + +local function getcontents(filename) + file = assert(io.open(filename, "r")) + contents = file:read("*a") + file:close() + return contents +end + +if #arg ~= 1 then + print ("Usage: lua tlp.lua ") + os.exit(1) +end + +local filename = arg[1] +local subject = getcontents(filename) + +print(tlparser.parse(subject, filename, false, true)) diff --git a/examples/typedlua/tlparser.lua b/examples/typedlua/tlparser.lua new file mode 100644 index 0000000..002e580 --- /dev/null +++ b/examples/typedlua/tlparser.lua @@ -0,0 +1,228 @@ +local tlparser = {} + +local lpeg = require "lpeglabel" +lpeg.locale(lpeg) + +local tllexer = require "tllexer" + +local function chainl1 (pat, sep) + return pat * (sep * pat)^0 +end + +local G = lpeg.P { "TypedLua"; + TypedLua = tllexer.Shebang^-1 * tllexer.Skip * lpeg.V("Chunk") * -1; + -- type language + Type = lpeg.V("NilableType"); + NilableType = lpeg.V("UnionType") * tllexer.symb("?")^-1; + UnionType = lpeg.V("PrimaryType") * (tllexer.symb("|") * lpeg.V("PrimaryType"))^0; + PrimaryType = lpeg.V("LiteralType") + + lpeg.V("BaseType") + + lpeg.V("NilType") + + lpeg.V("ValueType") + + lpeg.V("AnyType") + + lpeg.V("SelfType") + + lpeg.V("FunctionType") + + lpeg.V("TableType") + + lpeg.V("VariableType"); + LiteralType = tllexer.token("false") + + tllexer.token("true") + + tllexer.token(tllexer.Number) + + tllexer.token(tllexer.String); + BaseType = tllexer.token("boolean") + + tllexer.token("number") + + tllexer.token("string") + + tllexer.token("integer"); + NilType = tllexer.token("nil"); + ValueType = tllexer.token("value"); + AnyType = tllexer.token("any"); + SelfType = tllexer.token("self"); + FunctionType = lpeg.V("InputType") * tllexer.symb("->") * lpeg.V("NilableTuple"); + MethodType = lpeg.V("InputType") * tllexer.symb("=>") * lpeg.V("NilableTuple"); + InputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.symb(")"); + NilableTuple = lpeg.V("UnionlistType") * tllexer.symb("?")^-1; + UnionlistType = lpeg.V("OutputType") * (tllexer.symb("|") * lpeg.V("OutputType"))^0; + OutputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.symb(")"); + TupleType = lpeg.V("Type") * (tllexer.symb(",") * lpeg.V("Type"))^0 * tllexer.symb("*")^-1; + TableType = tllexer.symb("{") * lpeg.V("TableTypeBody")^-1 * tllexer.symb("}"); + TableTypeBody = lpeg.V("RecordType") + + lpeg.V("HashType") + + lpeg.V("ArrayType"); + RecordType = lpeg.V("RecordField") * (tllexer.symb(",") * lpeg.V("RecordField"))^0 * + (tllexer.symb(",") * (lpeg.V("HashType") + lpeg.V("ArrayType")))^-1; + RecordField = tllexer.kw("const")^-1 * + lpeg.V("LiteralType") * tllexer.symb(":") * lpeg.V("Type"); + HashType = lpeg.V("KeyType") * tllexer.symb(":") * lpeg.V("FieldType"); + ArrayType = lpeg.V("FieldType"); + KeyType = lpeg.V("BaseType") + lpeg.V("ValueType") + lpeg.V("AnyType"); + FieldType = lpeg.V("Type"); + VariableType = tllexer.token(tllexer.Name); + RetType = lpeg.V("NilableTuple") + + lpeg.V("Type"); + Id = tllexer.token(tllexer.Name); + TypeDecId = (tllexer.kw("const") * lpeg.V("Id")) + + lpeg.V("Id"); + IdList = lpeg.V("TypeDecId") * (tllexer.symb(",") * lpeg.V("TypeDecId"))^0; + IdDec = lpeg.V("IdList") * tllexer.symb(":") * + (lpeg.V("Type") + lpeg.V("MethodType")); + IdDecList = (lpeg.V("IdDec")^1)^-1; + TypeDec = tllexer.token(tllexer.Name) * lpeg.V("IdDecList") * tllexer.kw("end"); + Interface = tllexer.kw("interface") * lpeg.V("TypeDec") + + tllexer.kw("typealias") * tllexer.token(tllexer.Name) * tllexer.symb("=") * lpeg.V("Type"); + -- parser + Chunk = lpeg.V("Block"); + StatList = (tllexer.symb(";") + lpeg.V("Stat"))^0; + Var = lpeg.V("Id"); + TypedId = tllexer.token(tllexer.Name) * (tllexer.symb(":") * lpeg.V("Type"))^-1; + FunctionDef = tllexer.kw("function") * lpeg.V("FuncBody"); + FieldSep = tllexer.symb(",") + tllexer.symb(";"); + Field = ((tllexer.symb("[") * lpeg.V("Expr") * tllexer.symb("]")) + + (tllexer.token(tllexer.Name))) * + tllexer.symb("=") * lpeg.V("Expr") + + lpeg.V("Expr"); + TField = (tllexer.kw("const") * lpeg.V("Field")) + + lpeg.V("Field"); + FieldList = (lpeg.V("TField") * (lpeg.V("FieldSep") * lpeg.V("TField"))^0 * + lpeg.V("FieldSep")^-1)^-1; + Constructor = tllexer.symb("{") * lpeg.V("FieldList") * tllexer.symb("}"); + NameList = lpeg.V("TypedId") * (tllexer.symb(",") * lpeg.V("TypedId"))^0; + ExpList = lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0; + FuncArgs = tllexer.symb("(") * + (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 * + tllexer.symb(")") + + lpeg.V("Constructor") + + tllexer.token(tllexer.String); + OrOp = tllexer.kw("or"); + AndOp = tllexer.kw("and"); + RelOp = tllexer.symb("~=") + + tllexer.symb("==") + + tllexer.symb("<=") + + tllexer.symb(">=") + + tllexer.symb("<") + + tllexer.symb(">"); + BOrOp = tllexer.symb("|"); + BXorOp = tllexer.symb("~"); + BAndOp = tllexer.symb("&"); + ShiftOp = tllexer.symb("<<") + + tllexer.symb(">>"); + ConOp = tllexer.symb(".."); + AddOp = tllexer.symb("+") + + tllexer.symb("-"); + MulOp = tllexer.symb("*") + + tllexer.symb("//") + + tllexer.symb("/") + + tllexer.symb("%"); + UnOp = tllexer.kw("not") + + tllexer.symb("-") + + tllexer.symb("~") + + tllexer.symb("#"); + PowOp = tllexer.symb("^"); + Expr = lpeg.V("SubExpr_1"); + SubExpr_1 = chainl1(lpeg.V("SubExpr_2"), lpeg.V("OrOp")); + SubExpr_2 = chainl1(lpeg.V("SubExpr_3"), lpeg.V("AndOp")); + SubExpr_3 = chainl1(lpeg.V("SubExpr_4"), lpeg.V("RelOp")); + SubExpr_4 = chainl1(lpeg.V("SubExpr_5"), lpeg.V("BOrOp")); + SubExpr_5 = chainl1(lpeg.V("SubExpr_6"), lpeg.V("BXorOp")); + SubExpr_6 = chainl1(lpeg.V("SubExpr_7"), lpeg.V("BAndOp")); + SubExpr_7 = chainl1(lpeg.V("SubExpr_8"), lpeg.V("ShiftOp")); + SubExpr_8 = lpeg.V("SubExpr_9") * lpeg.V("ConOp") * lpeg.V("SubExpr_8") + + lpeg.V("SubExpr_9"); + SubExpr_9 = chainl1(lpeg.V("SubExpr_10"), lpeg.V("AddOp")); + SubExpr_10 = chainl1(lpeg.V("SubExpr_11"), lpeg.V("MulOp")); + SubExpr_11 = lpeg.V("UnOp") * lpeg.V("SubExpr_11") + + lpeg.V("SubExpr_12"); + SubExpr_12 = lpeg.V("SimpleExp") * (lpeg.V("PowOp") * lpeg.V("SubExpr_11"))^-1; + SimpleExp = tllexer.token(tllexer.Number) + + tllexer.token(tllexer.String) + + tllexer.kw("nil") + + tllexer.kw("false") + + tllexer.kw("true") + + tllexer.symb("...") + + lpeg.V("FunctionDef") + + lpeg.V("Constructor") + + lpeg.V("SuffixedExp"); + SuffixedExp = lpeg.V("PrimaryExp") * ( + (tllexer.symb(".") * tllexer.token(tllexer.Name)) / "index" + + (tllexer.symb("[") * lpeg.V("Expr") * tllexer.symb("]")) / "index" + + (tllexer.symb(":") * tllexer.token(tllexer.Name) * lpeg.V("FuncArgs")) / "call" + + lpeg.V("FuncArgs") / "call")^0 / function (...) local l = {...}; return l[#l] end; + PrimaryExp = lpeg.V("Var") / "var" + + tllexer.symb("(") * lpeg.V("Expr") * tllexer.symb(")"); + Block = lpeg.V("StatList") * lpeg.V("RetStat")^-1; + IfStat = tllexer.kw("if") * lpeg.V("Expr") * tllexer.kw("then") * lpeg.V("Block") * + (tllexer.kw("elseif") * lpeg.V("Expr") * tllexer.kw("then") * lpeg.V("Block"))^0 * + (tllexer.kw("else") * lpeg.V("Block"))^-1 * + tllexer.kw("end"); + WhileStat = tllexer.kw("while") * lpeg.V("Expr") * + tllexer.kw("do") * lpeg.V("Block") * tllexer.kw("end"); + DoStat = tllexer.kw("do") * lpeg.V("Block") * tllexer.kw("end"); + ForBody = tllexer.kw("do") * lpeg.V("Block"); + ForNum = lpeg.V("Id") * tllexer.symb("=") * lpeg.V("Expr") * tllexer.symb(",") * + lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^-1 * + lpeg.V("ForBody"); + ForGen = lpeg.V("NameList") * tllexer.kw("in") * + lpeg.V("ExpList") * lpeg.V("ForBody"); + ForStat = tllexer.kw("for") * (lpeg.V("ForNum") + lpeg.V("ForGen")) * tllexer.kw("end"); + RepeatStat = tllexer.kw("repeat") * lpeg.V("Block") * + tllexer.kw("until") * lpeg.V("Expr"); + FuncName = lpeg.V("Id") * (tllexer.symb(".") * + (tllexer.token(tllexer.Name)))^0 * + (tllexer.symb(":") * (tllexer.token(tllexer.Name)))^-1; + ParList = lpeg.V("NameList") * (tllexer.symb(",") * lpeg.V("TypedVarArg"))^-1 + + lpeg.V("TypedVarArg"); + TypedVarArg = tllexer.symb("...") * (tllexer.symb(":") * lpeg.V("Type"))^-1; + FuncBody = tllexer.symb("(") * lpeg.V("ParList")^-1 * tllexer.symb(")") * + (tllexer.symb(":") * lpeg.V("RetType"))^-1 * + lpeg.V("Block") * tllexer.kw("end"); + FuncStat = tllexer.kw("const")^-1 * + tllexer.kw("function") * lpeg.V("FuncName") * lpeg.V("FuncBody"); + LocalFunc = tllexer.kw("function") * + lpeg.V("Id") * lpeg.V("FuncBody"); + LocalAssign = lpeg.V("NameList") * + ((tllexer.symb("=") * lpeg.V("ExpList")))^-1; + LocalStat = tllexer.kw("local") * + (lpeg.V("LocalTypeDec") + lpeg.V("LocalFunc") + lpeg.V("LocalAssign")); + LabelStat = tllexer.symb("::") * tllexer.token(tllexer.Name) * tllexer.symb("::"); + BreakStat = tllexer.kw("break"); + GoToStat = tllexer.kw("goto") * tllexer.token(tllexer.Name); + RetStat = tllexer.kw("return") * + (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 * + tllexer.symb(";")^-1; + TypeDecStat = lpeg.V("Interface"); + LocalTypeDec = lpeg.V("TypeDecStat"); + LVar = (tllexer.kw("const") * lpeg.V("SuffixedExp")) + + lpeg.V("SuffixedExp"); + ExprStat = lpeg.Cmt(lpeg.V("LVar") * lpeg.V("Assignment"), + function (s, i, ...) + local l = {...} + local i = 1 + while l[i] ~= "=" do + local se = l[i] + if se ~= "var" and se ~= "index" then return false end + i = i + 1 + end + return true + end) + + lpeg.Cmt(lpeg.V("SuffixedExp"), + function (s, i, se) + if se ~= "call" then return false end + return true + end); + Assignment = ((tllexer.symb(",") * lpeg.V("LVar"))^1)^-1 * (tllexer.symb("=") / "=") * lpeg.V("ExpList"); + Stat = lpeg.V("IfStat") + lpeg.V("WhileStat") + lpeg.V("DoStat") + lpeg.V("ForStat") + + lpeg.V("RepeatStat") + lpeg.V("FuncStat") + lpeg.V("LocalStat") + + lpeg.V("LabelStat") + lpeg.V("BreakStat") + lpeg.V("GoToStat") + + lpeg.V("TypeDecStat") + lpeg.V("ExprStat"); +} + +function tlparser.parse (subject, filename, strict, integer) + local errorinfo = {} + lpeg.setmaxstack(1000) + local ast, label, _ = lpeg.match(G, subject, nil, errorinfo, strict, integer) + if not ast then + return nil + else + return true + end +end + +return tlparser -- cgit v1.2.3-55-g6feb From 9f277371cfb63082b04b7432c80b80e0e8fd6ddb Mon Sep 17 00:00:00 2001 From: Andre Murbach Maidl Date: Mon, 5 Oct 2015 16:41:59 -0300 Subject: Annotating Typed Lua parser --- examples/typedlua/test.lua | 2569 ++++++++++++++++++++++++++++++++++++++++ examples/typedlua/tlerror.lua | 47 + examples/typedlua/tllexer.lua | 50 +- examples/typedlua/tlp.lua | 4 +- examples/typedlua/tlparser.lua | 139 ++- 5 files changed, 2733 insertions(+), 76 deletions(-) create mode 100755 examples/typedlua/test.lua create mode 100644 examples/typedlua/tlerror.lua (limited to 'examples') diff --git a/examples/typedlua/test.lua b/examples/typedlua/test.lua new file mode 100755 index 0000000..3b99e5c --- /dev/null +++ b/examples/typedlua/test.lua @@ -0,0 +1,2569 @@ +#!/usr/bin/env lua + +local tlparser = require "tlparser" + +-- expected result, result, message, subject +local e, r, m, s + +local filename = "test.lua" + +local function parse (s) + local r, m = tlparser.parse(s,filename,false,false) + if not r then m = m .. "\n" end + return r, m +end + +print("> testing lexer...") + +-- syntax ok + +-- empty files + +s = [=[ +]=] +--[=[ +{ } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +-- testing empty file +]=] +--[=[ +{ } +]=] + +r, m = parse(s) +assert(r == true) + +-- expressions + +s = [=[ +local _nil,_false,_true,_dots = nil,false,true,... +]=] +--[=[ +{ `Local{ { `Id "_nil", `Id "_false", `Id "_true", `Id "_dots" }, { `Nil, `False, `True, `Dots } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- floating points + +s = [=[ +local f1 = 1. +local f2 = 1.1 +]=] +--[=[ +{ `Local{ { `Id "f1" }, { `Number "1.0" } }, `Local{ { `Id "f2" }, { `Number "1.1" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local f1 = 1.e-1 +local f2 = 1.e1 +]=] +--[=[ +{ `Local{ { `Id "f1" }, { `Number "0.1" } }, `Local{ { `Id "f2" }, { `Number "10.0" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local f1 = 1.1e+1 +local f2 = 1.1e1 +]=] +--[=[ +{ `Local{ { `Id "f1" }, { `Number "11.0" } }, `Local{ { `Id "f2" }, { `Number "11.0" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local f1 = .1 +local f2 = .1e1 +]=] +--[=[ +{ `Local{ { `Id "f1" }, { `Number "0.1" } }, `Local{ { `Id "f2" }, { `Number "1.0" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local f1 = 1E1 +local f2 = 1e-1 +]=] +--[=[ +{ `Local{ { `Id "f1" }, { `Number "10.0" } }, `Local{ { `Id "f2" }, { `Number "0.1" } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- integers + +s = [=[ +local i = 1 +local h = 0xff +]=] +--[=[ +{ `Local{ { `Id "i" }, { `Number "1" } }, `Local{ { `Id "h" }, { `Number "255" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local h = 0x76c +local i = 4294967296 -- 2^32 +]=] +--[=[ +{ `Local{ { `Id "h" }, { `Number "1900" } }, `Local{ { `Id "i" }, { `Number "4294967296" } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- long comments + +s = [=[ +--[======[ +testing +long +comment +[==[ one ]==] +[===[ more ]===] +[====[ time ]====] +bye +]======] +]=] +--[=[ +{ } +]=] + +r, m = parse(s) +assert(r == true) + +-- long strings + +s = [=[ +--[[ +testing long string1 begin +]] + +local ls1 = +[[ +testing long string +]] + +--[[ +testing long string1 end +]] +]=] +--[=[ +{ `Local{ { `Id "ls1" }, { `String "testing long string\n" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +--[==[ +testing long string2 begin +]==] + +local ls2 = [==[ testing \n [[ long ]] \t [===[ string ]===] +\a ]==] + +--[==[ +[[ testing long string2 end ]] +]==] +]=] +--[=[ +{ `Local{ { `Id "ls2" }, { `String " testing \\n [[ long ]] \\t [===[ string ]===]\n\\a " } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- short strings + +s = [=[ +-- short string test begin + +local ss1_a = "ola mundo\a" +local ss1_b = 'ola mundo\a' + +-- short string test end +]=] +--[=[ +{ `Local{ { `Id "ss1_a" }, { `String "ola mundo\a" } }, `Local{ { `Id "ss1_b" }, { `String "ola mundo\a" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +-- short string test begin + +local ss2_a = "testando,\tteste\n1\n2\n3 --> \"tchau\"" +local ss2_b = 'testando,\tteste\n1\n2\n3 --> \'tchau\'' + +-- short string test end +]=] +--[=[ +{ `Local{ { `Id "ss2_a" }, { `String "testando,\tteste\n1\n2\n3 --> \"tchau\"" } }, `Local{ { `Id "ss2_b" }, { `String "testando,\tteste\n1\n2\n3 --> 'tchau'" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +-- short string test begin + +local ss3_a = "ola \ +'mundo'!" + +local ss3_b = 'ola \ +"mundo"!' + +-- short string test end +]=] +--[=[ +{ `Local{ { `Id "ss3_a" }, { `String "ola \n'mundo'!" } }, `Local{ { `Id "ss3_b" }, { `String "ola \n\"mundo\"!" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +-- short string test begin + +local ss4_a = "C:\\Temp/" + +local ss4_b = 'C:\\Temp/' + +-- short string test end +]=] +--[=[ +{ `Local{ { `Id "ss4_a" }, { `String "C:\\Temp/" } }, `Local{ { `Id "ss4_b" }, { `String "C:\\Temp/" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +-- short string test begin + +local ss5_a = "ola \ +mundo \\ \ +cruel" + +local ss5_b = 'ola \ +mundo \\ \ +cruel' + +-- short string test end +]=] +--[=[ +{ `Local{ { `Id "ss5_a" }, { `String "ola \nmundo \\ \ncruel" } }, `Local{ { `Id "ss5_b" }, { `String "ola \nmundo \\ \ncruel" } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- syntax error + +-- floating points + +s = [=[ +local f = 9e +]=] +--[=[ +test.lua:2:1: syntax error, unexpected 'EOF', expecting '=', ',', 'String', '{', '(', ':', '[', '.' +]=] +e = [=[ +test.lua:1:11: malformed +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local f = 5.e +]=] +--[=[ +test.lua:2:1: syntax error, unexpected 'EOF', expecting '=', ',', 'String', '{', '(', ':', '[', '.' +]=] +e = [=[ +test.lua:1:11: malformed +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local f = .9e- +]=] +--[=[ +test.lua:1:14: syntax error, unexpected '-', expecting '=', ',', 'String', '{', '(', ':', '[', '.' +]=] +e = [=[ +test.lua:1:11: malformed +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local f = 5.9e+ +]=] +--[=[ +test.lua:1:15: syntax error, unexpected '+', expecting '=', ',', 'String', '{', '(', ':', '[', '.' +]=] +e = [=[ +test.lua:1:11: malformed +]=] + +r, m = parse(s) +assert(m == e) + +-- integers + +s = [=[ +-- invalid hexadecimal number + +local hex = 0xG +]=] +--[=[ +test.lua:4:1: syntax error, unexpected 'EOF', expecting '=', ',', 'String', '{', '(', ':', '[', '.' +]=] +e = [=[ +test.lua:3:13: malformed +]=] + +r, m = parse(s) +assert(m == e) + +-- long strings + +s = [=[ +--[==[ +testing long string3 begin +]==] + +local ls3 = [===[ +testing +unfinised +long string +]==] + +--[==[ +[[ testing long string3 end ]] +]==] +]=] +--[=[ +test.lua:5:13: syntax error, unexpected '[', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] +e = [=[ +test.lua:5:13: unfinished long string +]=] + +r, m = parse(s) +assert(m == e) + +-- short strings + +s = [=[ +-- short string test begin + +local ss6 = "testing unfinished string + +-- short string test end +]=] +--[=[ +test.lua:3:13: syntax error, unexpected '"', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] +e = [=[ +test.lua:3:13: malformed +]=] + +r, m = parse(s) +assert(m == e) + +-- unfinished comments + +s = [=[ +--[[ testing +unfinished +comment +]=] +--[=[ +test.lua:3:1: syntax error, unexpected 'comment', expecting '=', ',', 'String', '{', '(', ':', '[', '.' +]=] +e = [=[ +test.lua:4:1: unfinished long comment +]=] + +r, m = parse(s) +assert(m == e) + +print("> testing parser...") + +-- syntax ok + +-- anonymous functions + +s = [=[ +local a,b,c = function () end +]=] +--[=[ +{ `Local{ { `Id "a", `Id "b", `Id "c" }, { `Function{ { }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local test = function ( a , b , ... ) end +]=] +--[=[ +{ `Local{ { `Id "test" }, { `Function{ { `Id "a", `Id "b", `Dots }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local test = function (...) return ...,0 end +]=] +--[=[ +{ `Local{ { `Id "test" }, { `Function{ { `Dots }, { `Return{ `Dots, `Number "0" } } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- arithmetic expressions + +s = [=[ +local arithmetic = 1 - 2 * 3 + 4 +]=] +--[=[ +{ `Local{ { `Id "arithmetic" }, { `Op{ "add", `Op{ "sub", `Number "1", `Op{ "mul", `Number "2", `Number "3" } }, `Number "4" } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local pow = -3^-2^2 +]=] +--[=[ +{ `Local{ { `Id "pow" }, { `Op{ "unm", `Op{ "pow", `Number "3", `Op{ "unm", `Op{ "pow", `Number "2", `Number "2" } } } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +q, r, f = 3//2, 3%2, 3/2 +]=] +--[=[ +{ `Set{ { `Index{ `Id "_ENV", `String "q" }, `Index{ `Id "_ENV", `String "r" }, `Index{ `Id "_ENV", `String "f" } }, { `Op{ "idiv", `Number "3", `Number "2" }, `Op{ "mod", `Number "3", `Number "2" }, `Op{ "div", `Number "3", `Number "2" } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- assignments + +s = [=[ +a = f()[1] +]=] +--[=[ +{ `Set{ { `Index{ `Id "_ENV", `String "a" } }, { `Index{ `Call{ `Index{ `Id "_ENV", `String "f" } }, `Number "1" } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +a()[1] = 1; +]=] +--[=[ +{ `Set{ { `Index{ `Call{ `Index{ `Id "_ENV", `String "a" } }, `Number "1" } }, { `Number "1" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +i = a.f(1) +]=] +--[=[ +{ `Set{ { `Index{ `Id "_ENV", `String "i" } }, { `Call{ `Index{ `Index{ `Id "_ENV", `String "a" }, `String "f" }, `Number "1" } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +i = a[f(1)] +]=] +--[=[ +{ `Set{ { `Index{ `Id "_ENV", `String "i" } }, { `Index{ `Index{ `Id "_ENV", `String "a" }, `Call{ `Index{ `Id "_ENV", `String "f" }, `Number "1" } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +a[f()] = sub +i = i + 1 +]=] +--[=[ +{ `Set{ { `Index{ `Index{ `Id "_ENV", `String "a" }, `Call{ `Index{ `Id "_ENV", `String "f" } } } }, { `Index{ `Id "_ENV", `String "sub" } } }, `Set{ { `Index{ `Id "_ENV", `String "i" } }, { `Op{ "add", `Index{ `Id "_ENV", `String "i" }, `Number "1" } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +a:b(1)._ = some_value +]=] +--[=[ +{ `Set{ { `Index{ `Invoke{ `Index{ `Id "_ENV", `String "a" }, `String "b", `Number "1" }, `String "_" } }, { `Index{ `Id "_ENV", `String "some_value" } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- bitwise expressions + +s = [=[ +b = 1 & 0 | 1 ~ 1 +]=] +--[=[ +{ `Set{ { `Index{ `Id "_ENV", `String "b" } }, { `Op{ "bor", `Op{ "band", `Number "1", `Number "0" }, `Op{ "bxor", `Number "1", `Number "1" } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +b = 1 & 0 | 1 >> 1 ~ 1 +]=] +--[=[ +{ `Set{ { `Index{ `Id "_ENV", `String "b" } }, { `Op{ "bor", `Op{ "band", `Number "1", `Number "0" }, `Op{ "bxor", `Op{ "shr", `Number "1", `Number "1" }, `Number "1" } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- break + +s = [=[ +while 1 do + break +end +]=] +--[=[ +{ `While{ `Number "1", { `Break } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +while 1 do + while 1 do + break + end + break +end +]=] +--[=[ +{ `While{ `Number "1", { `While{ `Number "1", { `Break } }, `Break } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +repeat + if 2 > 1 then break end +until 1 +]=] +--[=[ +{ `Repeat{ { `If{ `Op{ "lt", `Number "1", `Number "2" }, { `Break } } }, `Number "1" } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +for i=1,10 do + do + break + break + return + end +end +]=] +--[=[ +{ `Fornum{ `Id "i", `Number "1", `Number "10", { `Do{ `Break, `Break, `Return } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- block statements + +s = [=[ +do + local var = 2+2; + return +end +]=] +--[=[ +{ `Do{ `Local{ { `Id "var" }, { `Op{ "add", `Number "2", `Number "2" } } }, `Return } } +]=] + +r, m = parse(s) +assert(r == true) + +-- calls + +s = [=[ +f() +t:m() +]=] +--[=[ +{ `Call{ `Index{ `Id "_ENV", `String "f" } }, `Invoke{ `Index{ `Id "_ENV", `String "t" }, `String "m" } } +]=] + +r, m = parse(s) +assert(r == true) + +-- concatenation expressions + +s = [=[ +local concat1 = 1 .. 2^3 +]=] +--[=[ +{ `Local{ { `Id "concat1" }, { `Op{ "concat", `Number "1", `Op{ "pow", `Number "2", `Number "3" } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- empty files + +s = [=[ +; +]=] +--[=[ +{ } +]=] + +r, m = parse(s) +assert(r == true) + +-- for generic + +s = [=[ +for k,v in pairs(t) do print (k,v) end +]=] +--[=[ +{ `Forin{ { `Id "k", `Id "v" }, { `Call{ `Index{ `Id "_ENV", `String "pairs" }, `Index{ `Id "_ENV", `String "t" } } }, { `Call{ `Index{ `Id "_ENV", `String "print" }, `Id "k", `Id "v" } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- for numeric + +s = [=[ +for i = 1 , 10 , 2 do end +]=] +--[=[ +{ `Fornum{ `Id "i", `Number "1", `Number "10", `Number "2", { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +for i=1,10 do end +]=] +--[=[ +{ `Fornum{ `Id "i", `Number "1", `Number "10", { } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- global functions + +s = [=[ +function test(a , b , ...) end +]=] +--[=[ +{ `Set{ { `Index{ `Id "_ENV", `String "test" } }, { `Function{ { `Id "a", `Id "b", `Dots }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +function test (...) end +]=] +--[=[ +{ `Set{ { `Index{ `Id "_ENV", `String "test" } }, { `Function{ { `Dots }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +function t.a:b() end +]=] +--[=[ +{ `Set{ { `Index{ `Index{ `Index{ `Id "_ENV", `String "t" }, `String "a" }, `String "b" } }, { `Function{ { `Id "self" }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +function t.a() end +]=] +--[=[ +{ `Set{ { `Index{ `Index{ `Id "_ENV", `String "t" }, `String "a" } }, { `Function{ { }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +function testando . funcao . com : espcacos ( e, com , parametros, ... ) end +]=] +--[=[ +{ `Set{ { `Index{ `Index{ `Index{ `Index{ `Id "_ENV", `String "testando" }, `String "funcao" }, `String "com" }, `String "espcacos" } }, { `Function{ { `Id "self", `Id "e", `Id "com", `Id "parametros", `Dots }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- goto + +s = [=[ +goto label +:: label :: return +]=] +--[=[ +{ `Goto{ "label" }, `Label{ "label" }, `Return } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +::label:: +goto label +]=] +--[=[ +{ `Label{ "label" }, `Goto{ "label" } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +goto label +::label:: +]=] +--[=[ +{ `Goto{ "label" }, `Label{ "label" } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +::label:: +do ::label:: goto label end +]=] +--[=[ +{ `Label{ "label" }, `Do{ `Label{ "label" }, `Goto{ "label" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +::label:: +do goto label ; ::label:: end +]=] +--[=[ +{ `Label{ "label" }, `Do{ `Goto{ "label" }, `Label{ "label" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +::label:: +do goto label end +]=] +--[=[ +{ `Label{ "label" }, `Do{ `Goto{ "label" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +do goto label end +::label:: +]=] +--[=[ +{ `Do{ `Goto{ "label" } }, `Label{ "label" } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +do do do do do goto label end end end end end +::label:: +]=] +--[=[ +{ `Do{ `Do{ `Do{ `Do{ `Do{ `Goto{ "label" } } } } } }, `Label{ "label" } } +]=] + +r, m = parse(s) +assert(r == true) + +-- if-else + +s = [=[ +if a then end +]=] +--[=[ +{ `If{ `Index{ `Id "_ENV", `String "a" }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +if a then return a else return end +]=] +--[=[ +{ `If{ `Index{ `Id "_ENV", `String "a" }, { `Return{ `Index{ `Id "_ENV", `String "a" } } }, { `Return } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +if a then + return a +else + local c = d + d = d + 1 + return d +end +]=] +--[=[ +{ `If{ `Index{ `Id "_ENV", `String "a" }, { `Return{ `Index{ `Id "_ENV", `String "a" } } }, { `Local{ { `Id "c" }, { `Index{ `Id "_ENV", `String "d" } } }, `Set{ { `Index{ `Id "_ENV", `String "d" } }, { `Op{ "add", `Index{ `Id "_ENV", `String "d" }, `Number "1" } } }, `Return{ `Index{ `Id "_ENV", `String "d" } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +if a then + return a +elseif b then + return b +elseif c then + return c +end +]=] +--[=[ +{ `If{ `Index{ `Id "_ENV", `String "a" }, { `Return{ `Index{ `Id "_ENV", `String "a" } } }, `Index{ `Id "_ENV", `String "b" }, { `Return{ `Index{ `Id "_ENV", `String "b" } } }, `Index{ `Id "_ENV", `String "c" }, { `Return{ `Index{ `Id "_ENV", `String "c" } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +if a then return a +elseif b then return +else ; +end +]=] +--[=[ +{ `If{ `Index{ `Id "_ENV", `String "a" }, { `Return{ `Index{ `Id "_ENV", `String "a" } } }, `Index{ `Id "_ENV", `String "b" }, { `Return }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +if a then + return +elseif c then +end +]=] +--[=[ +{ `If{ `Index{ `Id "_ENV", `String "a" }, { `Return }, `Index{ `Id "_ENV", `String "c" }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- interfaces + +s = [=[ +local interface Empty end +]=] +--[=[ +{ `Interface{ Empty, `TTable{ } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local interface X + x, y, z:number +end +]=] +--[=[ +{ `Interface{ X, `TTable{ `TLiteral x:`TBase number, `TLiteral y:`TBase number, `TLiteral z:`TBase number } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local interface Person + firstname:string + lastname:string +end +]=] +--[=[ +{ `Interface{ Person, `TTable{ `TLiteral firstname:`TBase string, `TLiteral lastname:`TBase string } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local interface Element + info:number + next:Element? +end +]=] +--[=[ +{ `Interface{ Element, `TRecursive{ Element, `TTable{ `TLiteral info:`TBase number, `TLiteral next:`TUnion{ `TVariable Element, `TNil } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- labels + +s = [=[ +::label:: +do ::label:: end +::other_label:: +]=] +--[=[ +{ `Label{ "label" }, `Do{ `Label{ "label" } }, `Label{ "other_label" } } +]=] + +r, m = parse(s) +assert(r == true) + +-- locals + +s = [=[ +local a +]=] +--[=[ +{ `Local{ { `Id "a" }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local a,b,c +]=] +--[=[ +{ `Local{ { `Id "a", `Id "b", `Id "c" }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local a = 1 , 1 + 2, 5.1 +]=] +--[=[ +{ `Local{ { `Id "a" }, { `Number "1", `Op{ "add", `Number "1", `Number "2" }, `Number "5.1" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local a,b,c = 1.9 +]=] +--[=[ +{ `Local{ { `Id "a", `Id "b", `Id "c" }, { `Number "1.9" } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function test() end +]=] +--[=[ +{ `Localrec{ { `Id "test" }, { `Function{ { }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function test ( a , b , c , ... ) end +]=] +--[=[ +{ `Localrec{ { `Id "test" }, { `Function{ { `Id "a", `Id "b", `Id "c", `Dots }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function test(...) return ... end +]=] +--[=[ +{ `Localrec{ { `Id "test" }, { `Function{ { `Dots }, { `Return{ `Dots } } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- relational expressions + +s = [=[ +local relational = 1 < 2 >= 3 == 4 ~= 5 < 6 <= 7 +]=] +--[=[ +{ `Local{ { `Id "relational" }, { `Op{ "le", `Op{ "lt", `Op{ "not", `Op{ "eq", `Op{ "eq", `Op{ "le", `Number "3", `Op{ "lt", `Number "1", `Number "2" } }, `Number "4" }, `Number "5" } }, `Number "6" }, `Number "7" } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- repeat + +s = [=[ +repeat + local a,b,c = 1+1,2+2,3+3 + break +until a < 1 +]=] +--[=[ +{ `Repeat{ { `Local{ { `Id "a", `Id "b", `Id "c" }, { `Op{ "add", `Number "1", `Number "1" }, `Op{ "add", `Number "2", `Number "2" }, `Op{ "add", `Number "3", `Number "3" } } }, `Break }, `Op{ "lt", `Index{ `Id "_ENV", `String "a" }, `Number "1" } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- return + +s = [=[ +return +]=] +--[=[ +{ `Return } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +return 1 +]=] +--[=[ +{ `Return{ `Number "1" } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +return 1,1-2*3+4,"alo" +]=] +--[=[ +{ `Return{ `Number "1", `Op{ "add", `Op{ "sub", `Number "1", `Op{ "mul", `Number "2", `Number "3" } }, `Number "4" }, `String "alo" } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +return; +]=] +--[=[ +{ `Return } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +return 1; +]=] +--[=[ +{ `Return{ `Number "1" } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +return 1,1-2*3+4,"alo"; +]=] +--[=[ +{ `Return{ `Number "1", `Op{ "add", `Op{ "sub", `Number "1", `Op{ "mul", `Number "2", `Number "3" } }, `Number "4" }, `String "alo" } } +]=] + +r, m = parse(s) +assert(r == true) + +-- tables + +s = [=[ +local t = { [1] = "alo", alo = 1, 2; } +]=] +--[=[ +{ `Local{ { `Id "t" }, { `Table{ `Pair{ `Number "1", `String "alo" }, `Pair{ `String "alo", `Number "1" }, `Number "2" } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local t = { 1.5 } +]=] +--[=[ +{ `Local{ { `Id "t" }, { `Table{ `Number "1.5" } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local t = {1,2; +3, +4, + + + +5} +]=] +--[=[ +{ `Local{ { `Id "t" }, { `Table{ `Number "1", `Number "2", `Number "3", `Number "4", `Number "5" } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local t = {[1]=1,[2]=2; +[3]=3, +[4]=4, + + + +[5]=5} +]=] +--[=[ +{ `Local{ { `Id "t" }, { `Table{ `Pair{ `Number "1", `Number "1" }, `Pair{ `Number "2", `Number "2" }, `Pair{ `Number "3", `Number "3" }, `Pair{ `Number "4", `Number "4" }, `Pair{ `Number "5", `Number "5" } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local t = {{{}}, {"alo"}} +]=] +--[=[ +{ `Local{ { `Id "t" }, { `Table{ `Table{ `Table }, `Table{ `String "alo" } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- vararg + +s = [=[ +local f = function (...) + return ... +end +]=] +--[=[ +{ `Local{ { `Id "f" }, { `Function{ { `Dots }, { `Return{ `Dots } } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local f = function () + local g = function (x, y, ...) + return ...,...,... + end +end +]=] +--[=[ +{ `Local{ { `Id "f" }, { `Function{ { }, { `Local{ { `Id "g" }, { `Function{ { `Id "x", `Id "y", `Dots }, { `Return{ `Dots, `Dots, `Dots } } } } } } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f (x, ...) + return ... +end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x", `Dots }, { `Return{ `Dots } } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local f = function (x, ...) + return ... +end +]=] +--[=[ +{ `Local{ { `Id "f" }, { `Function{ { `Id "x", `Dots }, { `Return{ `Dots } } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- while + +s = [=[ +local i = 0 +while (i < 10) +do + i = i + 1 +end +]=] +--[=[ +{ `Local{ { `Id "i" }, { `Number "0" } }, `While{ `Paren{ `Op{ "lt", `Id "i", `Number "10" } }, { `Set{ { `Id "i" }, { `Op{ "add", `Id "i", `Number "1" } } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- type annotations + +s = [=[ +local x:nil +]=] +--[=[ +{ `Local{ { `Id "x":`TNil }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:false, y:true +]=] +--[=[ +{ `Local{ { `Id "x":`TLiteral false, `Id "y":`TLiteral true }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:1, y:1.1 +]=] +--[=[ +{ `Local{ { `Id "x":`TLiteral 1, `Id "y":`TLiteral 1.1 }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:"hello", y:'world' +]=] +--[=[ +{ `Local{ { `Id "x":`TLiteral hello, `Id "y":`TLiteral world }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:boolean, y:number, z:string +]=] +--[=[ +{ `Local{ { `Id "x":`TBase boolean, `Id "y":`TBase number, `Id "z":`TBase string }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:any +]=] +--[=[ +{ `Local{ { `Id "x":`TAny }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:number? +]=] +--[=[ +{ `Local{ { `Id "x":`TUnion{ `TBase number, `TNil } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:number|nil +]=] +--[=[ +{ `Local{ { `Id "x":`TUnion{ `TBase number, `TNil } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:number|string|nil +]=] +--[=[ +{ `Local{ { `Id "x":`TUnion{ `TBase number, `TBase string, `TNil } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:number|nil|nil|nil|nil +]=] +--[=[ +{ `Local{ { `Id "x":`TUnion{ `TBase number, `TNil } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:number|nil|string|nil|number|boolean|string +]=] +--[=[ +{ `Local{ { `Id "x":`TUnion{ `TNil, `TBase number, `TBase boolean, `TBase string } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:number|string? +]=] +--[=[ +{ `Local{ { `Id "x":`TUnion{ `TBase number, `TBase string, `TNil } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:(number) -> (number) +]=] +--[=[ +{ `Local{ { `Id "x":`TFunction{ `TTuple{ `TBase number, `TVararg{ `TValue } }, `TTuple{ `TBase number, `TVararg{ `TNil } } } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:(value*) -> (nil*) +]=] +--[=[ +{ `Local{ { `Id "x":`TFunction{ `TTuple{ `TVararg{ `TValue } }, `TTuple{ `TVararg{ `TNil } } } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:(number,string,boolean) -> (string,number,boolean) +]=] +--[=[ +{ `Local{ { `Id "x":`TFunction{ `TTuple{ `TBase number, `TBase string, `TBase boolean, `TVararg{ `TValue } }, `TTuple{ `TBase string, `TBase number, `TBase boolean, `TVararg{ `TNil } } } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:(number,string,value*) -> (string,number,nil*) +]=] +--[=[ +{ `Local{ { `Id "x":`TFunction{ `TTuple{ `TBase number, `TBase string, `TVararg{ `TValue } }, `TTuple{ `TBase string, `TBase number, `TVararg{ `TNil } } } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:{} +]=] +--[=[ +{ `Local{ { `Id "x":`TTable{ } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:{{{{{}}}}} +]=] +--[=[ +{ `Local{ { `Id "x":`TTable{ `TBase number:`TUnion{ `TTable{ `TBase number:`TUnion{ `TTable{ `TBase number:`TUnion{ `TTable{ `TBase number:`TUnion{ `TTable{ }, `TNil } }, `TNil } }, `TNil } }, `TNil } } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:{string} +]=] +--[=[ +{ `Local{ { `Id "x":`TTable{ `TBase number:`TUnion{ `TBase string, `TNil } } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:{string:number} +]=] +--[=[ +{ `Local{ { `Id "x":`TTable{ `TBase string:`TUnion{ `TBase number, `TNil } } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:{'firstname':string, 'lastname':string} +]=] +--[=[ +{ `Local{ { `Id "x":`TTable{ `TLiteral firstname:`TBase string, `TLiteral lastname:`TBase string } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:{'tag':string, number:string} +]=] +--[=[ +{ `Local{ { `Id "x":`TTable{ `TLiteral tag:`TBase string, `TBase number:`TUnion{ `TBase string, `TNil } } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local x:{'f':(number) -> (number), 't':{number:number}} +]=] +--[=[ +{ `Local{ { `Id "x":`TTable{ `TLiteral f:`TFunction{ `TTuple{ `TBase number, `TVararg{ `TValue } }, `TTuple{ `TBase number, `TVararg{ `TNil } } }, `TLiteral t:`TTable{ `TBase number:`TUnion{ `TBase number, `TNil } } } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +for k:number, v:string in ipairs({"hello", "world"}) do end +]=] +--[=[ +{ `Forin{ { `Id "k":`TBase number, `Id "v":`TBase string }, { `Call{ `Index{ `Id "_ENV", `String "ipairs" }, `Table{ `String "hello", `String "world" } } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +for k:string, v in pairs({}) do end +]=] +--[=[ +{ `Forin{ { `Id "k":`TBase string, `Id "v" }, { `Call{ `Index{ `Id "_ENV", `String "pairs" }, `Table } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +for k, v:boolean in pairs({}) do end +]=] +--[=[ +{ `Forin{ { `Id "k", `Id "v":`TBase boolean }, { `Call{ `Index{ `Id "_ENV", `String "pairs" }, `Table } }, { } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f (x:any) end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f (x:any):(any) end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny }:`TTuple{ `TAny, `TVararg{ `TNil } }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f (...:any) end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { `Dots:`TAny }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f (x:any, ...:any) end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny, `Dots:`TAny }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f (x, ...:any) end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x", `Dots:`TAny }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f (x:any, ...) end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny, `Dots }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f (x:any, ...:any):(any) end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny, `Dots:`TAny }:`TTuple{ `TAny, `TVararg{ `TNil } }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f (x:(any) -> (any)):((any) -> (any)) end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TFunction{ `TTuple{ `TAny, `TVararg{ `TValue } }, `TTuple{ `TAny, `TVararg{ `TNil } } } }:`TTuple{ `TFunction{ `TTuple{ `TAny, `TVararg{ `TValue } }, `TTuple{ `TAny, `TVararg{ `TNil } } }, `TVararg{ `TNil } }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f (x:(number, number) -> (number, nil*)):(number*) end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TFunction{ `TTuple{ `TBase number, `TBase number, `TVararg{ `TValue } }, `TTuple{ `TBase number, `TVararg{ `TNil } } } }:`TTuple{ `TVararg{ `TBase number } }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f ():(number, nil*) end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { }:`TTuple{ `TBase number, `TVararg{ `TNil } }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f ():number end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { }:`TTuple{ `TBase number, `TVararg{ `TNil } }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f ():number? end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { }:`TTuple{ `TUnion{ `TBase number, `TNil }, `TVararg{ `TNil } }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f ():(number) | (nil,string) end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { }:`TUnionlist{ `TTuple{ `TBase number, `TVararg{ `TNil } }, `TTuple{ `TNil, `TBase string, `TVararg{ `TNil } } }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f ():(number)? end +]=] +--[=[ +{ `Localrec{ { `Id "f" }, { `Function{ { }:`TUnionlist{ `TTuple{ `TBase number, `TVararg{ `TNil } }, `TTuple{ `TNil, `TBase string, `TVararg{ `TNil } } }, { } } } } } +]=] + +r, m = parse(s) +assert(r == true) + +-- syntax error + +-- anonymous functions + +s = [=[ +a = function (a,b,) end +]=] +--[=[ +test.lua:1:19: syntax error, unexpected ')', expecting '...', 'Name' +]=] +e = [=[ +test.lua:1:19: expecting '...' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +a = function (...,a) end +]=] +--[=[ +test.lua:1:18: syntax error, unexpected ',', expecting ')', ':' +]=] +e = [=[ +test.lua:1:18: missing ')' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local a = function (1) end +]=] +--[=[ +test.lua:1:21: syntax error, unexpected '1', expecting ')', '...', 'Name' +]=] +e = [=[ +test.lua:1:21: missing ')' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local test = function ( a , b , c , ... ) +]=] +--[=[ +test.lua:2:1: syntax error, unexpected 'EOF', expecting 'end', 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ':' +]=] +e = [=[ +test.lua:2:1: missing 'end' to close function declaration +]=] + +r, m = parse(s) +assert(m == e) + +-- arithmetic expressions + +s = [=[ +a = 3 / / 2 +]=] +--[=[ +test.lua:1:9: syntax error, unexpected '/', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] +e = [=[ +test.lua:1:9: unexpected '/', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] + +r, m = parse(s) +assert(m == e) + +-- bitwise expressions + +s = [=[ +b = 1 && 1 +]=] +--[=[ +test.lua:1:8: syntax error, unexpected '&', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] +e = [=[ +test.lua:1:8: unexpected '&', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +b = 1 <> 0 +]=] +--[=[ +test.lua:1:8: syntax error, unexpected '>', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] +e = [=[ +test.lua:1:8: unexpected '>', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +b = 1 < < 0 +]=] +--[=[ +test.lua:1:9: syntax error, unexpected '<', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] +e = [=[ +test.lua:1:9: unexpected '<', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] + +r, m = parse(s) +assert(m == e) + +-- concatenation expressions + +s = [=[ +concat2 = 2^3..1 +]=] +--[=[ +test.lua:1:15: syntax error, unexpected '.1', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' +]=] +e = [=[ +test.lua:1:15: unexpected '.1', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' +]=] + +r, m = parse(s) +assert(m == e) + +-- for generic + +s = [=[ +for k;v in pairs(t) do end +]=] +--[=[ +test.lua:1:6: syntax error, unexpected ';', expecting 'in', ',', ':', '=' +]=] +e = [=[ +test.lua:1:6: unexpected ';', expecting 'in', ',', ':', '=' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +for k,v in pairs(t:any) do end +]=] +--[=[ +test.lua:1:23: syntax error, unexpected ')', expecting 'String', '{', '(' +]=] +e = [=[ +test.lua:1:23: expecting '(' for method call +]=] + +r, m = parse(s) +assert(m == e) + +-- for numeric + +s = [=[ +for i=1,10, do end +]=] +--[=[ +test.lua:1:13: syntax error, unexpected 'do', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] +e = [=[ +test.lua:1:13: missing 'do' in for statement +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +for i=1,n:number do end +]=] +--[=[ +test.lua:1:18: syntax error, unexpected 'do', expecting 'String', '{', '(' +]=] +e = [=[ +test.lua:1:18: expecting '(' for method call +]=] + +r, m = parse(s) +assert(m == e) + +-- global functions + +s = [=[ +function func(a,b,c,) end +]=] +--[=[ +test.lua:1:21: syntax error, unexpected ')', expecting '...', 'Name' +]=] +e = [=[ +test.lua:1:21: expecting '...' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +function func(...,a) end +]=] +--[=[ +test.lua:1:18: syntax error, unexpected ',', expecting ')', ':' +]=] +e = [=[ +test.lua:1:18: missing ')' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +function a.b:c:d () end +]=] +--[=[ +test.lua:1:15: syntax error, unexpected ':', expecting '(' +]=] +e = [=[ +test.lua:1:15: unexpected ':', expecting '(' +]=] + +r, m = parse(s) +assert(m == e) + +-- goto + +s = [=[ +:: label :: return +goto label +]=] +--[=[ +test.lua:2:1: syntax error, unexpected 'goto', expecting ';', '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] +e = [=[ +test.lua:2:1: unexpected 'goto', expecting ';', '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] + +r, m = parse(s) +assert(m == e) + +-- if-else + +s = [=[ +if a then +]=] +--[=[ +test.lua:2:1: syntax error, unexpected 'EOF', expecting 'end', 'else', 'elseif', 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';' +]=] +e = [=[ +test.lua:2:1: missing 'end' to close if statement +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +if a then else +]=] +--[=[ +test.lua:2:1: syntax error, unexpected 'EOF', expecting 'end', 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';' +]=] +e = [=[ +test.lua:2:1: missing 'end' to close if statement +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +if a then + return a +elseif b then + return b +elseif + +end +]=] +--[=[ +test.lua:7:1: syntax error, unexpected 'end', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] +e = [=[ +test.lua:7:1: missing 'end' to close if statement +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +if a:any then else end +]=] +--[=[ +test.lua:1:10: syntax error, unexpected 'then', expecting 'String', '{', '(' +]=] +e = [=[ +test.lua:1:10: expecting '(' for method call +]=] + +r, m = parse(s) +assert(m == e) + +-- labels + +s = [=[ +:: blah :: +:: not :: +]=] +--[=[ +test.lua:2:4: syntax error, unexpected 'not', expecting 'Name' +]=] +e = [=[ +test.lua:2:4: expecting after '::' +]=] + +r, m = parse(s) +assert(m == e) + +-- locals + +s = [=[ +local a = +]=] +--[=[ +test.lua:2:1: syntax error, unexpected 'EOF', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] +e = [=[ +test.lua:2:1: expecting expression list after '=' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local function t.a() end +]=] +--[=[ +test.lua:1:17: syntax error, unexpected '.', expecting '(' +]=] +e = [=[ +test.lua:1:17: unexpected '.', expecting '(' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local function test (a,) end +]=] +--[=[ +test.lua:1:24: syntax error, unexpected ')', expecting '...', 'Name' +]=] +e = [=[ +test.lua:1:24: expecting '...' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local function test(...,a) end +]=] +--[=[ +test.lua:1:24: syntax error, unexpected ',', expecting ')', ':' +]=] +e = [=[ +test.lua:1:24: missing ')' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local function (a, b, c, ...) end +]=] +--[=[ +test.lua:1:16: syntax error, unexpected '(', expecting 'Name' +]=] +e = [=[ +test.lua:1:16: unexpected '(', expecting 'Name' +]=] + +r, m = parse(s) +assert(m == e) + +-- repeat + +s = [=[ +repeat + a,b,c = 1+1,2+2,3+3 + break +]=] +--[=[ +test.lua:4:1: syntax error, unexpected 'EOF', expecting 'until', 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';' +]=] +e = [=[ +test.lua:4:1: missing 'until' in repeat statement +]=] + +r, m = parse(s) +assert(m == e) + +-- return + +s = [=[ +return +return 1 +return 1,1-2*3+4,"alo" +return; +return 1; +return 1,1-2*3+4,"alo"; +]=] +--[=[ +test.lua:2:1: syntax error, unexpected 'return', expecting ';', '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] +e = [=[ +test.lua:2:1: unexpected 'return', expecting ';', '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +]=] + +r, m = parse(s) +assert(m == e) + +-- tables + +s = [=[ +t = { , } +]=] +--[=[ +test.lua:1:7: syntax error, unexpected ',', expecting '}', '(', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not', 'Name', '[', 'const' +]=] +e = [=[ +test.lua:1:7: missing '}' +]=] + +r, m = parse(s) +assert(m == e) + +-- while + +s = [=[ +i = 0 +while (i < 10) + i = i + 1 +end +]=] +--[=[ +test.lua:3:3: syntax error, unexpected 'i', expecting 'do', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^', 'String', '{', '(', ':', '[', '.' +]=] +e = [=[ +test.lua:3:3: missing 'do' in while statement +]=] + +r, m = parse(s) +assert(m == e) + +-- type annotations + +s = [=[ +t[x:any] = 1 +]=] +--[=[ +test.lua:1:8: syntax error, unexpected ']', expecting 'String', '{', '(' +]=] +e = [=[ +test.lua:1:8: expecting '(' for method call +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +x:number, y, z:boolean = 1, nil, true +]=] +--[=[ +test.lua:1:9: syntax error, unexpected ',', expecting 'String', '{', '(' +]=] +e = [=[ +test.lua:1:9: expecting '(' for method call +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +x = x:any +]=] +--[=[ +test.lua:2:1: syntax error, unexpected 'EOF', expecting 'String', '{', '(' +]=] +e = [=[ +test.lua:2:1: expecting '(' for method call +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +x = ...:any +]=] +--[=[ +test.lua:1:8: syntax error, unexpected ':', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' +]=] +e = [=[ +test.lua:1:8: unexpected ':', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +f(x:any) +]=] +--[=[ +test.lua:1:8: syntax error, unexpected ')', expecting 'String', '{', '(' +]=] +e = [=[ +test.lua:1:8: expecting '(' for method call +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +f(...:any) +]=] +--[=[ +test.lua:1:6: syntax error, unexpected ':', expecting ')', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' +]=] +e = [=[ +test.lua:1:6: missing ')' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local x:number* +]=] +--[=[ +test.lua:1:15: syntax error, unexpected '*', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ',', '?', '|' +]=] +e = [=[ +test.lua:1:15: unexpected '*', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ',', '?', '|' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local x:number| +]=] +--[=[ +test.lua:2:1: syntax error, unexpected 'EOF', expecting '{', '(', 'Type' +]=] +e = [=[ +test.lua:2:1: expecting after '|' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local x:number?|string? +]=] +--[=[ +test.lua:1:16: syntax error, unexpected '|', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ',' +]=] +e = [=[ +test.lua:1:16: unexpected '|', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ',' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local x:() -> number +]=] +--[=[ +test.lua:1:15: syntax error, unexpected 'number', expecting '(' +]=] +e = [=[ +test.lua:1:15: expecting after '->' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local x:() -> (number)? | (string)? +]=] +--[=[ +test.lua:1:35: syntax error, unexpected '?', expecting '->' +]=] +e = [=[ +test.lua:1:35: expecting after '|' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local x:{()->():string} +]=] +--[=[ +test.lua:1:16: syntax error, unexpected ':', expecting '}', '?', '|' +]=] +e = [=[ +test.lua:1:16: missing '}' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local x:{string:t 1} +]=] +--[=[ +test.lua:1:19: syntax error, unexpected '1', expecting '}', '?', '|' +]=] +e = [=[ +test.lua:1:19: missing '}' +]=] + +r, m = parse(s) +assert(m == e) + +s = [=[ +local x:{{{{{}}}} +]=] +--[=[ +test.lua:2:1: syntax error, unexpected 'EOF', expecting '}', '?', '|' +]=] +e = [=[ +test.lua:2:1: missing '}' +]=] + +r, m = parse(s) +assert(m == e) + +-- syntax errors that depend on some semantic information + +-- break + +s = [=[ +break +]=] +--[=[ +test.lua:1:1: syntax error, not inside a loop +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +function f (x) + if 1 then break end +end +]=] +--[=[ +test.lua:2:13: syntax error, not inside a loop +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +while 1 do +end +break +]=] +--[=[ +test.lua:3:1: syntax error, not inside a loop +]=] + +r, m = parse(s) +assert(r == true) + +-- goto + +s = [=[ +goto label +]=] +--[=[ +test.lua:1:1: syntax error, no visible label 'label' for +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +goto label +::other_label:: +]=] +--[=[ +test.lua:1:1: syntax error, no visible label 'label' for +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +::other_label:: +do do do goto label end end end +]=] +--[=[ +test.lua:2:10: syntax error, no visible label 'label' for +]=] + +r, m = parse(s) +assert(r == true) + +-- interfaces + +s = [=[ +local interface X + x:number + y:number + z:number + x:number +end +]=] +--[=[ +test.lua:1:7: syntax error, attempt to redeclare field 'x' +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local interface X + x, y, z, x:number +end +]=] +--[=[ +test.lua:1:7: syntax error, attempt to redeclare field 'x' +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local interface boolean end +]=] +--[=[ +test.lua:1:7: syntax error, attempt to redeclare type 'boolean' +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local interface number end +]=] +--[=[ +test.lua:1:7: syntax error, attempt to redeclare type 'number' +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local interface string end +]=] +--[=[ +test.lua:1:7: syntax error, attempt to redeclare type 'string' +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local interface value end +]=] +--[=[ +test.lua:1:7: syntax error, attempt to redeclare type 'value' +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local interface any end +]=] +--[=[ +test.lua:1:7: syntax error, attempt to redeclare type 'any' +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local interface self end +]=] +--[=[ +test.lua:1:7: syntax error, attempt to redeclare type 'self' +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local interface const end +]=] +--[=[ +test.lua:1:7: syntax error, attempt to redeclare type 'const' +]=] + +r, m = parse(s) +assert(r == true) + +-- labels + +s = [=[ +::label:: +::other_label:: +::label:: +]=] +--[=[ +test.lua:3:1: syntax error, label 'label' already defined +]=] + +r, m = parse(s) +assert(r == true) + +-- vararg + +s = [=[ +function f () + return ... +end +]=] +--[=[ +test.lua:2:10: syntax error, cannot use '...' outside a vararg function +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +function f () + function g (x, y) + return ...,...,... + end +end +]=] +--[=[ +test.lua:3:12: syntax error, cannot use '...' outside a vararg function +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local function f (x) + return ... +end +]=] +--[=[ +test.lua:2:10: syntax error, cannot use '...' outside a vararg function +]=] + +r, m = parse(s) +assert(r == true) + +s = [=[ +local f = function (x) + return ... +end +]=] +--[=[ +test.lua:2:10: syntax error, cannot use '...' outside a vararg function +]=] + +r, m = parse(s) +assert(r == true) + +print("OK") diff --git a/examples/typedlua/tlerror.lua b/examples/typedlua/tlerror.lua new file mode 100644 index 0000000..fe3a72e --- /dev/null +++ b/examples/typedlua/tlerror.lua @@ -0,0 +1,47 @@ + +local errors = {} +local function new_error (label, msg) + table.insert(errors, { label = label, msg = msg }) +end + +new_error("Number", "malformed ") +new_error("String", "malformed ") +new_error("LongString", "unfinished long string") +new_error("LongComment", "unfinished long comment") +new_error("MissingCP", "missing ')'") +new_error("MissingCC", "missing '}'") +new_error("MissingCB", "missing ']'") +new_error("UnionType", "expecting after '|'") +new_error("FunctionType", "expecting after '->'") +new_error("MethodType", "expecting after '=>'") +new_error("TupleType", "expecting after ','") +new_error("Type", "expecting after ':'") +new_error("TypeDecEnd", "missing 'end' in type declaration") +new_error("TypeAliasName", "expecting after 'typealias'") +new_error("MissingEqTypeAlias", "missing '=' in 'typealias'") +new_error("DotIndex", "expecting after '.'") +new_error("MethodName", "expecting after ':'") +new_error("Then", "missing 'then'") +new_error("IfEnd", "missing 'end' to close if statement") +new_error("WhileDo", "missing 'do' in while statement") +new_error("WhileEnd", "missing 'end' to close while statement") +new_error("BlockEnd", "missing 'end' to close block") +new_error("ForDo", "missing 'do' in for statement") +new_error("ForEnd", "missing 'end' to close for statement") +new_error("Until", "missing 'until' in repeat statement") +new_error("FuncEnd", "missing 'end' to close function declaration") +new_error("ParList", "expecting '...'") +new_error("MethodCall", "expecting '(' for method call") +new_error("Label1", "expecting after '::'") +new_error("Label2", "expecting '::' to close label declaration") +new_error("LocalAssign", "expecting expression list after '='") + +local labels = {} +for k, v in ipairs(errors) do + labels[v.label] = k +end + +return { + errors = errors, + labels = labels, +} diff --git a/examples/typedlua/tllexer.lua b/examples/typedlua/tllexer.lua index bcfa802..2e11377 100644 --- a/examples/typedlua/tllexer.lua +++ b/examples/typedlua/tllexer.lua @@ -3,15 +3,29 @@ local tllexer = {} local lpeg = require "lpeglabel" lpeg.locale(lpeg) -local function setffp (s, i, t) +local tlerror = require "tlerror" + +function tllexer.try (pat, label) + return pat + lpeg.T(tlerror.labels[label]) +end + +local function setffp (s, i, t, n) if not t.ffp or i > t.ffp then t.ffp = i + t.list = {} + t.list[n] = true + t.expected = "'" .. n .. "'" + elseif i == t.ffp then + if not t.list[n] then + t.list[n] = true + t.expected = "'" .. n .. "', " .. t.expected + end end return false end -local function updateffp () - return lpeg.Cmt(lpeg.Carg(1), setffp) +local function updateffp (name) + return lpeg.Cmt(lpeg.Carg(1) * lpeg.Cc(name), setffp) end tllexer.Shebang = lpeg.P("#") * (lpeg.P(1) - lpeg.P("\n"))^0 * lpeg.P("\n") @@ -24,11 +38,11 @@ local Close = "]" * lpeg.C(Equals) * "]" local CloseEQ = lpeg.Cmt(Close * lpeg.Cb("init"), function (s, i, a, b) return a == b end) -local LongString = Open * (lpeg.P(1) - CloseEQ)^0 * Close / +local LongString = Open * (lpeg.P(1) - CloseEQ)^0 * tllexer.try(Close, "LongString") / function (s, o) return s end -local Comment = lpeg.P("--") * LongString / - function () return end + +local Comment = lpeg.Lc(lpeg.P("--") * LongString / function () return end, + lpeg.T(tlerror.labels["LongComment"]), tlerror.labels["LongString"]) + lpeg.P("--") * (lpeg.P(1) - lpeg.P("\n"))^0 tllexer.Skip = (Space + Comment)^0 @@ -47,20 +61,20 @@ local Identifier = idStart * idRest^0 tllexer.Name = -tllexer.Reserved * Identifier * -idRest -function tllexer.token (pat) - return pat * tllexer.Skip + updateffp() * lpeg.P(false) +function tllexer.token (pat, name) + return pat * tllexer.Skip + updateffp(name) * lpeg.P(false) end function tllexer.symb (str) - return tllexer.token(lpeg.P(str)) + return tllexer.token(lpeg.P(str), str) end function tllexer.kw (str) - return tllexer.token(lpeg.P(str) * -idRest) + return tllexer.token(lpeg.P(str) * -idRest, str) end -local Hex = (lpeg.P("0x") + lpeg.P("0X")) * lpeg.xdigit^1 -local Expo = lpeg.S("eE") * lpeg.S("+-")^-1 * lpeg.digit^1 +local Hex = (lpeg.P("0x") + lpeg.P("0X")) * tllexer.try(lpeg.xdigit^1, "Number") +local Expo = lpeg.S("eE") * lpeg.S("+-")^-1 * tllexer.try(lpeg.digit^1, "Number") local Float = (((lpeg.digit^1 * lpeg.P(".") * lpeg.digit^0) + (lpeg.P(".") * lpeg.digit^1)) * Expo^-1) + (lpeg.digit^1 * Expo) @@ -70,11 +84,19 @@ tllexer.Number = Hex + Float + Int local ShortString = lpeg.P('"') * ((lpeg.P('\\') * lpeg.P(1)) + (lpeg.P(1) - lpeg.P('"')))^0 * - lpeg.P('"') + + tllexer.try(lpeg.P('"'), "String") + lpeg.P("'") * ((lpeg.P("\\") * lpeg.P(1)) + (lpeg.P(1) - lpeg.P("'")))^0 * - lpeg.P("'") + tllexer.try(lpeg.P("'"), "String") tllexer.String = LongString + ShortString +-- for error reporting +tllexer.OneWord = tllexer.Name + + tllexer.Number + + tllexer.String + + tllexer.Reserved + + lpeg.P("...") + + lpeg.P(1) + return tllexer diff --git a/examples/typedlua/tlp.lua b/examples/typedlua/tlp.lua index 4605751..2a4a736 100644 --- a/examples/typedlua/tlp.lua +++ b/examples/typedlua/tlp.lua @@ -14,5 +14,7 @@ end local filename = arg[1] local subject = getcontents(filename) +local r, msg = tlparser.parse(subject, filename, false, true) +if not r then print(msg) end -print(tlparser.parse(subject, filename, false, true)) +os.exit(0) diff --git a/examples/typedlua/tlparser.lua b/examples/typedlua/tlparser.lua index 002e580..c8d03ea 100644 --- a/examples/typedlua/tlparser.lua +++ b/examples/typedlua/tlparser.lua @@ -4,8 +4,9 @@ local lpeg = require "lpeglabel" lpeg.locale(lpeg) local tllexer = require "tllexer" +local tlerror = require "tlerror" -local function chainl1 (pat, sep) +local function chainl1 (pat, sep, label) return pat * (sep * pat)^0 end @@ -14,7 +15,7 @@ local G = lpeg.P { "TypedLua"; -- type language Type = lpeg.V("NilableType"); NilableType = lpeg.V("UnionType") * tllexer.symb("?")^-1; - UnionType = lpeg.V("PrimaryType") * (tllexer.symb("|") * lpeg.V("PrimaryType"))^0; + UnionType = lpeg.V("PrimaryType") * (tllexer.symb("|") * tllexer.try(lpeg.V("PrimaryType"), "UnionType"))^0; PrimaryType = lpeg.V("LiteralType") + lpeg.V("BaseType") + lpeg.V("NilType") + @@ -24,73 +25,74 @@ local G = lpeg.P { "TypedLua"; lpeg.V("FunctionType") + lpeg.V("TableType") + lpeg.V("VariableType"); - LiteralType = tllexer.token("false") + - tllexer.token("true") + - tllexer.token(tllexer.Number) + - tllexer.token(tllexer.String); - BaseType = tllexer.token("boolean") + - tllexer.token("number") + - tllexer.token("string") + - tllexer.token("integer"); - NilType = tllexer.token("nil"); - ValueType = tllexer.token("value"); - AnyType = tllexer.token("any"); - SelfType = tllexer.token("self"); - FunctionType = lpeg.V("InputType") * tllexer.symb("->") * lpeg.V("NilableTuple"); - MethodType = lpeg.V("InputType") * tllexer.symb("=>") * lpeg.V("NilableTuple"); - InputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.symb(")"); + LiteralType = tllexer.token("false", "false") + + tllexer.token("true", "true") + + tllexer.token(tllexer.Number, "Number") + + tllexer.token(tllexer.String, "String"); + BaseType = tllexer.token("boolean", "boolean") + + tllexer.token("number", "number") + + tllexer.token("string", "string") + + tllexer.token("integer", "integer"); + NilType = tllexer.token("nil", "nil"); + ValueType = tllexer.token("value", "value"); + AnyType = tllexer.token("any", "any"); + SelfType = tllexer.token("self", "self"); + FunctionType = lpeg.V("InputType") * tllexer.symb("->") * tllexer.try(lpeg.V("NilableTuple"), "FunctionType"); + MethodType = lpeg.V("InputType") * tllexer.symb("=>") * tllexer.try(lpeg.V("NilableTuple"), "MethodType"); + InputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP"); NilableTuple = lpeg.V("UnionlistType") * tllexer.symb("?")^-1; - UnionlistType = lpeg.V("OutputType") * (tllexer.symb("|") * lpeg.V("OutputType"))^0; - OutputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.symb(")"); - TupleType = lpeg.V("Type") * (tllexer.symb(",") * lpeg.V("Type"))^0 * tllexer.symb("*")^-1; - TableType = tllexer.symb("{") * lpeg.V("TableTypeBody")^-1 * tllexer.symb("}"); + UnionlistType = lpeg.V("OutputType") * (tllexer.symb("|") * tllexer.try(lpeg.V("OutputType"), "UnionType"))^0; + OutputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP"); + TupleType = lpeg.V("Type") * (tllexer.symb(",") * tllexer.try(lpeg.V("Type"), "TupleType"))^0 * tllexer.symb("*")^-1; + TableType = tllexer.symb("{") * lpeg.V("TableTypeBody")^-1 * tllexer.try(tllexer.symb("}"), "MissingCC"); TableTypeBody = lpeg.V("RecordType") + lpeg.V("HashType") + lpeg.V("ArrayType"); RecordType = lpeg.V("RecordField") * (tllexer.symb(",") * lpeg.V("RecordField"))^0 * (tllexer.symb(",") * (lpeg.V("HashType") + lpeg.V("ArrayType")))^-1; RecordField = tllexer.kw("const")^-1 * - lpeg.V("LiteralType") * tllexer.symb(":") * lpeg.V("Type"); - HashType = lpeg.V("KeyType") * tllexer.symb(":") * lpeg.V("FieldType"); + lpeg.V("LiteralType") * tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"); + HashType = lpeg.V("KeyType") * tllexer.symb(":") * tllexer.try(lpeg.V("FieldType"), "Type"); ArrayType = lpeg.V("FieldType"); KeyType = lpeg.V("BaseType") + lpeg.V("ValueType") + lpeg.V("AnyType"); FieldType = lpeg.V("Type"); - VariableType = tllexer.token(tllexer.Name); + VariableType = tllexer.token(tllexer.Name, "Name"); RetType = lpeg.V("NilableTuple") + lpeg.V("Type"); - Id = tllexer.token(tllexer.Name); + Id = tllexer.token(tllexer.Name, "Name"); TypeDecId = (tllexer.kw("const") * lpeg.V("Id")) + lpeg.V("Id"); - IdList = lpeg.V("TypeDecId") * (tllexer.symb(",") * lpeg.V("TypeDecId"))^0; - IdDec = lpeg.V("IdList") * tllexer.symb(":") * - (lpeg.V("Type") + lpeg.V("MethodType")); + IdList = lpeg.V("TypeDecId") * (tllexer.symb(",") * tllexer.try(lpeg.V("TypeDecId"), "TupleType"))^0; + IdDec = lpeg.V("IdList") * tllexer.symb(":") * tllexer.try((lpeg.V("Type") + lpeg.V("MethodType")), "Type"); IdDecList = (lpeg.V("IdDec")^1)^-1; - TypeDec = tllexer.token(tllexer.Name) * lpeg.V("IdDecList") * tllexer.kw("end"); + TypeDec = tllexer.token(tllexer.Name, "Name") * lpeg.V("IdDecList") * tllexer.try(tllexer.kw("end"), "TypeDecEnd"); Interface = tllexer.kw("interface") * lpeg.V("TypeDec") + - tllexer.kw("typealias") * tllexer.token(tllexer.Name) * tllexer.symb("=") * lpeg.V("Type"); + tllexer.kw("typealias") * + tllexer.try(tllexer.token(tllexer.Name, "Name"), "TypeAliasName") * + tllexer.try(tllexer.symb("="), "MissingEqTypeAlias") * lpeg.V("Type"); -- parser Chunk = lpeg.V("Block"); StatList = (tllexer.symb(";") + lpeg.V("Stat"))^0; Var = lpeg.V("Id"); - TypedId = tllexer.token(tllexer.Name) * (tllexer.symb(":") * lpeg.V("Type"))^-1; + TypedId = tllexer.token(tllexer.Name, "Name") * (tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"))^-1; FunctionDef = tllexer.kw("function") * lpeg.V("FuncBody"); FieldSep = tllexer.symb(",") + tllexer.symb(";"); - Field = ((tllexer.symb("[") * lpeg.V("Expr") * tllexer.symb("]")) + - (tllexer.token(tllexer.Name))) * + Field = ((tllexer.symb("[") * lpeg.V("Expr") * tllexer.try(tllexer.symb("]"), "MissingCB")) + + (tllexer.token(tllexer.Name, "Name"))) * tllexer.symb("=") * lpeg.V("Expr") + lpeg.V("Expr"); TField = (tllexer.kw("const") * lpeg.V("Field")) + lpeg.V("Field"); FieldList = (lpeg.V("TField") * (lpeg.V("FieldSep") * lpeg.V("TField"))^0 * lpeg.V("FieldSep")^-1)^-1; - Constructor = tllexer.symb("{") * lpeg.V("FieldList") * tllexer.symb("}"); + Constructor = tllexer.symb("{") * lpeg.V("FieldList") * tllexer.try(tllexer.symb("}"), "MissingCC"); NameList = lpeg.V("TypedId") * (tllexer.symb(",") * lpeg.V("TypedId"))^0; ExpList = lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0; FuncArgs = tllexer.symb("(") * (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 * - tllexer.symb(")") + + tllexer.try(tllexer.symb(")"), "MissingCP") + lpeg.V("Constructor") + - tllexer.token(tllexer.String); + tllexer.token(tllexer.String, "String"); OrOp = tllexer.kw("or"); AndOp = tllexer.kw("and"); RelOp = tllexer.symb("~=") + @@ -131,8 +133,8 @@ local G = lpeg.P { "TypedLua"; SubExpr_11 = lpeg.V("UnOp") * lpeg.V("SubExpr_11") + lpeg.V("SubExpr_12"); SubExpr_12 = lpeg.V("SimpleExp") * (lpeg.V("PowOp") * lpeg.V("SubExpr_11"))^-1; - SimpleExp = tllexer.token(tllexer.Number) + - tllexer.token(tllexer.String) + + SimpleExp = tllexer.token(tllexer.Number, "Number") + + tllexer.token(tllexer.String, "String") + tllexer.kw("nil") + tllexer.kw("false") + tllexer.kw("true") + @@ -141,49 +143,49 @@ local G = lpeg.P { "TypedLua"; lpeg.V("Constructor") + lpeg.V("SuffixedExp"); SuffixedExp = lpeg.V("PrimaryExp") * ( - (tllexer.symb(".") * tllexer.token(tllexer.Name)) / "index" + - (tllexer.symb("[") * lpeg.V("Expr") * tllexer.symb("]")) / "index" + - (tllexer.symb(":") * tllexer.token(tllexer.Name) * lpeg.V("FuncArgs")) / "call" + + (tllexer.symb(".") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "DotIndex")) / "index" + + (tllexer.symb("[") * lpeg.V("Expr") * tllexer.try(tllexer.symb("]"), "MissingCB")) / "index" + + (tllexer.symb(":") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "MethodName") * tllexer.try(lpeg.V("FuncArgs"), "MethodCall")) / "call" + lpeg.V("FuncArgs") / "call")^0 / function (...) local l = {...}; return l[#l] end; PrimaryExp = lpeg.V("Var") / "var" + - tllexer.symb("(") * lpeg.V("Expr") * tllexer.symb(")"); + tllexer.symb("(") * lpeg.V("Expr") * tllexer.try(tllexer.symb(")"), "MissingCP"); Block = lpeg.V("StatList") * lpeg.V("RetStat")^-1; - IfStat = tllexer.kw("if") * lpeg.V("Expr") * tllexer.kw("then") * lpeg.V("Block") * - (tllexer.kw("elseif") * lpeg.V("Expr") * tllexer.kw("then") * lpeg.V("Block"))^0 * + IfStat = tllexer.kw("if") * lpeg.V("Expr") * tllexer.try(tllexer.kw("then"), "Then") * lpeg.V("Block") * + (tllexer.kw("elseif") * lpeg.V("Expr") * tllexer.try(tllexer.kw("then"), "Then") * lpeg.V("Block"))^0 * (tllexer.kw("else") * lpeg.V("Block"))^-1 * - tllexer.kw("end"); + tllexer.try(tllexer.kw("end"), "IfEnd"); WhileStat = tllexer.kw("while") * lpeg.V("Expr") * - tllexer.kw("do") * lpeg.V("Block") * tllexer.kw("end"); - DoStat = tllexer.kw("do") * lpeg.V("Block") * tllexer.kw("end"); - ForBody = tllexer.kw("do") * lpeg.V("Block"); + tllexer.try(tllexer.kw("do"), "WhileDo") * lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "WhileEnd"); + DoStat = tllexer.kw("do") * lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "BlockEnd"); + ForBody = tllexer.try(tllexer.kw("do"), "ForDo") * lpeg.V("Block"); ForNum = lpeg.V("Id") * tllexer.symb("=") * lpeg.V("Expr") * tllexer.symb(",") * lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^-1 * lpeg.V("ForBody"); ForGen = lpeg.V("NameList") * tllexer.kw("in") * lpeg.V("ExpList") * lpeg.V("ForBody"); - ForStat = tllexer.kw("for") * (lpeg.V("ForNum") + lpeg.V("ForGen")) * tllexer.kw("end"); + ForStat = tllexer.kw("for") * (lpeg.V("ForNum") + lpeg.V("ForGen")) * tllexer.try(tllexer.kw("end"), "ForEnd"); RepeatStat = tllexer.kw("repeat") * lpeg.V("Block") * - tllexer.kw("until") * lpeg.V("Expr"); + tllexer.try(tllexer.kw("until"), "Until") * lpeg.V("Expr"); FuncName = lpeg.V("Id") * (tllexer.symb(".") * - (tllexer.token(tllexer.Name)))^0 * - (tllexer.symb(":") * (tllexer.token(tllexer.Name)))^-1; - ParList = lpeg.V("NameList") * (tllexer.symb(",") * lpeg.V("TypedVarArg"))^-1 + + (tllexer.token(tllexer.Name, "Name")))^0 * + (tllexer.symb(":") * (tllexer.token(tllexer.Name, "Name")))^-1; + ParList = lpeg.V("NameList") * (tllexer.symb(",") * tllexer.try(lpeg.V("TypedVarArg"), "ParList"))^-1 + lpeg.V("TypedVarArg"); - TypedVarArg = tllexer.symb("...") * (tllexer.symb(":") * lpeg.V("Type"))^-1; - FuncBody = tllexer.symb("(") * lpeg.V("ParList")^-1 * tllexer.symb(")") * - (tllexer.symb(":") * lpeg.V("RetType"))^-1 * - lpeg.V("Block") * tllexer.kw("end"); + TypedVarArg = tllexer.symb("...") * (tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"))^-1; + FuncBody = tllexer.symb("(") * lpeg.V("ParList")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP") * + (tllexer.symb(":") * tllexer.try(lpeg.V("RetType"), "Type"))^-1 * + lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "FuncEnd"); FuncStat = tllexer.kw("const")^-1 * tllexer.kw("function") * lpeg.V("FuncName") * lpeg.V("FuncBody"); LocalFunc = tllexer.kw("function") * lpeg.V("Id") * lpeg.V("FuncBody"); LocalAssign = lpeg.V("NameList") * - ((tllexer.symb("=") * lpeg.V("ExpList")))^-1; + ((tllexer.symb("=") * tllexer.try(lpeg.V("ExpList"), "LocalAssign")))^-1; LocalStat = tllexer.kw("local") * (lpeg.V("LocalTypeDec") + lpeg.V("LocalFunc") + lpeg.V("LocalAssign")); - LabelStat = tllexer.symb("::") * tllexer.token(tllexer.Name) * tllexer.symb("::"); + LabelStat = tllexer.symb("::") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "Label1") * tllexer.try(tllexer.symb("::"), "Label2"); BreakStat = tllexer.kw("break"); - GoToStat = tllexer.kw("goto") * tllexer.token(tllexer.Name); + GoToStat = tllexer.kw("goto") * tllexer.token(tllexer.Name, "Name"); RetStat = tllexer.kw("return") * (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 * tllexer.symb(";")^-1; @@ -214,12 +216,27 @@ local G = lpeg.P { "TypedLua"; lpeg.V("TypeDecStat") + lpeg.V("ExprStat"); } +local function lineno (s, i) + if i == 1 then return 1, 1 end + local rest, num = s:sub(1,i):gsub("[^\n]*\n", "") + local r = #rest + return 1 + num, r ~= 0 and r or 1 +end + function tlparser.parse (subject, filename, strict, integer) local errorinfo = {} lpeg.setmaxstack(1000) local ast, label, _ = lpeg.match(G, subject, nil, errorinfo, strict, integer) if not ast then - return nil + local line, col = lineno(subject, errorinfo.ffp) + local error_msg = string.format("%s:%d:%d: ", filename, line, col) + if label ~= 0 then + error_msg = error_msg .. tlerror.errors[label].msg + else + local u = lpeg.match(lpeg.C(tllexer.OneWord) + lpeg.Cc("EOF"), subject, errorinfo.ffp) + error_msg = error_msg .. string.format("unexpected '%s', expecting %s", u, errorinfo.expected) + end + return nil, error_msg else return true end -- cgit v1.2.3-55-g6feb From e8e389b9ddebe6ced19d5f4bc112b309ffe1a8ff Mon Sep 17 00:00:00 2001 From: Andre Murbach Maidl Date: Wed, 7 Oct 2015 15:17:08 -0300 Subject: Adding some missing annotations due to MAXLABELS limitation to 32 labels --- examples/typedlua/test.lua | 8 ++++---- examples/typedlua/tlerror.lua | 3 +++ examples/typedlua/tlparser.lua | 6 +++--- 3 files changed, 10 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/typedlua/test.lua b/examples/typedlua/test.lua index 3b99e5c..ffdbd70 100755 --- a/examples/typedlua/test.lua +++ b/examples/typedlua/test.lua @@ -1828,7 +1828,7 @@ for k;v in pairs(t) do end test.lua:1:6: syntax error, unexpected ';', expecting 'in', ',', ':', '=' ]=] e = [=[ -test.lua:1:6: unexpected ';', expecting 'in', ',', ':', '=' +test.lua:1:6: expecting 'in' ]=] r, m = parse(s) @@ -1910,7 +1910,7 @@ function a.b:c:d () end test.lua:1:15: syntax error, unexpected ':', expecting '(' ]=] e = [=[ -test.lua:1:15: unexpected ':', expecting '(' +test.lua:1:15: missing '(' ]=] r, m = parse(s) @@ -2030,7 +2030,7 @@ local function t.a() end test.lua:1:17: syntax error, unexpected '.', expecting '(' ]=] e = [=[ -test.lua:1:17: unexpected '.', expecting '(' +test.lua:1:17: missing '(' ]=] r, m = parse(s) @@ -2069,7 +2069,7 @@ local function (a, b, c, ...) end test.lua:1:16: syntax error, unexpected '(', expecting 'Name' ]=] e = [=[ -test.lua:1:16: unexpected '(', expecting 'Name' +test.lua:1:16: expecting in local function declaration ]=] r, m = parse(s) diff --git a/examples/typedlua/tlerror.lua b/examples/typedlua/tlerror.lua index fe3a72e..6881b6b 100644 --- a/examples/typedlua/tlerror.lua +++ b/examples/typedlua/tlerror.lua @@ -8,6 +8,7 @@ new_error("Number", "malformed ") new_error("String", "malformed ") new_error("LongString", "unfinished long string") new_error("LongComment", "unfinished long comment") +new_error("MissingOP", "missing '('") new_error("MissingCP", "missing ')'") new_error("MissingCC", "missing '}'") new_error("MissingCB", "missing ']'") @@ -35,6 +36,8 @@ new_error("MethodCall", "expecting '(' for method call") new_error("Label1", "expecting after '::'") new_error("Label2", "expecting '::' to close label declaration") new_error("LocalAssign", "expecting expression list after '='") +new_error("ForGen", "expecting 'in'") +new_error("LocalFunc", "expecting in local function declaration") local labels = {} for k, v in ipairs(errors) do diff --git a/examples/typedlua/tlparser.lua b/examples/typedlua/tlparser.lua index c8d03ea..2180812 100644 --- a/examples/typedlua/tlparser.lua +++ b/examples/typedlua/tlparser.lua @@ -161,7 +161,7 @@ local G = lpeg.P { "TypedLua"; ForNum = lpeg.V("Id") * tllexer.symb("=") * lpeg.V("Expr") * tllexer.symb(",") * lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^-1 * lpeg.V("ForBody"); - ForGen = lpeg.V("NameList") * tllexer.kw("in") * + ForGen = lpeg.V("NameList") * tllexer.try(tllexer.kw("in"), "ForGen") * lpeg.V("ExpList") * lpeg.V("ForBody"); ForStat = tllexer.kw("for") * (lpeg.V("ForNum") + lpeg.V("ForGen")) * tllexer.try(tllexer.kw("end"), "ForEnd"); RepeatStat = tllexer.kw("repeat") * lpeg.V("Block") * @@ -172,13 +172,13 @@ local G = lpeg.P { "TypedLua"; ParList = lpeg.V("NameList") * (tllexer.symb(",") * tllexer.try(lpeg.V("TypedVarArg"), "ParList"))^-1 + lpeg.V("TypedVarArg"); TypedVarArg = tllexer.symb("...") * (tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"))^-1; - FuncBody = tllexer.symb("(") * lpeg.V("ParList")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP") * + FuncBody = tllexer.try(tllexer.symb("("), "MissingOP") * lpeg.V("ParList")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP") * (tllexer.symb(":") * tllexer.try(lpeg.V("RetType"), "Type"))^-1 * lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "FuncEnd"); FuncStat = tllexer.kw("const")^-1 * tllexer.kw("function") * lpeg.V("FuncName") * lpeg.V("FuncBody"); LocalFunc = tllexer.kw("function") * - lpeg.V("Id") * lpeg.V("FuncBody"); + tllexer.try(lpeg.V("Id"), "LocalFunc") * lpeg.V("FuncBody"); LocalAssign = lpeg.V("NameList") * ((tllexer.symb("=") * tllexer.try(lpeg.V("ExpList"), "LocalAssign")))^-1; LocalStat = tllexer.kw("local") * -- cgit v1.2.3-55-g6feb From a949129c2f3d24c7614093376083082f5beb83da Mon Sep 17 00:00:00 2001 From: Andre Murbach Maidl Date: Wed, 7 Oct 2015 17:39:13 -0300 Subject: Adding labels and messages for malformed expressions --- examples/typedlua/test.lua | 10 +++++----- examples/typedlua/tlerror.lua | 14 ++++++++++++++ examples/typedlua/tlparser.lua | 30 +++++++++++++++--------------- 3 files changed, 34 insertions(+), 20 deletions(-) (limited to 'examples') diff --git a/examples/typedlua/test.lua b/examples/typedlua/test.lua index ffdbd70..aa78856 100755 --- a/examples/typedlua/test.lua +++ b/examples/typedlua/test.lua @@ -1757,7 +1757,7 @@ a = 3 / / 2 test.lua:1:9: syntax error, unexpected '/', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:1:9: unexpected '/', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +test.lua:1:9: malformed multiplication expression ]=] r, m = parse(s) @@ -1772,7 +1772,7 @@ b = 1 && 1 test.lua:1:8: syntax error, unexpected '&', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:1:8: unexpected '&', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +test.lua:1:8: malformed '&' expression ]=] r, m = parse(s) @@ -1785,7 +1785,7 @@ b = 1 <> 0 test.lua:1:8: syntax error, unexpected '>', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:1:8: unexpected '>', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +test.lua:1:8: malformed relational expression ]=] r, m = parse(s) @@ -1798,7 +1798,7 @@ b = 1 < < 0 test.lua:1:9: syntax error, unexpected '<', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:1:9: unexpected '<', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +test.lua:1:9: malformed relational expression ]=] r, m = parse(s) @@ -1973,7 +1973,7 @@ end test.lua:7:1: syntax error, unexpected 'end', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:7:1: missing 'end' to close if statement +test.lua:7:1: expecting after 'elseif' ]=] r, m = parse(s) diff --git a/examples/typedlua/tlerror.lua b/examples/typedlua/tlerror.lua index 6881b6b..c51a53b 100644 --- a/examples/typedlua/tlerror.lua +++ b/examples/typedlua/tlerror.lua @@ -38,6 +38,20 @@ new_error("Label2", "expecting '::' to close label declaration") new_error("LocalAssign", "expecting expression list after '='") new_error("ForGen", "expecting 'in'") new_error("LocalFunc", "expecting in local function declaration") +new_error("Exp", "malformed expression") +new_error("ElseIf", "expecting after 'elseif'") +new_error("SubExpr_1", "malformed 'or' expression") +new_error("SubExpr_2", "malformed 'and' expression") +new_error("SubExpr_3", "malformed relational expression") +new_error("SubExpr_4", "malformed '|' expression") +new_error("SubExpr_5", "malformed '~' expression") +new_error("SubExpr_6", "malformed '&' expression") +new_error("SubExpr_7", "malformed shift expression") +new_error("SubExpr_8", "malformed '..' expression") +new_error("SubExpr_9", "malformed addition expression") +new_error("SubExpr_10", "malformed multiplication expression") +new_error("SubExpr_11", "malformed unary expression") +new_error("SubExpr_12", "malformed '^' expression") local labels = {} for k, v in ipairs(errors) do diff --git a/examples/typedlua/tlparser.lua b/examples/typedlua/tlparser.lua index 2180812..67a06a4 100644 --- a/examples/typedlua/tlparser.lua +++ b/examples/typedlua/tlparser.lua @@ -7,7 +7,7 @@ local tllexer = require "tllexer" local tlerror = require "tlerror" local function chainl1 (pat, sep, label) - return pat * (sep * pat)^0 + return pat * (sep * tllexer.try(pat, label))^0 end local G = lpeg.P { "TypedLua"; @@ -102,7 +102,7 @@ local G = lpeg.P { "TypedLua"; tllexer.symb("<") + tllexer.symb(">"); BOrOp = tllexer.symb("|"); - BXorOp = tllexer.symb("~"); + BXorOp = tllexer.symb("~") * -lpeg.P("="); BAndOp = tllexer.symb("&"); ShiftOp = tllexer.symb("<<") + tllexer.symb(">>"); @@ -119,20 +119,20 @@ local G = lpeg.P { "TypedLua"; tllexer.symb("#"); PowOp = tllexer.symb("^"); Expr = lpeg.V("SubExpr_1"); - SubExpr_1 = chainl1(lpeg.V("SubExpr_2"), lpeg.V("OrOp")); - SubExpr_2 = chainl1(lpeg.V("SubExpr_3"), lpeg.V("AndOp")); - SubExpr_3 = chainl1(lpeg.V("SubExpr_4"), lpeg.V("RelOp")); - SubExpr_4 = chainl1(lpeg.V("SubExpr_5"), lpeg.V("BOrOp")); - SubExpr_5 = chainl1(lpeg.V("SubExpr_6"), lpeg.V("BXorOp")); - SubExpr_6 = chainl1(lpeg.V("SubExpr_7"), lpeg.V("BAndOp")); - SubExpr_7 = chainl1(lpeg.V("SubExpr_8"), lpeg.V("ShiftOp")); - SubExpr_8 = lpeg.V("SubExpr_9") * lpeg.V("ConOp") * lpeg.V("SubExpr_8") + + SubExpr_1 = chainl1(lpeg.V("SubExpr_2"), lpeg.V("OrOp"), "SubExpr_1"); + SubExpr_2 = chainl1(lpeg.V("SubExpr_3"), lpeg.V("AndOp"), "SubExpr_2"); + SubExpr_3 = chainl1(lpeg.V("SubExpr_4"), lpeg.V("RelOp"), "SubExpr_3"); + SubExpr_4 = chainl1(lpeg.V("SubExpr_5"), lpeg.V("BOrOp"), "SubExpr_4"); + SubExpr_5 = chainl1(lpeg.V("SubExpr_6"), lpeg.V("BXorOp"), "SubExpr_5"); + SubExpr_6 = chainl1(lpeg.V("SubExpr_7"), lpeg.V("BAndOp"), "SubExpr_6"); + SubExpr_7 = chainl1(lpeg.V("SubExpr_8"), lpeg.V("ShiftOp"), "SubExpr_7"); + SubExpr_8 = lpeg.V("SubExpr_9") * lpeg.V("ConOp") * tllexer.try(lpeg.V("SubExpr_8"), "SubExpr_8") + lpeg.V("SubExpr_9"); - SubExpr_9 = chainl1(lpeg.V("SubExpr_10"), lpeg.V("AddOp")); - SubExpr_10 = chainl1(lpeg.V("SubExpr_11"), lpeg.V("MulOp")); - SubExpr_11 = lpeg.V("UnOp") * lpeg.V("SubExpr_11") + + SubExpr_9 = chainl1(lpeg.V("SubExpr_10"), lpeg.V("AddOp"), "SubExpr_9"); + SubExpr_10 = chainl1(lpeg.V("SubExpr_11"), lpeg.V("MulOp"), "SubExpr_10"); + SubExpr_11 = lpeg.V("UnOp") * tllexer.try(lpeg.V("SubExpr_11"), "SubExpr_11") + lpeg.V("SubExpr_12"); - SubExpr_12 = lpeg.V("SimpleExp") * (lpeg.V("PowOp") * lpeg.V("SubExpr_11"))^-1; + SubExpr_12 = lpeg.V("SimpleExp") * (lpeg.V("PowOp") * tllexer.try(lpeg.V("SubExpr_11"), "SubExpr_12"))^-1; SimpleExp = tllexer.token(tllexer.Number, "Number") + tllexer.token(tllexer.String, "String") + tllexer.kw("nil") + @@ -151,7 +151,7 @@ local G = lpeg.P { "TypedLua"; tllexer.symb("(") * lpeg.V("Expr") * tllexer.try(tllexer.symb(")"), "MissingCP"); Block = lpeg.V("StatList") * lpeg.V("RetStat")^-1; IfStat = tllexer.kw("if") * lpeg.V("Expr") * tllexer.try(tllexer.kw("then"), "Then") * lpeg.V("Block") * - (tllexer.kw("elseif") * lpeg.V("Expr") * tllexer.try(tllexer.kw("then"), "Then") * lpeg.V("Block"))^0 * + (tllexer.kw("elseif") * tllexer.try(lpeg.V("Expr"), "ElseIf") * tllexer.try(tllexer.kw("then"), "Then") * lpeg.V("Block"))^0 * (tllexer.kw("else") * lpeg.V("Block"))^-1 * tllexer.try(tllexer.kw("end"), "IfEnd"); WhileStat = tllexer.kw("while") * lpeg.V("Expr") * -- cgit v1.2.3-55-g6feb From 779bb8c74418d41344268525c5208f874626dcd2 Mon Sep 17 00:00:00 2001 From: Andre Murbach Maidl Date: Wed, 7 Oct 2015 22:06:28 -0300 Subject: Adding some unusual annotations --- examples/typedlua/test.lua | 12 ++++++------ examples/typedlua/tlerror.lua | 6 ++++-- examples/typedlua/tllexer.lua | 6 +++++- examples/typedlua/tlparser.lua | 8 ++++---- 4 files changed, 19 insertions(+), 13 deletions(-) (limited to 'examples') diff --git a/examples/typedlua/test.lua b/examples/typedlua/test.lua index aa78856..4e173b9 100755 --- a/examples/typedlua/test.lua +++ b/examples/typedlua/test.lua @@ -1813,7 +1813,7 @@ concat2 = 2^3..1 test.lua:1:15: syntax error, unexpected '.1', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' ]=] e = [=[ -test.lua:1:15: unexpected '.1', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' +test.lua:1:13: malformed ]=] r, m = parse(s) @@ -1926,7 +1926,7 @@ goto label test.lua:2:1: syntax error, unexpected 'goto', expecting ';', '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:2:1: unexpected 'goto', expecting ';', '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +test.lua:2:1: invalid statement after 'return' ]=] r, m = parse(s) @@ -2106,7 +2106,7 @@ return 1,1-2*3+4,"alo"; test.lua:2:1: syntax error, unexpected 'return', expecting ';', '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:2:1: unexpected 'return', expecting ';', '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' +test.lua:2:1: invalid statement ]=] r, m = parse(s) @@ -2193,7 +2193,7 @@ x = ...:any test.lua:1:8: syntax error, unexpected ':', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' ]=] e = [=[ -test.lua:1:8: unexpected ':', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' +test.lua:1:8: invalid statement ]=] r, m = parse(s) @@ -2232,7 +2232,7 @@ local x:number* test.lua:1:15: syntax error, unexpected '*', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ',', '?', '|' ]=] e = [=[ -test.lua:1:15: unexpected '*', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ',', '?', '|' +test.lua:1:15: invalid local declaration ]=] r, m = parse(s) @@ -2258,7 +2258,7 @@ local x:number?|string? test.lua:1:16: syntax error, unexpected '|', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ',' ]=] e = [=[ -test.lua:1:16: unexpected '|', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ',' +test.lua:1:16: invalid local declaration ]=] r, m = parse(s) diff --git a/examples/typedlua/tlerror.lua b/examples/typedlua/tlerror.lua index c51a53b..94be024 100644 --- a/examples/typedlua/tlerror.lua +++ b/examples/typedlua/tlerror.lua @@ -35,10 +35,11 @@ new_error("ParList", "expecting '...'") new_error("MethodCall", "expecting '(' for method call") new_error("Label1", "expecting after '::'") new_error("Label2", "expecting '::' to close label declaration") -new_error("LocalAssign", "expecting expression list after '='") +new_error("LocalAssign1", "expecting expression list after '='") +new_error("LocalAssign2", "invalid local declaration") new_error("ForGen", "expecting 'in'") new_error("LocalFunc", "expecting in local function declaration") -new_error("Exp", "malformed expression") +new_error("RetStat", "invalid statement after 'return'") new_error("ElseIf", "expecting after 'elseif'") new_error("SubExpr_1", "malformed 'or' expression") new_error("SubExpr_2", "malformed 'and' expression") @@ -52,6 +53,7 @@ new_error("SubExpr_9", "malformed addition expression") new_error("SubExpr_10", "malformed multiplication expression") new_error("SubExpr_11", "malformed unary expression") new_error("SubExpr_12", "malformed '^' expression") +new_error("Stat", "invalid statement") local labels = {} for k, v in ipairs(errors) do diff --git a/examples/typedlua/tllexer.lua b/examples/typedlua/tllexer.lua index 2e11377..6517ba5 100644 --- a/examples/typedlua/tllexer.lua +++ b/examples/typedlua/tllexer.lua @@ -9,6 +9,10 @@ function tllexer.try (pat, label) return pat + lpeg.T(tlerror.labels[label]) end +function tllexer.catch (pat, label) + return lpeg.Lc(pat, lpeg.P(false), tlerror.labels[label]) +end + local function setffp (s, i, t, n) if not t.ffp or i > t.ffp then t.ffp = i @@ -75,7 +79,7 @@ end local Hex = (lpeg.P("0x") + lpeg.P("0X")) * tllexer.try(lpeg.xdigit^1, "Number") local Expo = lpeg.S("eE") * lpeg.S("+-")^-1 * tllexer.try(lpeg.digit^1, "Number") -local Float = (((lpeg.digit^1 * lpeg.P(".") * lpeg.digit^0) + +local Float = (((lpeg.digit^1 * lpeg.P(".") * lpeg.digit^0 * tllexer.try(-lpeg.P("."), "Number")) + (lpeg.P(".") * lpeg.digit^1)) * Expo^-1) + (lpeg.digit^1 * Expo) local Int = lpeg.digit^1 diff --git a/examples/typedlua/tlparser.lua b/examples/typedlua/tlparser.lua index 67a06a4..dba94f7 100644 --- a/examples/typedlua/tlparser.lua +++ b/examples/typedlua/tlparser.lua @@ -11,7 +11,7 @@ local function chainl1 (pat, sep, label) end local G = lpeg.P { "TypedLua"; - TypedLua = tllexer.Shebang^-1 * tllexer.Skip * lpeg.V("Chunk") * -1; + TypedLua = tllexer.Shebang^-1 * tllexer.Skip * lpeg.V("Chunk") * tllexer.try(-1, "Stat"); -- type language Type = lpeg.V("NilableType"); NilableType = lpeg.V("UnionType") * tllexer.symb("?")^-1; @@ -179,14 +179,14 @@ local G = lpeg.P { "TypedLua"; tllexer.kw("function") * lpeg.V("FuncName") * lpeg.V("FuncBody"); LocalFunc = tllexer.kw("function") * tllexer.try(lpeg.V("Id"), "LocalFunc") * lpeg.V("FuncBody"); - LocalAssign = lpeg.V("NameList") * - ((tllexer.symb("=") * tllexer.try(lpeg.V("ExpList"), "LocalAssign")))^-1; + LocalAssign = lpeg.V("NameList") * tllexer.symb("=") * tllexer.try(lpeg.V("ExpList"), "LocalAssign1") + + lpeg.V("NameList") * (#(-tllexer.symb("=") * (lpeg.V("Stat") + -1)) * lpeg.P(true)) + lpeg.T(tlerror.labels["LocalAssign2"]); LocalStat = tllexer.kw("local") * (lpeg.V("LocalTypeDec") + lpeg.V("LocalFunc") + lpeg.V("LocalAssign")); LabelStat = tllexer.symb("::") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "Label1") * tllexer.try(tllexer.symb("::"), "Label2"); BreakStat = tllexer.kw("break"); GoToStat = tllexer.kw("goto") * tllexer.token(tllexer.Name, "Name"); - RetStat = tllexer.kw("return") * + RetStat = tllexer.kw("return") * tllexer.try(-lpeg.V("Stat"), "RetStat") * (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 * tllexer.symb(";")^-1; TypeDecStat = lpeg.V("Interface"); -- cgit v1.2.3-55-g6feb From 53d28a6ff2ffcd6e3779b0f0bf92b6ae39d924fe Mon Sep 17 00:00:00 2001 From: Andre Murbach Maidl Date: Tue, 13 Oct 2015 16:49:58 -0300 Subject: Fixing Typed Lua parser to use label failure position instead of farthest failure position --- examples/typedlua/test.lua | 84 +++++++++++++++++++++--------------------- examples/typedlua/tlparser.lua | 4 +- 2 files changed, 44 insertions(+), 44 deletions(-) (limited to 'examples') diff --git a/examples/typedlua/test.lua b/examples/typedlua/test.lua index 4e173b9..ed4e7a1 100755 --- a/examples/typedlua/test.lua +++ b/examples/typedlua/test.lua @@ -290,7 +290,7 @@ local f = 9e test.lua:2:1: syntax error, unexpected 'EOF', expecting '=', ',', 'String', '{', '(', ':', '[', '.' ]=] e = [=[ -test.lua:1:11: malformed +test.lua:1:12: malformed ]=] r, m = parse(s) @@ -303,7 +303,7 @@ local f = 5.e test.lua:2:1: syntax error, unexpected 'EOF', expecting '=', ',', 'String', '{', '(', ':', '[', '.' ]=] e = [=[ -test.lua:1:11: malformed +test.lua:1:13: malformed ]=] r, m = parse(s) @@ -316,7 +316,7 @@ local f = .9e- test.lua:1:14: syntax error, unexpected '-', expecting '=', ',', 'String', '{', '(', ':', '[', '.' ]=] e = [=[ -test.lua:1:11: malformed +test.lua:1:14: malformed ]=] r, m = parse(s) @@ -329,7 +329,7 @@ local f = 5.9e+ test.lua:1:15: syntax error, unexpected '+', expecting '=', ',', 'String', '{', '(', ':', '[', '.' ]=] e = [=[ -test.lua:1:11: malformed +test.lua:1:15: malformed ]=] r, m = parse(s) @@ -346,7 +346,7 @@ local hex = 0xG test.lua:4:1: syntax error, unexpected 'EOF', expecting '=', ',', 'String', '{', '(', ':', '[', '.' ]=] e = [=[ -test.lua:3:13: malformed +test.lua:3:14: malformed ]=] r, m = parse(s) @@ -373,7 +373,7 @@ long string test.lua:5:13: syntax error, unexpected '[', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:5:13: unfinished long string +test.lua:14:1: unfinished long string ]=] r, m = parse(s) @@ -392,7 +392,7 @@ local ss6 = "testing unfinished string test.lua:3:13: syntax error, unexpected '"', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:3:13: malformed +test.lua:6:1: malformed ]=] r, m = parse(s) @@ -409,7 +409,7 @@ comment test.lua:3:1: syntax error, unexpected 'comment', expecting '=', ',', 'String', '{', '(', ':', '[', '.' ]=] e = [=[ -test.lua:4:1: unfinished long comment +test.lua:1:1: unfinished long comment ]=] r, m = parse(s) @@ -1703,7 +1703,7 @@ a = function (a,b,) end test.lua:1:19: syntax error, unexpected ')', expecting '...', 'Name' ]=] e = [=[ -test.lua:1:19: expecting '...' +test.lua:1:18: expecting '...' ]=] r, m = parse(s) @@ -1716,7 +1716,7 @@ a = function (...,a) end test.lua:1:18: syntax error, unexpected ',', expecting ')', ':' ]=] e = [=[ -test.lua:1:18: missing ')' +test.lua:1:17: missing ')' ]=] r, m = parse(s) @@ -1729,7 +1729,7 @@ local a = function (1) end test.lua:1:21: syntax error, unexpected '1', expecting ')', '...', 'Name' ]=] e = [=[ -test.lua:1:21: missing ')' +test.lua:1:20: missing ')' ]=] r, m = parse(s) @@ -1757,7 +1757,7 @@ a = 3 / / 2 test.lua:1:9: syntax error, unexpected '/', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:1:9: malformed multiplication expression +test.lua:1:8: malformed multiplication expression ]=] r, m = parse(s) @@ -1772,7 +1772,7 @@ b = 1 && 1 test.lua:1:8: syntax error, unexpected '&', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:1:8: malformed '&' expression +test.lua:1:7: malformed '&' expression ]=] r, m = parse(s) @@ -1785,7 +1785,7 @@ b = 1 <> 0 test.lua:1:8: syntax error, unexpected '>', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:1:8: malformed relational expression +test.lua:1:7: malformed relational expression ]=] r, m = parse(s) @@ -1798,7 +1798,7 @@ b = 1 < < 0 test.lua:1:9: syntax error, unexpected '<', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:1:9: malformed relational expression +test.lua:1:8: malformed relational expression ]=] r, m = parse(s) @@ -1813,7 +1813,7 @@ concat2 = 2^3..1 test.lua:1:15: syntax error, unexpected '.1', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' ]=] e = [=[ -test.lua:1:13: malformed +test.lua:1:14: malformed ]=] r, m = parse(s) @@ -1828,7 +1828,7 @@ for k;v in pairs(t) do end test.lua:1:6: syntax error, unexpected ';', expecting 'in', ',', ':', '=' ]=] e = [=[ -test.lua:1:6: expecting 'in' +test.lua:1:5: expecting 'in' ]=] r, m = parse(s) @@ -1841,7 +1841,7 @@ for k,v in pairs(t:any) do end test.lua:1:23: syntax error, unexpected ')', expecting 'String', '{', '(' ]=] e = [=[ -test.lua:1:23: expecting '(' for method call +test.lua:1:22: expecting '(' for method call ]=] r, m = parse(s) @@ -1856,7 +1856,7 @@ for i=1,10, do end test.lua:1:13: syntax error, unexpected 'do', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' ]=] e = [=[ -test.lua:1:13: missing 'do' in for statement +test.lua:1:10: missing 'do' in for statement ]=] r, m = parse(s) @@ -1869,7 +1869,7 @@ for i=1,n:number do end test.lua:1:18: syntax error, unexpected 'do', expecting 'String', '{', '(' ]=] e = [=[ -test.lua:1:18: expecting '(' for method call +test.lua:1:17: expecting '(' for method call ]=] r, m = parse(s) @@ -1884,7 +1884,7 @@ function func(a,b,c,) end test.lua:1:21: syntax error, unexpected ')', expecting '...', 'Name' ]=] e = [=[ -test.lua:1:21: expecting '...' +test.lua:1:20: expecting '...' ]=] r, m = parse(s) @@ -1897,7 +1897,7 @@ function func(...,a) end test.lua:1:18: syntax error, unexpected ',', expecting ')', ':' ]=] e = [=[ -test.lua:1:18: missing ')' +test.lua:1:17: missing ')' ]=] r, m = parse(s) @@ -1910,7 +1910,7 @@ function a.b:c:d () end test.lua:1:15: syntax error, unexpected ':', expecting '(' ]=] e = [=[ -test.lua:1:15: missing '(' +test.lua:1:14: missing '(' ]=] r, m = parse(s) @@ -1986,7 +1986,7 @@ if a:any then else end test.lua:1:10: syntax error, unexpected 'then', expecting 'String', '{', '(' ]=] e = [=[ -test.lua:1:10: expecting '(' for method call +test.lua:1:9: expecting '(' for method call ]=] r, m = parse(s) @@ -2002,7 +2002,7 @@ s = [=[ test.lua:2:4: syntax error, unexpected 'not', expecting 'Name' ]=] e = [=[ -test.lua:2:4: expecting after '::' +test.lua:2:3: expecting after '::' ]=] r, m = parse(s) @@ -2030,7 +2030,7 @@ local function t.a() end test.lua:1:17: syntax error, unexpected '.', expecting '(' ]=] e = [=[ -test.lua:1:17: missing '(' +test.lua:1:16: missing '(' ]=] r, m = parse(s) @@ -2043,7 +2043,7 @@ local function test (a,) end test.lua:1:24: syntax error, unexpected ')', expecting '...', 'Name' ]=] e = [=[ -test.lua:1:24: expecting '...' +test.lua:1:23: expecting '...' ]=] r, m = parse(s) @@ -2056,7 +2056,7 @@ local function test(...,a) end test.lua:1:24: syntax error, unexpected ',', expecting ')', ':' ]=] e = [=[ -test.lua:1:24: missing ')' +test.lua:1:23: missing ')' ]=] r, m = parse(s) @@ -2069,7 +2069,7 @@ local function (a, b, c, ...) end test.lua:1:16: syntax error, unexpected '(', expecting 'Name' ]=] e = [=[ -test.lua:1:16: expecting in local function declaration +test.lua:1:15: expecting in local function declaration ]=] r, m = parse(s) @@ -2121,7 +2121,7 @@ t = { , } test.lua:1:7: syntax error, unexpected ',', expecting '}', '(', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not', 'Name', '[', 'const' ]=] e = [=[ -test.lua:1:7: missing '}' +test.lua:1:6: missing '}' ]=] r, m = parse(s) @@ -2139,7 +2139,7 @@ end test.lua:3:3: syntax error, unexpected 'i', expecting 'do', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^', 'String', '{', '(', ':', '[', '.' ]=] e = [=[ -test.lua:3:3: missing 'do' in while statement +test.lua:3:2: missing 'do' in while statement ]=] r, m = parse(s) @@ -2154,7 +2154,7 @@ t[x:any] = 1 test.lua:1:8: syntax error, unexpected ']', expecting 'String', '{', '(' ]=] e = [=[ -test.lua:1:8: expecting '(' for method call +test.lua:1:7: expecting '(' for method call ]=] r, m = parse(s) @@ -2167,7 +2167,7 @@ x:number, y, z:boolean = 1, nil, true test.lua:1:9: syntax error, unexpected ',', expecting 'String', '{', '(' ]=] e = [=[ -test.lua:1:9: expecting '(' for method call +test.lua:1:8: expecting '(' for method call ]=] r, m = parse(s) @@ -2193,7 +2193,7 @@ x = ...:any test.lua:1:8: syntax error, unexpected ':', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' ]=] e = [=[ -test.lua:1:8: invalid statement +test.lua:1:7: invalid statement ]=] r, m = parse(s) @@ -2206,7 +2206,7 @@ f(x:any) test.lua:1:8: syntax error, unexpected ')', expecting 'String', '{', '(' ]=] e = [=[ -test.lua:1:8: expecting '(' for method call +test.lua:1:7: expecting '(' for method call ]=] r, m = parse(s) @@ -2219,7 +2219,7 @@ f(...:any) test.lua:1:6: syntax error, unexpected ':', expecting ')', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' ]=] e = [=[ -test.lua:1:6: missing ')' +test.lua:1:5: missing ')' ]=] r, m = parse(s) @@ -2232,7 +2232,7 @@ local x:number* test.lua:1:15: syntax error, unexpected '*', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ',', '?', '|' ]=] e = [=[ -test.lua:1:15: invalid local declaration +test.lua:1:6: invalid local declaration ]=] r, m = parse(s) @@ -2258,7 +2258,7 @@ local x:number?|string? test.lua:1:16: syntax error, unexpected '|', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ',' ]=] e = [=[ -test.lua:1:16: invalid local declaration +test.lua:1:6: invalid local declaration ]=] r, m = parse(s) @@ -2271,7 +2271,7 @@ local x:() -> number test.lua:1:15: syntax error, unexpected 'number', expecting '(' ]=] e = [=[ -test.lua:1:15: expecting after '->' +test.lua:1:14: expecting after '->' ]=] r, m = parse(s) @@ -2284,7 +2284,7 @@ local x:() -> (number)? | (string)? test.lua:1:35: syntax error, unexpected '?', expecting '->' ]=] e = [=[ -test.lua:1:35: expecting after '|' +test.lua:1:26: expecting after '|' ]=] r, m = parse(s) @@ -2297,7 +2297,7 @@ local x:{()->():string} test.lua:1:16: syntax error, unexpected ':', expecting '}', '?', '|' ]=] e = [=[ -test.lua:1:16: missing '}' +test.lua:1:15: missing '}' ]=] r, m = parse(s) @@ -2310,7 +2310,7 @@ local x:{string:t 1} test.lua:1:19: syntax error, unexpected '1', expecting '}', '?', '|' ]=] e = [=[ -test.lua:1:19: missing '}' +test.lua:1:18: missing '}' ]=] r, m = parse(s) diff --git a/examples/typedlua/tlparser.lua b/examples/typedlua/tlparser.lua index dba94f7..a301fa6 100644 --- a/examples/typedlua/tlparser.lua +++ b/examples/typedlua/tlparser.lua @@ -226,9 +226,9 @@ end function tlparser.parse (subject, filename, strict, integer) local errorinfo = {} lpeg.setmaxstack(1000) - local ast, label, _ = lpeg.match(G, subject, nil, errorinfo, strict, integer) + local ast, label, suffix = lpeg.match(G, subject, nil, errorinfo, strict, integer) if not ast then - local line, col = lineno(subject, errorinfo.ffp) + local line, col = lineno(subject, string.len(subject) - string.len(suffix)) local error_msg = string.format("%s:%d:%d: ", filename, line, col) if label ~= 0 then error_msg = error_msg .. tlerror.errors[label].msg -- cgit v1.2.3-55-g6feb