diff options
Diffstat (limited to 'examples/typedlua/tlparser.lua')
-rw-r--r-- | examples/typedlua/tlparser.lua | 139 |
1 files changed, 78 insertions, 61 deletions
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" | |||
4 | lpeg.locale(lpeg) | 4 | lpeg.locale(lpeg) |
5 | 5 | ||
6 | local tllexer = require "tllexer" | 6 | local tllexer = require "tllexer" |
7 | local tlerror = require "tlerror" | ||
7 | 8 | ||
8 | local function chainl1 (pat, sep) | 9 | local function chainl1 (pat, sep, label) |
9 | return pat * (sep * pat)^0 | 10 | return pat * (sep * pat)^0 |
10 | end | 11 | end |
11 | 12 | ||
@@ -14,7 +15,7 @@ local G = lpeg.P { "TypedLua"; | |||
14 | -- type language | 15 | -- type language |
15 | Type = lpeg.V("NilableType"); | 16 | Type = lpeg.V("NilableType"); |
16 | NilableType = lpeg.V("UnionType") * tllexer.symb("?")^-1; | 17 | NilableType = lpeg.V("UnionType") * tllexer.symb("?")^-1; |
17 | UnionType = lpeg.V("PrimaryType") * (tllexer.symb("|") * lpeg.V("PrimaryType"))^0; | 18 | UnionType = lpeg.V("PrimaryType") * (tllexer.symb("|") * tllexer.try(lpeg.V("PrimaryType"), "UnionType"))^0; |
18 | PrimaryType = lpeg.V("LiteralType") + | 19 | PrimaryType = lpeg.V("LiteralType") + |
19 | lpeg.V("BaseType") + | 20 | lpeg.V("BaseType") + |
20 | lpeg.V("NilType") + | 21 | lpeg.V("NilType") + |
@@ -24,73 +25,74 @@ local G = lpeg.P { "TypedLua"; | |||
24 | lpeg.V("FunctionType") + | 25 | lpeg.V("FunctionType") + |
25 | lpeg.V("TableType") + | 26 | lpeg.V("TableType") + |
26 | lpeg.V("VariableType"); | 27 | lpeg.V("VariableType"); |
27 | LiteralType = tllexer.token("false") + | 28 | LiteralType = tllexer.token("false", "false") + |
28 | tllexer.token("true") + | 29 | tllexer.token("true", "true") + |
29 | tllexer.token(tllexer.Number) + | 30 | tllexer.token(tllexer.Number, "Number") + |
30 | tllexer.token(tllexer.String); | 31 | tllexer.token(tllexer.String, "String"); |
31 | BaseType = tllexer.token("boolean") + | 32 | BaseType = tllexer.token("boolean", "boolean") + |
32 | tllexer.token("number") + | 33 | tllexer.token("number", "number") + |
33 | tllexer.token("string") + | 34 | tllexer.token("string", "string") + |
34 | tllexer.token("integer"); | 35 | tllexer.token("integer", "integer"); |
35 | NilType = tllexer.token("nil"); | 36 | NilType = tllexer.token("nil", "nil"); |
36 | ValueType = tllexer.token("value"); | 37 | ValueType = tllexer.token("value", "value"); |
37 | AnyType = tllexer.token("any"); | 38 | AnyType = tllexer.token("any", "any"); |
38 | SelfType = tllexer.token("self"); | 39 | SelfType = tllexer.token("self", "self"); |
39 | FunctionType = lpeg.V("InputType") * tllexer.symb("->") * lpeg.V("NilableTuple"); | 40 | FunctionType = lpeg.V("InputType") * tllexer.symb("->") * tllexer.try(lpeg.V("NilableTuple"), "FunctionType"); |
40 | MethodType = lpeg.V("InputType") * tllexer.symb("=>") * lpeg.V("NilableTuple"); | 41 | MethodType = lpeg.V("InputType") * tllexer.symb("=>") * tllexer.try(lpeg.V("NilableTuple"), "MethodType"); |
41 | InputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.symb(")"); | 42 | InputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP"); |
42 | NilableTuple = lpeg.V("UnionlistType") * tllexer.symb("?")^-1; | 43 | NilableTuple = lpeg.V("UnionlistType") * tllexer.symb("?")^-1; |
43 | UnionlistType = lpeg.V("OutputType") * (tllexer.symb("|") * lpeg.V("OutputType"))^0; | 44 | UnionlistType = lpeg.V("OutputType") * (tllexer.symb("|") * tllexer.try(lpeg.V("OutputType"), "UnionType"))^0; |
44 | OutputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.symb(")"); | 45 | OutputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP"); |
45 | TupleType = lpeg.V("Type") * (tllexer.symb(",") * lpeg.V("Type"))^0 * tllexer.symb("*")^-1; | 46 | TupleType = lpeg.V("Type") * (tllexer.symb(",") * tllexer.try(lpeg.V("Type"), "TupleType"))^0 * tllexer.symb("*")^-1; |
46 | TableType = tllexer.symb("{") * lpeg.V("TableTypeBody")^-1 * tllexer.symb("}"); | 47 | TableType = tllexer.symb("{") * lpeg.V("TableTypeBody")^-1 * tllexer.try(tllexer.symb("}"), "MissingCC"); |
47 | TableTypeBody = lpeg.V("RecordType") + | 48 | TableTypeBody = lpeg.V("RecordType") + |
48 | lpeg.V("HashType") + | 49 | lpeg.V("HashType") + |
49 | lpeg.V("ArrayType"); | 50 | lpeg.V("ArrayType"); |
50 | RecordType = lpeg.V("RecordField") * (tllexer.symb(",") * lpeg.V("RecordField"))^0 * | 51 | RecordType = lpeg.V("RecordField") * (tllexer.symb(",") * lpeg.V("RecordField"))^0 * |
51 | (tllexer.symb(",") * (lpeg.V("HashType") + lpeg.V("ArrayType")))^-1; | 52 | (tllexer.symb(",") * (lpeg.V("HashType") + lpeg.V("ArrayType")))^-1; |
52 | RecordField = tllexer.kw("const")^-1 * | 53 | RecordField = tllexer.kw("const")^-1 * |
53 | lpeg.V("LiteralType") * tllexer.symb(":") * lpeg.V("Type"); | 54 | lpeg.V("LiteralType") * tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"); |
54 | HashType = lpeg.V("KeyType") * tllexer.symb(":") * lpeg.V("FieldType"); | 55 | HashType = lpeg.V("KeyType") * tllexer.symb(":") * tllexer.try(lpeg.V("FieldType"), "Type"); |
55 | ArrayType = lpeg.V("FieldType"); | 56 | ArrayType = lpeg.V("FieldType"); |
56 | KeyType = lpeg.V("BaseType") + lpeg.V("ValueType") + lpeg.V("AnyType"); | 57 | KeyType = lpeg.V("BaseType") + lpeg.V("ValueType") + lpeg.V("AnyType"); |
57 | FieldType = lpeg.V("Type"); | 58 | FieldType = lpeg.V("Type"); |
58 | VariableType = tllexer.token(tllexer.Name); | 59 | VariableType = tllexer.token(tllexer.Name, "Name"); |
59 | RetType = lpeg.V("NilableTuple") + | 60 | RetType = lpeg.V("NilableTuple") + |
60 | lpeg.V("Type"); | 61 | lpeg.V("Type"); |
61 | Id = tllexer.token(tllexer.Name); | 62 | Id = tllexer.token(tllexer.Name, "Name"); |
62 | TypeDecId = (tllexer.kw("const") * lpeg.V("Id")) + | 63 | TypeDecId = (tllexer.kw("const") * lpeg.V("Id")) + |
63 | lpeg.V("Id"); | 64 | lpeg.V("Id"); |
64 | IdList = lpeg.V("TypeDecId") * (tllexer.symb(",") * lpeg.V("TypeDecId"))^0; | 65 | IdList = lpeg.V("TypeDecId") * (tllexer.symb(",") * tllexer.try(lpeg.V("TypeDecId"), "TupleType"))^0; |
65 | IdDec = lpeg.V("IdList") * tllexer.symb(":") * | 66 | IdDec = lpeg.V("IdList") * tllexer.symb(":") * tllexer.try((lpeg.V("Type") + lpeg.V("MethodType")), "Type"); |
66 | (lpeg.V("Type") + lpeg.V("MethodType")); | ||
67 | IdDecList = (lpeg.V("IdDec")^1)^-1; | 67 | IdDecList = (lpeg.V("IdDec")^1)^-1; |
68 | TypeDec = tllexer.token(tllexer.Name) * lpeg.V("IdDecList") * tllexer.kw("end"); | 68 | TypeDec = tllexer.token(tllexer.Name, "Name") * lpeg.V("IdDecList") * tllexer.try(tllexer.kw("end"), "TypeDecEnd"); |
69 | Interface = tllexer.kw("interface") * lpeg.V("TypeDec") + | 69 | Interface = tllexer.kw("interface") * lpeg.V("TypeDec") + |
70 | tllexer.kw("typealias") * tllexer.token(tllexer.Name) * tllexer.symb("=") * lpeg.V("Type"); | 70 | tllexer.kw("typealias") * |
71 | tllexer.try(tllexer.token(tllexer.Name, "Name"), "TypeAliasName") * | ||
72 | tllexer.try(tllexer.symb("="), "MissingEqTypeAlias") * lpeg.V("Type"); | ||
71 | -- parser | 73 | -- parser |
72 | Chunk = lpeg.V("Block"); | 74 | Chunk = lpeg.V("Block"); |
73 | StatList = (tllexer.symb(";") + lpeg.V("Stat"))^0; | 75 | StatList = (tllexer.symb(";") + lpeg.V("Stat"))^0; |
74 | Var = lpeg.V("Id"); | 76 | Var = lpeg.V("Id"); |
75 | TypedId = tllexer.token(tllexer.Name) * (tllexer.symb(":") * lpeg.V("Type"))^-1; | 77 | TypedId = tllexer.token(tllexer.Name, "Name") * (tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"))^-1; |
76 | FunctionDef = tllexer.kw("function") * lpeg.V("FuncBody"); | 78 | FunctionDef = tllexer.kw("function") * lpeg.V("FuncBody"); |
77 | FieldSep = tllexer.symb(",") + tllexer.symb(";"); | 79 | FieldSep = tllexer.symb(",") + tllexer.symb(";"); |
78 | Field = ((tllexer.symb("[") * lpeg.V("Expr") * tllexer.symb("]")) + | 80 | Field = ((tllexer.symb("[") * lpeg.V("Expr") * tllexer.try(tllexer.symb("]"), "MissingCB")) + |
79 | (tllexer.token(tllexer.Name))) * | 81 | (tllexer.token(tllexer.Name, "Name"))) * |
80 | tllexer.symb("=") * lpeg.V("Expr") + | 82 | tllexer.symb("=") * lpeg.V("Expr") + |
81 | lpeg.V("Expr"); | 83 | lpeg.V("Expr"); |
82 | TField = (tllexer.kw("const") * lpeg.V("Field")) + | 84 | TField = (tllexer.kw("const") * lpeg.V("Field")) + |
83 | lpeg.V("Field"); | 85 | lpeg.V("Field"); |
84 | FieldList = (lpeg.V("TField") * (lpeg.V("FieldSep") * lpeg.V("TField"))^0 * | 86 | FieldList = (lpeg.V("TField") * (lpeg.V("FieldSep") * lpeg.V("TField"))^0 * |
85 | lpeg.V("FieldSep")^-1)^-1; | 87 | lpeg.V("FieldSep")^-1)^-1; |
86 | Constructor = tllexer.symb("{") * lpeg.V("FieldList") * tllexer.symb("}"); | 88 | Constructor = tllexer.symb("{") * lpeg.V("FieldList") * tllexer.try(tllexer.symb("}"), "MissingCC"); |
87 | NameList = lpeg.V("TypedId") * (tllexer.symb(",") * lpeg.V("TypedId"))^0; | 89 | NameList = lpeg.V("TypedId") * (tllexer.symb(",") * lpeg.V("TypedId"))^0; |
88 | ExpList = lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0; | 90 | ExpList = lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0; |
89 | FuncArgs = tllexer.symb("(") * | 91 | FuncArgs = tllexer.symb("(") * |
90 | (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 * | 92 | (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 * |
91 | tllexer.symb(")") + | 93 | tllexer.try(tllexer.symb(")"), "MissingCP") + |
92 | lpeg.V("Constructor") + | 94 | lpeg.V("Constructor") + |
93 | tllexer.token(tllexer.String); | 95 | tllexer.token(tllexer.String, "String"); |
94 | OrOp = tllexer.kw("or"); | 96 | OrOp = tllexer.kw("or"); |
95 | AndOp = tllexer.kw("and"); | 97 | AndOp = tllexer.kw("and"); |
96 | RelOp = tllexer.symb("~=") + | 98 | RelOp = tllexer.symb("~=") + |
@@ -131,8 +133,8 @@ local G = lpeg.P { "TypedLua"; | |||
131 | SubExpr_11 = lpeg.V("UnOp") * lpeg.V("SubExpr_11") + | 133 | SubExpr_11 = lpeg.V("UnOp") * lpeg.V("SubExpr_11") + |
132 | lpeg.V("SubExpr_12"); | 134 | lpeg.V("SubExpr_12"); |
133 | SubExpr_12 = lpeg.V("SimpleExp") * (lpeg.V("PowOp") * lpeg.V("SubExpr_11"))^-1; | 135 | SubExpr_12 = lpeg.V("SimpleExp") * (lpeg.V("PowOp") * lpeg.V("SubExpr_11"))^-1; |
134 | SimpleExp = tllexer.token(tllexer.Number) + | 136 | SimpleExp = tllexer.token(tllexer.Number, "Number") + |
135 | tllexer.token(tllexer.String) + | 137 | tllexer.token(tllexer.String, "String") + |
136 | tllexer.kw("nil") + | 138 | tllexer.kw("nil") + |
137 | tllexer.kw("false") + | 139 | tllexer.kw("false") + |
138 | tllexer.kw("true") + | 140 | tllexer.kw("true") + |
@@ -141,49 +143,49 @@ local G = lpeg.P { "TypedLua"; | |||
141 | lpeg.V("Constructor") + | 143 | lpeg.V("Constructor") + |
142 | lpeg.V("SuffixedExp"); | 144 | lpeg.V("SuffixedExp"); |
143 | SuffixedExp = lpeg.V("PrimaryExp") * ( | 145 | SuffixedExp = lpeg.V("PrimaryExp") * ( |
144 | (tllexer.symb(".") * tllexer.token(tllexer.Name)) / "index" + | 146 | (tllexer.symb(".") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "DotIndex")) / "index" + |
145 | (tllexer.symb("[") * lpeg.V("Expr") * tllexer.symb("]")) / "index" + | 147 | (tllexer.symb("[") * lpeg.V("Expr") * tllexer.try(tllexer.symb("]"), "MissingCB")) / "index" + |
146 | (tllexer.symb(":") * tllexer.token(tllexer.Name) * lpeg.V("FuncArgs")) / "call" + | 148 | (tllexer.symb(":") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "MethodName") * tllexer.try(lpeg.V("FuncArgs"), "MethodCall")) / "call" + |
147 | lpeg.V("FuncArgs") / "call")^0 / function (...) local l = {...}; return l[#l] end; | 149 | lpeg.V("FuncArgs") / "call")^0 / function (...) local l = {...}; return l[#l] end; |
148 | PrimaryExp = lpeg.V("Var") / "var" + | 150 | PrimaryExp = lpeg.V("Var") / "var" + |
149 | tllexer.symb("(") * lpeg.V("Expr") * tllexer.symb(")"); | 151 | tllexer.symb("(") * lpeg.V("Expr") * tllexer.try(tllexer.symb(")"), "MissingCP"); |
150 | Block = lpeg.V("StatList") * lpeg.V("RetStat")^-1; | 152 | Block = lpeg.V("StatList") * lpeg.V("RetStat")^-1; |
151 | IfStat = tllexer.kw("if") * lpeg.V("Expr") * tllexer.kw("then") * lpeg.V("Block") * | 153 | IfStat = tllexer.kw("if") * lpeg.V("Expr") * tllexer.try(tllexer.kw("then"), "Then") * lpeg.V("Block") * |
152 | (tllexer.kw("elseif") * lpeg.V("Expr") * tllexer.kw("then") * lpeg.V("Block"))^0 * | 154 | (tllexer.kw("elseif") * lpeg.V("Expr") * tllexer.try(tllexer.kw("then"), "Then") * lpeg.V("Block"))^0 * |
153 | (tllexer.kw("else") * lpeg.V("Block"))^-1 * | 155 | (tllexer.kw("else") * lpeg.V("Block"))^-1 * |
154 | tllexer.kw("end"); | 156 | tllexer.try(tllexer.kw("end"), "IfEnd"); |
155 | WhileStat = tllexer.kw("while") * lpeg.V("Expr") * | 157 | WhileStat = tllexer.kw("while") * lpeg.V("Expr") * |
156 | tllexer.kw("do") * lpeg.V("Block") * tllexer.kw("end"); | 158 | tllexer.try(tllexer.kw("do"), "WhileDo") * lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "WhileEnd"); |
157 | DoStat = tllexer.kw("do") * lpeg.V("Block") * tllexer.kw("end"); | 159 | DoStat = tllexer.kw("do") * lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "BlockEnd"); |
158 | ForBody = tllexer.kw("do") * lpeg.V("Block"); | 160 | ForBody = tllexer.try(tllexer.kw("do"), "ForDo") * lpeg.V("Block"); |
159 | ForNum = lpeg.V("Id") * tllexer.symb("=") * lpeg.V("Expr") * tllexer.symb(",") * | 161 | ForNum = lpeg.V("Id") * tllexer.symb("=") * lpeg.V("Expr") * tllexer.symb(",") * |
160 | lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^-1 * | 162 | lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^-1 * |
161 | lpeg.V("ForBody"); | 163 | lpeg.V("ForBody"); |
162 | ForGen = lpeg.V("NameList") * tllexer.kw("in") * | 164 | ForGen = lpeg.V("NameList") * tllexer.kw("in") * |
163 | lpeg.V("ExpList") * lpeg.V("ForBody"); | 165 | lpeg.V("ExpList") * lpeg.V("ForBody"); |
164 | ForStat = tllexer.kw("for") * (lpeg.V("ForNum") + lpeg.V("ForGen")) * tllexer.kw("end"); | 166 | ForStat = tllexer.kw("for") * (lpeg.V("ForNum") + lpeg.V("ForGen")) * tllexer.try(tllexer.kw("end"), "ForEnd"); |
165 | RepeatStat = tllexer.kw("repeat") * lpeg.V("Block") * | 167 | RepeatStat = tllexer.kw("repeat") * lpeg.V("Block") * |
166 | tllexer.kw("until") * lpeg.V("Expr"); | 168 | tllexer.try(tllexer.kw("until"), "Until") * lpeg.V("Expr"); |
167 | FuncName = lpeg.V("Id") * (tllexer.symb(".") * | 169 | FuncName = lpeg.V("Id") * (tllexer.symb(".") * |
168 | (tllexer.token(tllexer.Name)))^0 * | 170 | (tllexer.token(tllexer.Name, "Name")))^0 * |
169 | (tllexer.symb(":") * (tllexer.token(tllexer.Name)))^-1; | 171 | (tllexer.symb(":") * (tllexer.token(tllexer.Name, "Name")))^-1; |
170 | ParList = lpeg.V("NameList") * (tllexer.symb(",") * lpeg.V("TypedVarArg"))^-1 + | 172 | ParList = lpeg.V("NameList") * (tllexer.symb(",") * tllexer.try(lpeg.V("TypedVarArg"), "ParList"))^-1 + |
171 | lpeg.V("TypedVarArg"); | 173 | lpeg.V("TypedVarArg"); |
172 | TypedVarArg = tllexer.symb("...") * (tllexer.symb(":") * lpeg.V("Type"))^-1; | 174 | TypedVarArg = tllexer.symb("...") * (tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"))^-1; |
173 | FuncBody = tllexer.symb("(") * lpeg.V("ParList")^-1 * tllexer.symb(")") * | 175 | FuncBody = tllexer.symb("(") * lpeg.V("ParList")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP") * |
174 | (tllexer.symb(":") * lpeg.V("RetType"))^-1 * | 176 | (tllexer.symb(":") * tllexer.try(lpeg.V("RetType"), "Type"))^-1 * |
175 | lpeg.V("Block") * tllexer.kw("end"); | 177 | lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "FuncEnd"); |
176 | FuncStat = tllexer.kw("const")^-1 * | 178 | FuncStat = tllexer.kw("const")^-1 * |
177 | tllexer.kw("function") * lpeg.V("FuncName") * lpeg.V("FuncBody"); | 179 | tllexer.kw("function") * lpeg.V("FuncName") * lpeg.V("FuncBody"); |
178 | LocalFunc = tllexer.kw("function") * | 180 | LocalFunc = tllexer.kw("function") * |
179 | lpeg.V("Id") * lpeg.V("FuncBody"); | 181 | lpeg.V("Id") * lpeg.V("FuncBody"); |
180 | LocalAssign = lpeg.V("NameList") * | 182 | LocalAssign = lpeg.V("NameList") * |
181 | ((tllexer.symb("=") * lpeg.V("ExpList")))^-1; | 183 | ((tllexer.symb("=") * tllexer.try(lpeg.V("ExpList"), "LocalAssign")))^-1; |
182 | LocalStat = tllexer.kw("local") * | 184 | LocalStat = tllexer.kw("local") * |
183 | (lpeg.V("LocalTypeDec") + lpeg.V("LocalFunc") + lpeg.V("LocalAssign")); | 185 | (lpeg.V("LocalTypeDec") + lpeg.V("LocalFunc") + lpeg.V("LocalAssign")); |
184 | LabelStat = tllexer.symb("::") * tllexer.token(tllexer.Name) * tllexer.symb("::"); | 186 | LabelStat = tllexer.symb("::") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "Label1") * tllexer.try(tllexer.symb("::"), "Label2"); |
185 | BreakStat = tllexer.kw("break"); | 187 | BreakStat = tllexer.kw("break"); |
186 | GoToStat = tllexer.kw("goto") * tllexer.token(tllexer.Name); | 188 | GoToStat = tllexer.kw("goto") * tllexer.token(tllexer.Name, "Name"); |
187 | RetStat = tllexer.kw("return") * | 189 | RetStat = tllexer.kw("return") * |
188 | (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 * | 190 | (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 * |
189 | tllexer.symb(";")^-1; | 191 | tllexer.symb(";")^-1; |
@@ -214,12 +216,27 @@ local G = lpeg.P { "TypedLua"; | |||
214 | lpeg.V("TypeDecStat") + lpeg.V("ExprStat"); | 216 | lpeg.V("TypeDecStat") + lpeg.V("ExprStat"); |
215 | } | 217 | } |
216 | 218 | ||
219 | local function lineno (s, i) | ||
220 | if i == 1 then return 1, 1 end | ||
221 | local rest, num = s:sub(1,i):gsub("[^\n]*\n", "") | ||
222 | local r = #rest | ||
223 | return 1 + num, r ~= 0 and r or 1 | ||
224 | end | ||
225 | |||
217 | function tlparser.parse (subject, filename, strict, integer) | 226 | function tlparser.parse (subject, filename, strict, integer) |
218 | local errorinfo = {} | 227 | local errorinfo = {} |
219 | lpeg.setmaxstack(1000) | 228 | lpeg.setmaxstack(1000) |
220 | local ast, label, _ = lpeg.match(G, subject, nil, errorinfo, strict, integer) | 229 | local ast, label, _ = lpeg.match(G, subject, nil, errorinfo, strict, integer) |
221 | if not ast then | 230 | if not ast then |
222 | return nil | 231 | local line, col = lineno(subject, errorinfo.ffp) |
232 | local error_msg = string.format("%s:%d:%d: ", filename, line, col) | ||
233 | if label ~= 0 then | ||
234 | error_msg = error_msg .. tlerror.errors[label].msg | ||
235 | else | ||
236 | local u = lpeg.match(lpeg.C(tllexer.OneWord) + lpeg.Cc("EOF"), subject, errorinfo.ffp) | ||
237 | error_msg = error_msg .. string.format("unexpected '%s', expecting %s", u, errorinfo.expected) | ||
238 | end | ||
239 | return nil, error_msg | ||
223 | else | 240 | else |
224 | return true | 241 | return true |
225 | end | 242 | end |