aboutsummaryrefslogtreecommitdiff
path: root/relabel.lua
diff options
context:
space:
mode:
authorUndecidable Robot <undecidabot@gmail.com>2016-05-21 22:29:37 +0800
committerUndecidable Robot <undecidabot@gmail.com>2016-05-21 23:44:04 +0800
commit0445a35b012fe3e5d8df38de2becc94955124ace (patch)
tree4c3c5504fa780b93f3e261b5c13a172d7591511f /relabel.lua
parent043f455b6ef018b7ee06829845fd7b1f9f08f74f (diff)
downloadlpeglabel-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.lua213
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
25local any = m.P(1) 25local any = m.P(1)
26 26
27local errors
28 27
29local function throw(label) 28local 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
75local errmsgs = {}
76local labels = {}
77
78for i, err in ipairs(errinfo) do
79 errmsgs[i] = err[2]
80 labels[err[1]] = i
81end
82
83local errfound
84
85local 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)
35end 92end
36 93
37local ignore = m.Cmt(any, function (input, pos) 94local ignore = m.Cmt(any, function (input, pos)
38 return errors[#errors][2], mm.P"" 95 return errfound[#errfound][2], mm.P""
39end) 96end)
40 97
98local function adderror(message)
99 tinsert(errfound, {message})
100end
101
41-- Pre-defined names 102-- Pre-defined names
42local Predef = { nl = m.P"\n" } 103local Predef = { nl = m.P"\n" }
43local tlabels = {} 104local tlabels = {}
44 105
45local function adderror(message)
46 tinsert(errors, {message})
47end
48
49 106
50local mem 107local mem
51local fmem 108local fmem
@@ -129,8 +186,8 @@ local Def = name * m.Carg(1)
129 186
130local num = m.C(m.R"09"^1) * S / tonumber 187local num = m.C(m.R"09"^1) * S / tonumber
131 188
132local String = "'" * m.C((any - "'" - m.P"\n")^0) * ("'" + throw(31)) + 189local 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
136local defined = "%" * Def / function (c,Defs) 193local defined = "%" * Def / function (c,Defs)
@@ -149,9 +206,9 @@ local item = defined + Range + m.C(any)
149local Class = 206local 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
156local function adddef (t, k, exp) 213local 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
187end 244end
188 245
246local function labify(labelnames)
247 for i, l in ipairs(labelnames) do
248 labelnames[i] = labels[l]
249 end
250 return labelnames
251end
252
253local labelset1 = labify {
254 "ExpPatt2", "ExpPatt3",
255 "ExpNum", "ExpCap", "ExpName1",
256 "MisTerm1", "MisTerm2"
257}
258
259local labelset2 = labify {
260 "MisClose1", "MisClose2", "MisClose3", "MisClose4", "MisClose5",
261 "MisClose7", "MisClose8"
262}
263
189local exp = m.P{ "Exp", 264local 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
242local pattern = S * m.Cg(m.Cc(false), "G") * (exp + throw(1)) / mm.P * (-any + throw(2)) 319local pattern = S * m.Cg(m.Cc(false), "G") * expect(exp, "NoPatt") / mm.P * expect(-any, "ExtraChars")
243 320
244local function lineno (s, i) 321local 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
249end 326end
250 327
251local 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
287local function compile (p, defs) 328local 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
309end 350end