diff options
author | Undecidable Robot <undecidabot@gmail.com> | 2016-05-21 22:29:37 +0800 |
---|---|---|
committer | Undecidable Robot <undecidabot@gmail.com> | 2016-05-21 23:44:04 +0800 |
commit | 0445a35b012fe3e5d8df38de2becc94955124ace (patch) | |
tree | 4c3c5504fa780b93f3e261b5c13a172d7591511f /relabel.lua | |
parent | 043f455b6ef018b7ee06829845fd7b1f9f08f74f (diff) | |
download | lpeglabel-0445a35b012fe3e5d8df38de2becc94955124ace.tar.gz lpeglabel-0445a35b012fe3e5d8df38de2becc94955124ace.tar.bz2 lpeglabel-0445a35b012fe3e5d8df38de2becc94955124ace.zip |
Making use of mnemonics and simplifying error messages
Diffstat (limited to '')
-rw-r--r-- | relabel.lua | 213 |
1 files changed, 127 insertions, 86 deletions
diff --git a/relabel.lua b/relabel.lua index 0594777..1cc0b3c 100644 --- a/relabel.lua +++ b/relabel.lua | |||
@@ -24,28 +24,85 @@ if version == "Lua 5.2" then _ENV = nil end | |||
24 | 24 | ||
25 | local any = m.P(1) | 25 | local any = m.P(1) |
26 | 26 | ||
27 | local errors | ||
28 | 27 | ||
29 | local function throw(label) | 28 | local errinfo = { |
29 | {"NoPatt", "no pattern found"}, | ||
30 | {"ExtraChars", "unexpected characters after the pattern"}, | ||
31 | |||
32 | {"ExpPatt1", "expected a pattern after '/' or the label(s)"}, | ||
33 | |||
34 | {"ExpPatt2", "expected a pattern after '&'"}, | ||
35 | {"ExpPatt3", "expected a pattern after '!'"}, | ||
36 | |||
37 | {"ExpPatt4", "expected a pattern after '('"}, | ||
38 | {"ExpPatt5", "expected a pattern after ':'"}, | ||
39 | {"ExpPatt6", "expected a pattern after '{~'"}, | ||
40 | {"ExpPatt7", "expected a pattern after '{|'"}, | ||
41 | |||
42 | {"ExpPatt8", "expected a pattern after '<-'"}, | ||
43 | |||
44 | {"ExpPattOrClose", "expected a pattern or closing '}' after '{'"}, | ||
45 | |||
46 | {"ExpNum", "expected a number after '^', '+' or '-' (no space)"}, | ||
47 | {"ExpCap", "expected a string, number, '{}' or name after '->'"}, | ||
48 | |||
49 | {"ExpName1", "expected the name of a rule after '=>'"}, | ||
50 | {"ExpName2", "expected the name of a rule after '=' (no space)"}, | ||
51 | {"ExpName3", "expected the name of a rule after '<' (no space)"}, | ||
52 | |||
53 | {"ExpLab1", "expected at least one label after '{'"}, | ||
54 | {"ExpLab2", "expected a label after the comma"}, | ||
55 | |||
56 | {"ExpNameOrLab", "expected a name or label after '%' (no space)"}, | ||
57 | |||
58 | {"ExpItem", "expected at least one item after '[' or '^'"}, | ||
59 | |||
60 | {"MisClose1", "missing closing ')'"}, | ||
61 | {"MisClose2", "missing closing ':}'"}, | ||
62 | {"MisClose3", "missing closing '~}'"}, | ||
63 | {"MisClose4", "missing closing '|}'"}, | ||
64 | {"MisClose5", "missing closing '}'"}, -- for the captures | ||
65 | |||
66 | {"MisClose6", "missing closing '>'"}, | ||
67 | {"MisClose7", "missing closing '}'"}, -- for the labels | ||
68 | |||
69 | {"MisClose8", "missing closing ']'"}, | ||
70 | |||
71 | {"MisTerm1", "missing terminating single quote"}, | ||
72 | {"MisTerm2", "missing terminating double quote"}, | ||
73 | } | ||
74 | |||
75 | local errmsgs = {} | ||
76 | local labels = {} | ||
77 | |||
78 | for i, err in ipairs(errinfo) do | ||
79 | errmsgs[i] = err[2] | ||
80 | labels[err[1]] = i | ||
81 | end | ||
82 | |||
83 | local errfound | ||
84 | |||
85 | local function expect(pattern, labelname) | ||
86 | local label = labels[labelname] | ||
30 | local record = function (input, pos) | 87 | local record = function (input, pos) |
31 | tinsert(errors, {label, pos}) | 88 | tinsert(errfound, {label, pos}) |
32 | return true | 89 | return true |
33 | end | 90 | end |
34 | return m.Cmt("", record) * m.T(label) | 91 | return pattern + m.Cmt("", record) * m.T(label) |
35 | end | 92 | end |
36 | 93 | ||
37 | local ignore = m.Cmt(any, function (input, pos) | 94 | local ignore = m.Cmt(any, function (input, pos) |
38 | return errors[#errors][2], mm.P"" | 95 | return errfound[#errfound][2], mm.P"" |
39 | end) | 96 | end) |
40 | 97 | ||
98 | local function adderror(message) | ||
99 | tinsert(errfound, {message}) | ||
100 | end | ||
101 | |||
41 | -- Pre-defined names | 102 | -- Pre-defined names |
42 | local Predef = { nl = m.P"\n" } | 103 | local Predef = { nl = m.P"\n" } |
43 | local tlabels = {} | 104 | local tlabels = {} |
44 | 105 | ||
45 | local function adderror(message) | ||
46 | tinsert(errors, {message}) | ||
47 | end | ||
48 | |||
49 | 106 | ||
50 | local mem | 107 | local mem |
51 | local fmem | 108 | local fmem |
@@ -129,8 +186,8 @@ local Def = name * m.Carg(1) | |||
129 | 186 | ||
130 | local num = m.C(m.R"09"^1) * S / tonumber | 187 | local num = m.C(m.R"09"^1) * S / tonumber |
131 | 188 | ||
132 | local String = "'" * m.C((any - "'" - m.P"\n")^0) * ("'" + throw(31)) + | 189 | local String = "'" * m.C((any - "'" - m.P"\n")^0) * expect("'", "MisTerm1") + |
133 | '"' * m.C((any - '"' - m.P"\n")^0) * ('"' + throw(30)) | 190 | '"' * m.C((any - '"' - m.P"\n")^0) * expect('"', "MisTerm2") |
134 | 191 | ||
135 | 192 | ||
136 | local defined = "%" * Def / function (c,Defs) | 193 | local defined = "%" * Def / function (c,Defs) |
@@ -149,9 +206,9 @@ local item = defined + Range + m.C(any) | |||
149 | local Class = | 206 | local Class = |
150 | "[" | 207 | "[" |
151 | * (m.C(m.P"^"^-1)) -- optional complement symbol | 208 | * (m.C(m.P"^"^-1)) -- optional complement symbol |
152 | * m.Cf((item + throw(24)) * (item - "]")^0, mt.__add) / | 209 | * m.Cf(expect(item, "ExpItem") * (item - "]")^0, mt.__add) / |
153 | function (c, p) return c == "^" and any - p or p end | 210 | function (c, p) return c == "^" and any - p or p end |
154 | * ("]" + throw(25)) | 211 | * expect("]", "MisClose8") |
155 | 212 | ||
156 | local function adddef (t, k, exp) | 213 | local function adddef (t, k, exp) |
157 | if t[k] then | 214 | if t[k] then |
@@ -186,60 +243,80 @@ local function labchoice (...) | |||
186 | return p | 243 | return p |
187 | end | 244 | end |
188 | 245 | ||
246 | local function labify(labelnames) | ||
247 | for i, l in ipairs(labelnames) do | ||
248 | labelnames[i] = labels[l] | ||
249 | end | ||
250 | return labelnames | ||
251 | end | ||
252 | |||
253 | local labelset1 = labify { | ||
254 | "ExpPatt2", "ExpPatt3", | ||
255 | "ExpNum", "ExpCap", "ExpName1", | ||
256 | "MisTerm1", "MisTerm2" | ||
257 | } | ||
258 | |||
259 | local labelset2 = labify { | ||
260 | "MisClose1", "MisClose2", "MisClose3", "MisClose4", "MisClose5", | ||
261 | "MisClose7", "MisClose8" | ||
262 | } | ||
263 | |||
189 | local exp = m.P{ "Exp", | 264 | local exp = m.P{ "Exp", |
190 | Exp = S * ( m.V"Grammar" | 265 | Exp = S * ( m.V"Grammar" |
191 | + (m.V"SeqLC" * ("/" * (m.V"Labels" + m.Cc(nil)) * S | 266 | + (m.V"SeqLC" * ("/" * (m.V"Labels" + m.Cc(nil)) * S |
192 | * m.Lc(m.V"SeqLC" + throw(4), m.V"SkipToSlash", 4))^0) / labchoice ); | 267 | * m.Lc(expect(m.V"SeqLC", "ExpPatt1"), m.V"SkipToSlash", labels["ExpPatt1"]))^0) / labchoice ); |
193 | Labels = m.Ct(m.P"{" * S * (m.V"Label" + throw(27)) * (S * "," * S * (m.V"Label" + throw(28)))^0 * S * ("}" + throw(29))); | 268 | Labels = m.Ct(m.P"{" * S * expect(m.V"Label", "ExpLab1") * (S * "," * S |
269 | * expect(m.V"Label", "ExpLab2"))^0 * S * expect("}", "MisClose7")); | ||
194 | SkipToSlash = (-m.P"/" * m.V"Stuff")^0 * m.Cc(mm.P""); | 270 | SkipToSlash = (-m.P"/" * m.V"Stuff")^0 * m.Cc(mm.P""); |
195 | Stuff = m.V"GroupedStuff" + any; | 271 | Stuff = m.V"GroupedStuff" + any; |
196 | GroupedStuff = "(" * (-m.P")" * m.V"Stuff")^0 * ")" | 272 | GroupedStuff = "(" * (-m.P")" * m.V"Stuff")^0 * ")" |
197 | + "{" * (-m.P"}" * m.V"Stuff")^0 * "}"; | 273 | + "{" * (-m.P"}" * m.V"Stuff")^0 * "}"; |
198 | SeqLC = m.Lc(m.V"Seq", m.V"SkipToSlash", 5, 6, 7, 8, 9, 10, 31, 30); | 274 | SeqLC = m.Lc(m.V"Seq", m.V"SkipToSlash", unpack(labelset1)); |
199 | Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix"^1 , mt.__mul); | 275 | Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix"^1 , mt.__mul); |
200 | Prefix = "&" * S * (m.V"Prefix" + throw(5)) / mt.__len | 276 | Prefix = "&" * S * expect(m.V"Prefix", "ExpPatt2") / mt.__len |
201 | + "!" * S * (m.V"Prefix" + throw(6)) / mt.__unm | 277 | + "!" * S * expect(m.V"Prefix", "ExpPatt3") / mt.__unm |
202 | + m.V"Suffix"; | 278 | + m.V"Suffix"; |
203 | Suffix = m.Cf(m.V"PrimaryLC" * S * | 279 | Suffix = m.Cf(m.V"PrimaryLC" * S * |
204 | ( ( m.P"+" * m.Cc(1, mt.__pow) | 280 | ( ( m.P"+" * m.Cc(1, mt.__pow) |
205 | + m.P"*" * m.Cc(0, mt.__pow) | 281 | + m.P"*" * m.Cc(0, mt.__pow) |
206 | + m.P"?" * m.Cc(-1, mt.__pow) | 282 | + m.P"?" * m.Cc(-1, mt.__pow) |
207 | + "^" * ( m.Cg(num * m.Cc(mult)) | 283 | + "^" * expect( m.Cg(num * m.Cc(mult)) |
208 | + m.Cg(m.C(m.S"+-" * m.R"09"^1) * m.Cc(mt.__pow)) | 284 | + m.Cg(m.C(m.S"+-" * m.R"09"^1) * m.Cc(mt.__pow)), |
209 | + throw(7) | 285 | "ExpNum" |
210 | ) | 286 | ) |
211 | + "->" * S * ( m.Cg((String + num) * m.Cc(mt.__div)) | 287 | + "->" * S * expect( m.Cg((String + num) * m.Cc(mt.__div)) |
212 | + m.P"{" * (m.P"}" + throw(8)) * m.Cc(nil, m.Ct) | 288 | + m.P"{}" * m.Cc(nil, m.Ct) |
213 | + m.Cg(Def / getdef * m.Cc(mt.__div)) | 289 | + m.Cg(Def / getdef * m.Cc(mt.__div)), |
214 | + throw(9) | 290 | "ExpCap" |
215 | ) | 291 | ) |
216 | + "=>" * S * (m.Cg(Def / getdef * m.Cc(m.Cmt)) + throw(10)) | 292 | + "=>" * S * expect(m.Cg(Def / getdef * m.Cc(m.Cmt)), "ExpName1") |
217 | ) * S | 293 | ) * S |
218 | )^0, function (a,b,f) return f(a,b) end ); | 294 | )^0, function (a,b,f) return f(a,b) end ); |
219 | PrimaryLC = m.Lc(m.V"Primary", ignore, 12, 15, 18, 20, 25, 29, 33); | 295 | PrimaryLC = m.Lc(m.V"Primary", ignore, unpack(labelset2)); |
220 | Primary = "(" * (m.V"Exp" + throw(11)) * (")" + throw(12)) | 296 | Primary = "(" * expect(m.V"Exp", "ExpPatt4") * expect(")", "MisClose1") |
221 | + String / mm.P | 297 | + String / mm.P |
222 | + Class | 298 | + Class |
223 | + defined | 299 | + defined |
224 | + "%{" * S * (m.V"Label" + throw(27)) * (S * "," * S * (m.V"Label" + throw(28)))^0 * S * ("}" + throw(29)) / mm.T | 300 | + "%{" * S * expect(m.V"Label", "ExpLab1") * (S * "," * S |
225 | + ("%" * throw(13)) | 301 | * expect(m.V"Label", "ExpLab2"))^0 * S * expect("}", "MisClose7") / mm.T |
226 | + "{:" * (name * ":" + m.Cc(nil)) * (m.V"Exp" + throw(14)) * (":}" + throw(15)) / | 302 | + "%" * expect(m.P(false), "ExpNameOrLab") |
227 | function (n, p) return mm.Cg(p, n) end | 303 | + "{:" * (name * ":" + m.Cc(nil)) * expect(m.V"Exp", "ExpPatt5") * expect(":}", "MisClose2") |
228 | + "=" * (name / function (n) return mm.Cmt(mm.Cb(n), equalcap) end + throw(16)) | 304 | / function (n, p) return mm.Cg(p, n) end |
305 | + "=" * expect(name, "ExpName2") / function (n) return mm.Cmt(mm.Cb(n), equalcap) end | ||
229 | + m.P"{}" / mm.Cp | 306 | + m.P"{}" / mm.Cp |
230 | + "{~" * (m.V"Exp" + throw(17)) * ("~}" + throw(18)) / mm.Cs | 307 | + "{~" * expect(m.V"Exp", "ExpPatt6") * expect("~}", "MisClose3") / mm.Cs |
231 | + "{|" * (m.V"Exp" + throw(32)) * ("|}" + throw(33)) / mm.Ct | 308 | + "{|" * expect(m.V"Exp", "ExpPatt7") * expect("|}", "MisClose4") / mm.Ct |
232 | + "{" * (m.V"Exp" + throw(19)) * ("}" + throw(20)) / mm.C | 309 | + "{" * expect(m.V"Exp", "ExpPattOrClose") * expect("}", "MisClose5") / mm.C |
233 | + m.P"." * m.Cc(any) | 310 | + m.P"." * m.Cc(any) |
234 | + (name * -arrow + "<" * (name + throw(21)) * (">" + throw(22))) * m.Cb("G") / NT; | 311 | + (name * -arrow + "<" * expect(name, "ExpName3") * expect(">", "MisClose6")) * m.Cb("G") / NT; |
235 | Label = num + name / function (f) return tlabels[f] end; | 312 | Label = num + name / function (f) return tlabels[f] end; |
236 | Definition = name * arrow * (m.V"Exp" + throw(23)); | 313 | Definition = name * arrow * expect(m.V"Exp", "ExpPatt8"); |
237 | Grammar = m.Cg(m.Cc(true), "G") * | 314 | Grammar = m.Cg(m.Cc(true), "G") * |
238 | m.Cf(m.V"Definition" / firstdef * m.Cg(m.V"Definition")^0, | 315 | m.Cf(m.V"Definition" / firstdef * m.Cg(m.V"Definition")^0, |
239 | adddef) / mm.P | 316 | adddef) / mm.P |
240 | } | 317 | } |
241 | 318 | ||
242 | local pattern = S * m.Cg(m.Cc(false), "G") * (exp + throw(1)) / mm.P * (-any + throw(2)) | 319 | local pattern = S * m.Cg(m.Cc(false), "G") * expect(exp, "NoPatt") / mm.P * expect(-any, "ExtraChars") |
243 | 320 | ||
244 | local function lineno (s, i) | 321 | local function lineno (s, i) |
245 | if i == 1 then return 1, 1 end | 322 | if i == 1 then return 1, 1 end |
@@ -248,62 +325,26 @@ local function lineno (s, i) | |||
248 | return 1 + num, r ~= 0 and r or 1 | 325 | return 1 + num, r ~= 0 and r or 1 |
249 | end | 326 | end |
250 | 327 | ||
251 | local errorMessages = { | ||
252 | "No pattern found", | ||
253 | "Unexpected characters after the pattern", | ||
254 | "Expected a pattern after labels", | ||
255 | "Expected a pattern after `/`", | ||
256 | "Expected a pattern after `&`", | ||
257 | "Expected a pattern after `!`", | ||
258 | "Expected a valid number after `^`", | ||
259 | "Expected `}` right after `{`", | ||
260 | "Expected a string, number, `{}` or name after `->`", | ||
261 | "Expected a name after `=>`", | ||
262 | "Expected a pattern after `(`", | ||
263 | "Missing the closing `)` after pattern", | ||
264 | "Expected a name or labels right after `%` (without any space)", | ||
265 | "Expected a pattern after `{:` or `:`", | ||
266 | "Missing the closing `:}` after pattern", | ||
267 | "Expected a name after `=` (without any space)", | ||
268 | "Expected a pattern after `{~`", | ||
269 | "Missing the closing `~}` after pattern", | ||
270 | "Expected a pattern or closing `}` after `{`", | ||
271 | "Missing the closing `}` after pattern", | ||
272 | "Expected a name right after `<`", | ||
273 | "Missing the closing `>` after the name", | ||
274 | "Expected a pattern after `<-`", | ||
275 | "Expected at least one item after `[` or `^`", | ||
276 | "Missing the closing `]` after the items", | ||
277 | "Expected an item after the `-` (except `]`)", | ||
278 | "Expected at least one label after the `{`", | ||
279 | "Expected a label after the comma", | ||
280 | "Missing closing `}` after the labels", | ||
281 | "Missing closing double quote in string", | ||
282 | "Missing closing single quote in string", | ||
283 | "Expected a pattern after `{|`", | ||
284 | "Missing the closing `|}` after pattern", | ||
285 | } | ||
286 | |||
287 | local function compile (p, defs) | 328 | local function compile (p, defs) |
288 | if mm.type(p) == "pattern" then return p end -- already compiled | 329 | if mm.type(p) == "pattern" then return p end -- already compiled |
289 | p = p .. " " -- for better reporting of column numbers in errors when at EOF | 330 | p = p .. " " -- for better reporting of column numbers in errors when at EOF |
290 | errors = {} | 331 | errfound = {} |
291 | local cp, label, suffix = pattern:match(p, 1, defs) | 332 | local cp, label, suffix = pattern:match(p, 1, defs) |
292 | if #errors > 0 then | 333 | if #errfound > 0 then |
293 | local lines = {} | 334 | local lines = {} |
294 | for line in p:gmatch("[^\r\n]+") do tinsert(lines, line) end | 335 | for line in p:gmatch("[^\r\n]+") do tinsert(lines, line) end |
295 | local errmsgs = {} | 336 | local errors = {} |
296 | for i, err in ipairs(errors) do | 337 | for i, err in ipairs(errfound) do |
297 | if #err == 1 then | 338 | if #err == 1 then |
298 | tinsert(errmsgs, err[1]) | 339 | tinsert(errors, err[1]) |
299 | else | 340 | else |
300 | local line, col = lineno(p, err[2]) | 341 | local line, col = lineno(p, err[2]) |
301 | tinsert(errmsgs, "Line" .. line .. ", Col " .. col .. ": " .. errorMessages[err[1]]) | 342 | tinsert(errors, "Line" .. line .. ", Col " .. col .. ": " .. errmsgs[err[1]]) |
302 | tinsert(errmsgs, lines[line]) | 343 | tinsert(errors, lines[line]) |
303 | tinsert(errmsgs, rep(" ", col-1) .. "^") | 344 | tinsert(errors, rep(" ", col-1) .. "^") |
304 | end | 345 | end |
305 | end | 346 | end |
306 | error(concat(errmsgs, "\n")) | 347 | error(concat(errors, "\n")) |
307 | end | 348 | end |
308 | return cp | 349 | return cp |
309 | end | 350 | end |