aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergio Queiroz <sqmedeiros@gmail.com>2016-11-10 16:26:11 -0300
committerSergio Queiroz <sqmedeiros@gmail.com>2016-11-10 16:26:11 -0300
commitfd28f9d9e54f33bf7ae3a5e12dc71478f9c91aea (patch)
tree875ab38000e52376583bc13741b18701c6294f80
parentd84dd6b3659f94b09e67eb90a10e71eb05c5630e (diff)
downloadlpeglabel-fd28f9d9e54f33bf7ae3a5e12dc71478f9c91aea.tar.gz
lpeglabel-fd28f9d9e54f33bf7ae3a5e12dc71478f9c91aea.tar.bz2
lpeglabel-fd28f9d9e54f33bf7ae3a5e12dc71478f9c91aea.zip
Removing labeled choice, updating testlabel, and disabling an optmization related to Throw
-rw-r--r--lpcode.c39
-rw-r--r--lpprint.c4
-rw-r--r--lptree.c23
-rw-r--r--lptree.h2
-rw-r--r--lpvm.c11
-rw-r--r--lpvm.h1
-rw-r--r--relabelrec.lua (renamed from relabel.lua)101
-rwxr-xr-xtest.lua2
-rw-r--r--testlabel.lua453
9 files changed, 348 insertions, 288 deletions
diff --git a/lpcode.c b/lpcode.c
index d5f8d68..b2dbba2 100644
--- a/lpcode.c
+++ b/lpcode.c
@@ -196,7 +196,7 @@ int checkaux (TTree *tree, int pred) {
196 if (checkaux(sib2(tree), pred)) return 1; 196 if (checkaux(sib2(tree), pred)) return 1;
197 /* else return checkaux(sib1(tree), pred); */ 197 /* else return checkaux(sib1(tree), pred); */
198 tree = sib1(tree); goto tailcall; 198 tree = sib1(tree); goto tailcall;
199 case TLabChoice: case TRecov: /* labeled failure */ 199 case TRecov: /* labeled failure */
200 /* we do not know whether sib2 will be evaluated */ 200 /* we do not know whether sib2 will be evaluated */
201 tree = sib1(tree); goto tailcall; 201 tree = sib1(tree); goto tailcall;
202 case TCapture: case TGrammar: case TRule: 202 case TCapture: case TGrammar: case TRule:
@@ -218,10 +218,10 @@ int fixedlenx (TTree *tree, int count, int len) {
218 switch (tree->tag) { 218 switch (tree->tag) {
219 case TChar: case TSet: case TAny: 219 case TChar: case TSet: case TAny:
220 return len + 1; 220 return len + 1;
221 case TFalse: case TTrue: case TNot: case TAnd: case TBehind: 221 case TFalse: case TTrue: case TNot: case TAnd: case TBehind:
222 case TThrow: /* labeled failure */
223 return len; 222 return len;
224 case TRep: case TRunTime: case TOpenCall: 223 case TRep: case TRunTime: case TOpenCall:
224 case TThrow: /* labeled failure */
225 return -1; 225 return -1;
226 case TCapture: case TRule: case TGrammar: 226 case TCapture: case TRule: case TGrammar:
227 /* return fixedlenx(sib1(tree), count); */ 227 /* return fixedlenx(sib1(tree), count); */
@@ -237,7 +237,7 @@ int fixedlenx (TTree *tree, int count, int len) {
237 /* else return fixedlenx(sib2(tree), count, len); */ 237 /* else return fixedlenx(sib2(tree), count, len); */
238 tree = sib2(tree); goto tailcall; 238 tree = sib2(tree); goto tailcall;
239 } 239 }
240 case TChoice: case TLabChoice: { /* labeled failure */ 240 case TChoice: {
241 int n1, n2; 241 int n1, n2;
242 n1 = fixedlenx(sib1(tree), count, len); 242 n1 = fixedlenx(sib1(tree), count, len);
243 if (n1 < 0) return -1; 243 if (n1 < 0) return -1;
@@ -287,7 +287,7 @@ static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) {
287 loopset(i, firstset->cs[i] = follow->cs[i]); /* follow = fullset(?) */ 287 loopset(i, firstset->cs[i] = follow->cs[i]); /* follow = fullset(?) */
288 return 1; 288 return 1;
289 } 289 }
290 case TChoice: case TLabChoice: { /*(?) labeled failure */ 290 case TChoice: {
291 Charset csaux; 291 Charset csaux;
292 int e1 = getfirst(sib1(tree), follow, firstset); 292 int e1 = getfirst(sib1(tree), follow, firstset);
293 int e2 = getfirst(sib2(tree), follow, &csaux); 293 int e2 = getfirst(sib2(tree), follow, &csaux);
@@ -378,7 +378,7 @@ static int headfail (TTree *tree) {
378 if (!nofail(sib2(tree))) return 0; 378 if (!nofail(sib2(tree))) return 0;
379 /* else return headfail(sib1(tree)); */ 379 /* else return headfail(sib1(tree)); */
380 tree = sib1(tree); goto tailcall; 380 tree = sib1(tree); goto tailcall;
381 case TChoice: case TLabChoice: case TRecov: /* labeled failure */ 381 case TChoice: case TRecov: /* labeled failure */
382 if (!headfail(sib1(tree))) return 0; 382 if (!headfail(sib1(tree))) return 0;
383 /* else return headfail(sib2(tree)); */ 383 /* else return headfail(sib2(tree)); */
384 tree = sib2(tree); goto tailcall; 384 tree = sib2(tree); goto tailcall;
@@ -398,7 +398,7 @@ static int needfollow (TTree *tree) {
398 case TChar: case TSet: case TAny: 398 case TChar: case TSet: case TAny:
399 case TFalse: case TTrue: case TAnd: case TNot: 399 case TFalse: case TTrue: case TAnd: case TNot:
400 case TRunTime: case TGrammar: case TCall: case TBehind: 400 case TRunTime: case TGrammar: case TCall: case TBehind:
401 case TThrow: case TLabChoice: case TRecov: /* (?)labeled failure */ 401 case TThrow: case TRecov: /* (?)labeled failure */
402 return 0; 402 return 0;
403 case TChoice: case TRep: 403 case TChoice: case TRep:
404 return 1; 404 return 1;
@@ -433,7 +433,7 @@ int sizei (const Instruction *i) {
433 return 2; 433 return 2;
434 case IThrow: /* labeled failure */ 434 case IThrow: /* labeled failure */
435 return 1; 435 return 1;
436 case ILabChoice: case IRecov: 436 case IRecov:
437 return (CHARSETINSTSIZE - 1) + 2; /* labeled failure */ 437 return (CHARSETINSTSIZE - 1) + 2; /* labeled failure */
438 default: return 1; 438 default: return 1;
439 } 439 }
@@ -499,7 +499,7 @@ static int addoffsetinst (CompileState *compst, Opcode op) {
499 int i = addinstruction(compst, op, 0); /* instruction */ 499 int i = addinstruction(compst, op, 0); /* instruction */
500 addinstruction(compst, (Opcode)0, 0); /* open space for offset */ 500 addinstruction(compst, (Opcode)0, 0); /* open space for offset */
501 assert(op == ITestSet || sizei(&getinstr(compst, i)) == 2 || 501 assert(op == ITestSet || sizei(&getinstr(compst, i)) == 2 ||
502 op == IRecov || op == ILabChoice); /* labeled failure */ 502 op == IRecov); /* labeled failure */
503 return i; 503 return i;
504} 504}
505 505
@@ -707,21 +707,6 @@ static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt,
707 707
708 708
709/* labeled failure begin */ 709/* labeled failure begin */
710static void codelabchoice (CompileState *compst, TTree *p1, TTree *p2, int opt,
711 const Charset *fl, const byte *cs) {
712 int emptyp2 = (p2->tag == TTrue);
713 int pcommit;
714 int test = NOINST;
715 int pchoice = addoffsetinst(compst, ILabChoice);
716 addcharset(compst, cs);
717 codegen(compst, p1, emptyp2, test, fullset);
718 pcommit = addoffsetinst(compst, ICommit);
719 jumptohere(compst, pchoice);
720 jumptohere(compst, test);
721 codegen(compst, p2, opt, NOINST, fl);
722 jumptohere(compst, pcommit);
723}
724
725static void coderecovery (CompileState *compst, TTree *p1, TTree *p2, int opt, 710static void coderecovery (CompileState *compst, TTree *p1, TTree *p2, int opt,
726 const Charset *fl, const byte *cs) { 711 const Charset *fl, const byte *cs) {
727 int emptyp2 = (p2->tag == TTrue); 712 int emptyp2 = (p2->tag == TTrue);
@@ -970,10 +955,6 @@ static void codegen (CompileState *compst, TTree *tree, int opt, int tt,
970 addinstruction(compst, IThrow, (byte) tree->u.label); 955 addinstruction(compst, IThrow, (byte) tree->u.label);
971 break; 956 break;
972 } 957 }
973 case TLabChoice: { /* labeled failure */
974 codelabchoice(compst, sib1(tree), sib2(tree), opt, fl, treelabelset(tree));
975 break;
976 }
977 case TRecov: { /* labeled failure */ 958 case TRecov: { /* labeled failure */
978 coderecovery(compst, sib1(tree), sib2(tree), opt, fl, treelabelset(tree)); 959 coderecovery(compst, sib1(tree), sib2(tree), opt, fl, treelabelset(tree));
979 break; 960 break;
@@ -1000,7 +981,7 @@ static void peephole (CompileState *compst) {
1000 switch (code[i].i.code) { 981 switch (code[i].i.code) {
1001 case IChoice: case ICall: case ICommit: case IPartialCommit: 982 case IChoice: case ICall: case ICommit: case IPartialCommit:
1002 case IBackCommit: case ITestChar: case ITestSet: 983 case IBackCommit: case ITestChar: case ITestSet:
1003 case ILabChoice: case IRecov: /* labeled failure */ 984 case IRecov: /* labeled failure */
1004 case ITestAny: { /* instructions with labels */ 985 case ITestAny: { /* instructions with labels */
1005 jumptothere(compst, i, finallabel(code, i)); /* optimize label */ 986 jumptothere(compst, i, finallabel(code, i)); /* optimize label */
1006 break; 987 break;
diff --git a/lpprint.c b/lpprint.c
index 122d2e5..ff69a6a 100644
--- a/lpprint.c
+++ b/lpprint.c
@@ -112,7 +112,7 @@ void printinst (const Instruction *op, const Instruction *p) {
112 printf("%d", p->i.aux); 112 printf("%d", p->i.aux);
113 break; 113 break;
114 } 114 }
115 case ILabChoice: case IRecov: { /* labeled failure */ 115 case IRecov: { /* labeled failure */
116 printjmp(op, p); 116 printjmp(op, p);
117 printcharset((p+2)->buff); 117 printcharset((p+2)->buff);
118 break; 118 break;
@@ -223,7 +223,7 @@ void printtree (TTree *tree, int ident) {
223 default: { 223 default: {
224 int sibs = numsiblings[tree->tag]; 224 int sibs = numsiblings[tree->tag];
225 printf("\n"); 225 printf("\n");
226 if (tree->tag == TLabChoice || tree->tag == TRecov) { /* labeled failure */ 226 if (tree->tag == TRecov) { /* labeled failure */
227 printcharset(treelabelset(tree)); 227 printcharset(treelabelset(tree));
228 printf("\n"); 228 printf("\n");
229 } 229 }
diff --git a/lptree.c b/lptree.c
index 700398b..9861cfe 100644
--- a/lptree.c
+++ b/lptree.c
@@ -723,37 +723,25 @@ static int lp_behind (lua_State *L) {
723*/ 723*/
724static int lp_throw (lua_State *L) { 724static int lp_throw (lua_State *L) {
725 int label = luaL_checkinteger(L, -1); 725 int label = luaL_checkinteger(L, -1);
726 luaL_argcheck(L, label >= 0 && label < MAXLABELS, -1, "the number of a label must be between 0 and 255"); 726 luaL_argcheck(L, label >= 1 && label < MAXLABELS, -1, "the number of a label must be between 1 and 255");
727 newthrowleaf(L, label); 727 newthrowleaf(L, label);
728 return 1; 728 return 1;
729} 729}
730 730
731/* 731/*
732** labeled choice function 732** labeled recovery function
733*/ 733*/
734static int lp_labchoice (lua_State *L) {
735 int n = lua_gettop(L);
736 TTree *tree = newrootlab2sib(L, TLabChoice);
737 int i;
738 for (i = 3; i <= n; i++) {
739 int d = luaL_checkinteger(L, i);
740 luaL_argcheck(L, d >= 0 && d < MAXLABELS, i, "the number of a label must be between 0 and 255");
741 setlabel(treelabelset(tree), (byte)d);
742 }
743 return 1;
744}
745
746
747static int lp_recovery (lua_State *L) { 734static int lp_recovery (lua_State *L) {
748 int n = lua_gettop(L); 735 int n = lua_gettop(L);
749 TTree *tree = newrootlab2sib(L, TRecov); 736 TTree *tree = newrootlab2sib(L, TRecov);
737 luaL_argcheck(L, n >= 3, 3, "non-nil value expected");
750 if (n == 2) { /* catches fail as default */ 738 if (n == 2) { /* catches fail as default */
751 /*setlabel(treelabelset(tree), LFAIL); recovery does not catch regular fail */ 739 /*setlabel(treelabelset(tree), LFAIL); recovery does not catch regular fail */
752 } else { 740 } else {
753 int i; 741 int i;
754 for (i = 3; i <= n; i++) { 742 for (i = 3; i <= n; i++) {
755 int d = luaL_checkinteger(L, i); 743 int d = luaL_checkinteger(L, i);
756 luaL_argcheck(L, d >= 0 && d < MAXLABELS, i, "the number of a label must be between 0 and 255"); 744 luaL_argcheck(L, d >= 1 && d < MAXLABELS, i, "the number of a label must be between 1 and 255");
757 setlabel(treelabelset(tree), (byte)d); 745 setlabel(treelabelset(tree), (byte)d);
758 } 746 }
759 } 747 }
@@ -1089,7 +1077,7 @@ static int verifyrule (lua_State *L, TTree *tree, int *passed, int npassed,
1089 return nb; 1077 return nb;
1090 /* else return verifyrule(L, sib2(tree), passed, npassed, nb); */ 1078 /* else return verifyrule(L, sib2(tree), passed, npassed, nb); */
1091 tree = sib2(tree); goto tailcall; 1079 tree = sib2(tree); goto tailcall;
1092 case TChoice: case TLabChoice: case TRecov: /* must check both children */ /* labeled failure */ 1080 case TChoice: case TRecov: /* must check both children */ /* labeled failure */
1093 nb = verifyrule(L, sib1(tree), passed, npassed, nb); 1081 nb = verifyrule(L, sib1(tree), passed, npassed, nb);
1094 /* return verifyrule(L, sib2(tree), passed, npassed, nb); */ 1082 /* return verifyrule(L, sib2(tree), passed, npassed, nb); */
1095 tree = sib2(tree); goto tailcall; 1083 tree = sib2(tree); goto tailcall;
@@ -1342,7 +1330,6 @@ static struct luaL_Reg pattreg[] = {
1342 {"setmaxstack", lp_setmax}, 1330 {"setmaxstack", lp_setmax},
1343 {"type", lp_type}, 1331 {"type", lp_type},
1344 {"T", lp_throw}, /* labeled failure throw */ 1332 {"T", lp_throw}, /* labeled failure throw */
1345 {"Lc", lp_labchoice}, /* labeled failure choice */
1346 {"Rec", lp_recovery}, /* labeled failure choice */ 1333 {"Rec", lp_recovery}, /* labeled failure choice */
1347 {NULL, NULL} 1334 {NULL, NULL}
1348}; 1335};
diff --git a/lptree.h b/lptree.h
index cca346e..b75f323 100644
--- a/lptree.h
+++ b/lptree.h
@@ -25,7 +25,7 @@ typedef enum TTag {
25 TBehind, /* match behind */ 25 TBehind, /* match behind */
26 TCapture, /* regular capture */ 26 TCapture, /* regular capture */
27 TRunTime, /* run-time capture */ 27 TRunTime, /* run-time capture */
28 TThrow, TLabChoice, TRecov /* labeled failure */ 28 TThrow, TRecov /* labeled failure */
29} TTag; 29} TTag;
30 30
31/* number of siblings for each tree */ 31/* number of siblings for each tree */
diff --git a/lpvm.c b/lpvm.c
index b200dce..122c8f4 100644
--- a/lpvm.c
+++ b/lpvm.c
@@ -274,17 +274,6 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
274 p += 2; 274 p += 2;
275 continue; 275 continue;
276 } 276 }
277 case ILabChoice: { /* labeled failure */
278 if (stack == stacklimit)
279 stack = doublestack(L, &stacklimit, ptop);
280 stack->p = p + getoffset(p);
281 stack->s = s;
282 stack->ls = (const Labelset *) ((p + 2)->buff);
283 stack->caplevel = captop;
284 stack++;
285 p += (CHARSETINSTSIZE - 1) + 2;
286 continue;
287 }
288 case IRecov: { /* labeled failure */ 277 case IRecov: { /* labeled failure */
289 if (stack == stacklimit) 278 if (stack == stacklimit)
290 stack = doublestack(L, &stacklimit, ptop); 279 stack = doublestack(L, &stacklimit, ptop);
diff --git a/lpvm.h b/lpvm.h
index 3c27027..bcfc22f 100644
--- a/lpvm.h
+++ b/lpvm.h
@@ -35,7 +35,6 @@ typedef enum Opcode {
35 ICloseCapture, 35 ICloseCapture,
36 ICloseRunTime, 36 ICloseRunTime,
37 IThrow, /* "fails" with a specific label labeled failure */ 37 IThrow, /* "fails" with a specific label labeled failure */
38 ILabChoice, /* labeled choice */
39 IRecov /* stack a recovery; next fail with label 'f' will jump to 'offset' */ 38 IRecov /* stack a recovery; next fail with label 'f' will jump to 'offset' */
40} Opcode; 39} Opcode;
41 40
diff --git a/relabel.lua b/relabelrec.lua
index 0e7195e..16ca7f0 100644
--- a/relabel.lua
+++ b/relabelrec.lua
@@ -82,15 +82,9 @@ for i, err in ipairs(errinfo) do
82 labels[err[1]] = i 82 labels[err[1]] = i
83end 83end
84 84
85local syntaxerrs = {}
86
87local function expect (pattern, labelname) 85local function expect (pattern, labelname)
88 local label = labels[labelname] 86 local label = labels[labelname]
89 local record = function (input, pos) 87 return pattern + m.T(label)
90 tinsert(syntaxerrs, { label = label, pos = pos })
91 return true
92 end
93 return pattern + m.Cmt("", record) * m.T(label)
94end 88end
95 89
96 90
@@ -222,86 +216,34 @@ local function NT (n, b)
222 end 216 end
223end 217end
224 218
225local function labchoice (...) 219local function choicerec (...)
226 local t = { ... } 220 local t = { ... }
227 local n = #t 221 local n = #t
228 local p = t[1] 222 local p = t[1]
229 local i = 2 223 local i = 2
230 while i + 1 <= n do 224 while i + 1 <= n do
231 -- t[i] == nil when there are no labels 225 -- t[i] == nil when there are no labels
232 p = t[i] and mm.Lc(p, t[i+1], unpack(t[i])) or mt.__add(p, t[i+1]) 226 p = t[i] and mm.Rec(p, t[i+1], unpack(t[i])) or mt.__add(p, t[i+1])
233 i = i + 2 227 i = i + 2
234 end 228 end
235 229
236 return p 230 return p
237end 231end
238 232
239-- error recovery
240local skip = m.P { "Skip",
241 Skip = (-m.P"/" * -m.P(name * arrow) * m.V"Ignored")^0 * m.Cc(dummy);
242 Ignored = m.V"Group" + any;
243 Group = "(" * (-m.P")" * m.V"Ignored")^0 * ")"
244 + "{" * (-m.P"}" * m.V"Ignored")^0 * "}"
245 + "[" * (-m.P"]" * m.V"Ignored")^0 * "]"
246 + "'" * (-m.P"'" * m.V"Ignored")^0 * "'"
247 + '"' * (-m.P'"' * m.V"Ignored")^0 * '"';
248}
249
250local ignore = m.Cmt(any, function (input, pos)
251 return syntaxerrs[#syntaxerrs].pos, dummy
252end)
253
254local pointAtStart = m.Cmt(any, function (input, pos)
255 -- like ignore but makes the last syntax error point at the start
256 local ret = syntaxerrs[#syntaxerrs].pos
257 syntaxerrs[#syntaxerrs].pos = pos-1
258 return ret, dummy
259end)
260
261
262local function labify (labelnames)
263 for i, l in ipairs(labelnames) do
264 labelnames[i] = labels[l]
265 end
266 return labelnames
267end
268
269local labelset1 = labify {
270 "ExpPatt2", "ExpPatt3",
271 "ExpPatt4", "ExpPatt5", "ExpPatt6", "ExpPatt7",
272 "ExpPatt8", "ExpPattOrClose",
273 "ExpNum", "ExpCap",
274 "ExpName1", "ExpName2", "ExpName3",
275 "ExpNameOrLab", "ExpItem",
276 "MisClose6", "MisClose7"
277}
278
279local labelset2 = labify {
280 "MisClose1", "MisClose2", "MisClose3", "MisClose4", "MisClose5"
281}
282
283local labelset3 = labify {
284 "ExpPatt1", "ExpLab1", "ExpLab2", "MisClose7"
285}
286
287local exp = m.P{ "Exp", 233local exp = m.P{ "Exp",
288 Exp = S * ( m.V"Grammar" 234 Exp = S * ( m.V"Grammar"
289 + (m.V"RecovSeq" * (S * "/" * m.Lc((m.Ct(m.V"Labels") + m.Cc(nil)) 235 + (m.V"Seq" * (S * (("//" * m.Ct(m.V"Labels")) + ("/" * m.Cc(nil)))
290 * expect(S * m.V"RecovSeq", 236 * expect(S * m.V"Seq", "ExpPatt1")
291 "ExpPatt1"),
292 m.Cc(nil) * skip,
293 unpack(labelset3))
294 )^0 237 )^0
295 ) / labchoice); 238 ) / choicerec);
296 Labels = m.P"{" * expect(S * m.V"Label", "ExpLab1") 239 Labels = m.P"{" * expect(S * m.V"Label", "ExpLab1")
297 * (S * "," * expect(S * m.V"Label", "ExpLab2"))^0 240 * (S * "," * expect(S * m.V"Label", "ExpLab2"))^0
298 * expect(S * "}", "MisClose7"); 241 * expect(S * "}", "MisClose7");
299 RecovSeq = m.Lc(m.V"Seq", skip, unpack(labelset1));
300 Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix" * (S * m.V"Prefix")^0, mt.__mul); 242 Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix" * (S * m.V"Prefix")^0, mt.__mul);
301 Prefix = "&" * expect(S * m.V"Prefix", "ExpPatt2") / mt.__len 243 Prefix = "&" * expect(S * m.V"Prefix", "ExpPatt2") / mt.__len
302 + "!" * expect(S * m.V"Prefix", "ExpPatt3") / mt.__unm 244 + "!" * expect(S * m.V"Prefix", "ExpPatt3") / mt.__unm
303 + m.V"Suffix"; 245 + m.V"Suffix";
304 Suffix = m.Cf(m.V"RecovPrimary" * 246 Suffix = m.Cf(m.V"Primary" *
305 ( S * ( m.P"+" * m.Cc(1, mt.__pow) 247 ( S * ( m.P"+" * m.Cc(1, mt.__pow)
306 + m.P"*" * m.Cc(0, mt.__pow) 248 + m.P"*" * m.Cc(0, mt.__pow)
307 + m.P"?" * m.Cc(-1, mt.__pow) 249 + m.P"?" * m.Cc(-1, mt.__pow)
@@ -318,13 +260,13 @@ local exp = m.P{ "Exp",
318 "ExpName1") 260 "ExpName1")
319 ) 261 )
320 )^0, function (a,b,f) return f(a,b) end ); 262 )^0, function (a,b,f) return f(a,b) end );
321 RecovPrimary = m.Lc(m.V"Primary", ignore, unpack(labelset2));
322 Primary = "(" * expect(m.V"Exp", "ExpPatt4") * expect(S * ")", "MisClose1") 263 Primary = "(" * expect(m.V"Exp", "ExpPatt4") * expect(S * ")", "MisClose1")
323 + m.Lc(String / mm.P, pointAtStart, 264 + String / mm.P
324 labels["MisTerm1"], labels["MisTerm2"]) 265 + Class
325 + m.Lc(Class, pointAtStart, labels["MisClose8"])
326 + defined 266 + defined
327 + "%" * expect(m.V"Labels", "ExpNameOrLab") / mm.T 267 + "%" * expect(m.P"{", "ExpNameOrLab")
268 * expect(S * m.V"Label", "ExpLab1")
269 * expect(S * "}", "MisClose7") / mm.T
328 + "{:" * (name * ":" + m.Cc(nil)) * expect(m.V"Exp", "ExpPatt5") 270 + "{:" * (name * ":" + m.Cc(nil)) * expect(m.V"Exp", "ExpPatt5")
329 * expect(S * ":}", "MisClose2") 271 * expect(S * ":}", "MisClose2")
330 / function (n, p) return mm.Cg(p, n) end 272 / function (n, p) return mm.Cg(p, n) end
@@ -374,23 +316,20 @@ local function compile (p, defs)
374 if mm.type(p) == "pattern" then return p end -- already compiled 316 if mm.type(p) == "pattern" then return p end -- already compiled
375 p = p .. " " -- for better reporting of column numbers in errors when at EOF 317 p = p .. " " -- for better reporting of column numbers in errors when at EOF
376 local ok, cp, label, suffix = pcall(function() return pattern:match(p, 1, defs) end) 318 local ok, cp, label, suffix = pcall(function() return pattern:match(p, 1, defs) end)
377 if not ok and #syntaxerrs == 0 then 319 if not ok and cp then
378 if type(cp) == "string" then 320 if type(cp) == "string" then
379 cp = cp:gsub("^[^:]+:[^:]+: ", "") 321 cp = cp:gsub("^[^:]+:[^:]+: ", "")
380 end 322 end
381 error(cp, 3) 323 error(cp, 3)
382 end 324 end
383 if #syntaxerrs > 0 then 325 if not cp then
384 local lines = splitlines(p) 326 local lines = splitlines(p)
385 local errors = {} 327 local line, col = lineno(p, #p - #suffix + 1)
386 for i, err in ipairs(syntaxerrs) do 328 local err = {}
387 local line, col = lineno(p, err.pos) 329 tinsert(err, "L" .. line .. ":C" .. col .. ": " .. errmsgs[label])
388 tinsert(errors, "L" .. line .. ":C" .. col .. ": " .. errmsgs[err.label]) 330 tinsert(err, lines[line])
389 tinsert(errors, lines[line]) 331 tinsert(err, rep(" ", col-1) .. "^")
390 tinsert(errors, rep(" ", col-1) .. "^") 332 error("syntax error(s) in pattern\n" .. concat(err, "\n"), 3)
391 end
392 syntaxerrs = {}
393 error("syntax error(s) in pattern\n" .. concat(errors, "\n"), 3)
394 end 333 end
395 return cp 334 return cp
396end 335end
diff --git a/test.lua b/test.lua
index fc2b607..18ab20f 100755
--- a/test.lua
+++ b/test.lua
@@ -1110,7 +1110,7 @@ checkeq(t, {'a', 'aa', 20, 'a', 'aaa', 'aaa'})
1110-- Tests for 're' module 1110-- Tests for 're' module
1111------------------------------------------------------------------- 1111-------------------------------------------------------------------
1112 1112
1113local re = require "relabel" 1113local re = require "relabelrec"
1114 1114
1115local match, compile = re.match, re.compile 1115local match, compile = re.match, re.compile
1116 1116
diff --git a/testlabel.lua b/testlabel.lua
index 25036b2..cb92657 100644
--- a/testlabel.lua
+++ b/testlabel.lua
@@ -11,6 +11,15 @@ local function checkeqlab (x, ...)
11 end 11 end
12end 12end
13 13
14local function checkeq (x, y, p)
15if p then print(x,y) end
16 if type(x) ~= "table" then assert(x == y)
17 else
18 for k,v in pairs(x) do checkeq(v, y[k], p) end
19 for k,v in pairs(y) do checkeq(v, x[k], p) end
20 end
21end
22
14-- throws a label 23-- throws a label
15p = m.T(1) 24p = m.T(1)
16s = "abc" 25s = "abc"
@@ -32,48 +41,97 @@ local g = m.P{
32r, l, serror = g:match(s) 41r, l, serror = g:match(s)
33assert(r == nil and l == 1 and serror == "abc") 42assert(r == nil and l == 1 and serror == "abc")
34 43
35--[==[ TODO: labeled choice does not work anymore 44
36-- throws a label that is not caught by labeled choice 45-- throws a label that is not caught by the recovery operator
37p = m.Lc(m.T(2), m.P"a", 1, 3) 46p = m.Rec(m.T(2), m.P"a", 1, 3)
38r, l, serror = p:match(s) 47r, l, serror = p:match(s)
39assert(r == nil and l == 2 and serror == "abc") 48assert(r == nil and l == 2 and serror == "abc")
40 49
41-- modifies previous pattern 50-- wraps the previous pattern with a recovery that catches label "2"
42-- adds another labeled choice to catch label "2" 51p = m.Rec(p, m.P"a", 2)
43p = m.Lc(p, m.P"a", 2)
44assert(p:match(s) == 2) 52assert(p:match(s) == 2)
45 53
46-- throws a label that is caught by labeled choice 54-- throws a label that is caught by recovery
47p = m.Lc(m.T(25), m.P"a", 25) 55p = m.Rec(m.T(25), m.P"a", 25)
48assert(p:match(s) == 2) 56assert(p:match(s) == 2)
49 57
50-- "fail" is label "0" 58-- "fail" is label "0"
51-- throws the "fail" label that is not caught by the labeled choice 59-- throws the "fail" label after the recovery
52s = "bola" 60s = "bola"
53r, l, serror = p:match("bola") 61r, l, serror = p:match("bola")
54assert(r == nil and l == 0 and serror == "bola") 62assert(r == nil and l == 0 and serror == "bola")
55 63
56-- labeled choice does not catch "fail" by default 64-- Recovery does not catch "fail" by default
57p = m.Lc(m.P"b", m.P"a", 1) 65p = m.Rec(m.P"b", m.P"a", 1)
58 66
59r, l, serror = p:match("abc") 67r, l, serror = p:match("abc")
60assert(r == nil and l == 0 and serror == "abc") 68assert(r == nil and l == 0 and serror == "abc")
61 69
62assert(p:match("bola") == 2) 70assert(p:match("bola") == 2)
63 71
64-- labeled choice can catch "fail" 72
65p = m.Lc(m.P"b", m.P"a", 0) 73-- recovery operator catches "1" or "3"
74p = m.Rec((m.P"a" + m.T(1)) * m.T(3), (m.P"a" + m.P"b"), 1, 3)
75assert(p:match("aac") == 3)
76assert(p:match("abc") == 3)
77r, l, serror = p:match("acc")
78assert(r == nil and l == 0 and serror == "cc")
79
80--throws 1, recovery pattern matches 'b', throw 3, and rec pat mathces 'a'
81assert(p:match("bac") == 3)
82
83r, l, serror = p:match("cab")
84assert(r == nil and l == 0 and serror == "cab")
85
86
87-- associativity
88-- (p1 / %1) //{1} (p2 / %2) //{2} p3
89-- left-associativity
90-- ("a" //{1} "b") //{2} "c"
91p = m.Rec(m.Rec(m.P"a" + m.T(1), m.P"b" + m.T(2), 1), m.P"c", 2)
66assert(p:match("abc") == 2) 92assert(p:match("abc") == 2)
67assert(p:match("bola") == 2) 93assert(p:match("bac") == 2)
94assert(p:match("cab") == 2)
95r, l, serror = p:match("dab")
96assert(r == nil and l == 0 and serror == "dab")
68 97
69-- "fail" is label "0" 98
70-- labeled choice catches "fail" or "3" 99-- righ-associativity
71p = m.Lc(m.P"a" * m.T(3), (m.P"a" + m.P"b"), 0, 3) 100-- "a" //{1} ("b" //{2} "c")
101p = m.Rec(m.P"a" + m.T(1), m.Rec(m.P"b" + m.T(2), m.P"c", 2), 1)
72assert(p:match("abc") == 2) 102assert(p:match("abc") == 2)
73assert(p:match("bac") == 2) 103assert(p:match("bac") == 2)
104assert(p:match("cab") == 2)
105r, l, serror = p:match("dab")
106assert(r == nil and l == 0 and serror == "dab")
107
108
109-- associativity -> in this case the error thrown by p1 is only
110-- recovered when we have a left-associative operator
111-- (p1 / %2) //{1} (p2 / %2) //{2} p3
112-- left-associativity
113-- ("a" //{1} "b") //{2} "c"
114p = m.Rec(m.Rec(m.P"a" + m.T(2), m.P"b" + m.T(2), 1), m.P"c", 2)
115assert(p:match("abc") == 2)
116r, l, serror = p:match("bac")
117assert(r == nil and l == 0 and serror == "bac")
118assert(p:match("cab") == 2)
119r, l, serror = p:match("dab")
120assert(r == nil and l == 0 and serror == "dab")
121
74 122
123-- righ-associativity
124-- "a" //{1} ("b" //{2} "c")
125p = m.Rec(m.P"a" + m.T(2), m.Rec(m.P"b" + m.T(2), m.P"c", 2), 1)
126assert(p:match("abc") == 2)
127r, l, serror = p:match("bac")
128assert(r == nil and l == 2 and serror == "bac")
75r, l, serror = p:match("cab") 129r, l, serror = p:match("cab")
76assert(r == nil and l == 0 and serror == "cab") 130assert(r == nil and l == 2 and serror == "cab")
131r, l, serror = p:match("dab")
132assert(r == nil and l == 2 and serror == "dab")
133
134
77 135
78-- tests related to predicates 136-- tests related to predicates
79p = #m.T(1) + m.P"a" 137p = #m.T(1) + m.P"a"
@@ -84,74 +142,66 @@ p = ##m.T(1) + m.P"a"
84r, l, serror = p:match("abc") 142r, l, serror = p:match("abc")
85assert(r == nil and l == 1 and serror == "abc") 143assert(r == nil and l == 1 and serror == "abc")
86 144
87p = #m.T(0) * m.P"a"
88assert(p:match("abc") == fail)
89
90p = #m.T(0) + m.P"a"
91assert(p:match("abc") == 2)
92
93p = -m.T(1) * m.P"a" 145p = -m.T(1) * m.P"a"
94r, l, serror = p:match("abc") 146r, l, serror = p:match("abc")
95assert(r == nil and l == 1 and serror == "abc") 147assert(r == nil and l == 1 and serror == "abc")
96 148
149p = -m.T(1) * m.P"a"
150r, l, serror = p:match("bbc")
151assert(r == nil and l == 1 and serror == "bbc")
152
97p = -(-m.T(1)) * m.P"a" 153p = -(-m.T(1)) * m.P"a"
98r, l, serror = p:match("abc") 154r, l, serror = p:match("abc")
99assert(r == nil and l == 1 and serror == "abc") 155assert(r == nil and l == 1 and serror == "abc")
100 156
101p = -m.T(0) * m.P"a" 157p = m.Rec(-m.T(22), m.P"a", 22)
102assert(p:match("abc") == 2) 158r, l, serror = p:match("abc")
159assert(r == nil and l == 0 and serror == "bc")
103 160
104p = -m.T(0) + m.P"a" 161assert(p:match("bbc") == 1)
105assert(p:match("abc") == 1)
106 162
107p = -(-m.T(0)) + m.P"a" 163p = m.Rec(#m.T(22), m.P"a", 22)
108assert(p:match("abc") == 2) 164assert(p:match("abc") == 1)
109 165
110p = m.Lc(-m.T(22), m.P"a", 22) 166p = #m.Rec(m.T(22), m.P"a", 22)
111assert(p:match("abc") == 2) 167assert(p:match("abc") == 1)
112 168
113p = m.Lc(-m.T(0), m.P"a", 0) 169p = m.Rec(m.T(22), #m.P"a", 22)
114assert(p:match("abc") == 1) 170assert(p:match("abc") == 1)
115 171
116p = m.Lc(#m.T(22), m.P"a", 22) 172p = m.Rec(#m.T(22), m.P"a", 22)
117assert(p:match("abc") == 2) 173r, l, serror = p:match("bbc")
174assert(r == nil and l == 0 and serror == "bbc")
118 175
119p = m.Lc(#m.T(0), m.P"a", 0)
120assert(p:match("abc") == 2)
121 176
122-- tests related to repetition 177-- tests related to repetition
123p = m.T(1)^0 178p = m.T(1)^0
124r, l, serror = p:match("ab") 179r, l, serror = p:match("ab")
125assert(r == nil and l == 1 and serror == "ab") 180assert(r == nil and l == 1 and serror == "ab")
126 181
127p = m.T(0)^0
128assert(p:match("ab") == 1)
129
130p = (m.P"a" + m.T(1))^0 182p = (m.P"a" + m.T(1))^0
131r, l, serror = p:match("aa") 183r, l, serror = p:match("aa")
132assert(r == nil and l == 1 and serror == "") 184assert(r == nil and l == 1 and serror == "")
133 185
134p = (m.P"a" + m.T(0))^0
135assert(p:match("aa") == 3)
136 186
137-- Bug reported by Matthew Allen 187-- Bug reported by Matthew Allen
138-- some optmizations performed by LPeg should not be 188-- some optmizations performed by LPeg should not be
139-- applied in case of labeled choices 189-- applied in case of labeled choices
140p = m.Lc(m.P"A", m.P(true), 1) + m.P("B") 190p = m.Rec(m.P"A", m.P(true), 1) + m.P("B")
141assert(p:match("B") == 2) 191assert(p:match("B") == 2)
142 192
143p = m.Lc(m.P"A", m.P(false), 1) + m.P("B") 193p = m.Rec(m.P"A", m.P(false), 1) + m.P("B")
144assert(p:match("B") == 2) 194assert(p:match("B") == 2)
145 195
146 196
147--[[ 197--[[
148S -> A /{1} 'a' 198S -> A //{1} 'a'
149A -> B 199A -> B
150B -> %1 200B -> %1
151]] 201]]
152g = m.P{ 202g = m.P{
153 "S", 203 "S",
154 S = m.Lc(m.V"A", m.P"a", 1), 204 S = m.Rec(m.V"A", m.P"a", 1),
155 A = m.V"B", 205 A = m.V"B",
156 B = m.T(1), 206 B = m.T(1),
157} 207}
@@ -177,66 +227,96 @@ r, l, serror = g:match("a;a")
177assert(r == nil and l == 1 and serror == "") 227assert(r == nil and l == 1 and serror == "")
178 228
179 229
180-- %1 /{1,3} %2 /{2} 'a' 230-- %1 //{1,3} %2 //{2} 'a'
181p = m.Lc(m.Lc(m.T(1), m.T(2), 1, 3), m.P"a", 2) 231p = m.Rec(m.Rec(m.T(1), m.T(2), 1, 3), m.P"a", 2)
182assert(p:match("abc") == 2) 232assert(p:match("abc") == 2)
183 233
184r, l, serror = p:match("") 234r, l, serror = p:match("")
185assert(r == nil and l == 0 and serror == "") 235assert(r == nil and l == 0 and serror == "")
186 236
187p = m.Lc(m.T(1), m.Lc(m.T(2), m.P"a", 2), 1, 3) 237p = m.Rec(m.T(1), m.Rec(m.T(2), m.P"a", 2), 1, 3)
188assert(p:match("abc") == 2) 238assert(p:match("abc") == 2)
189 239
190r, l, serror = p:match("") 240r, l, serror = p:match("")
191assert(r == nil and l == 0 and serror == "") 241assert(r == nil and l == 0 and serror == "")
192]==] 242
243
244-- Infinte Loop TODO: check the semantics
245-- %1 //{1} %1
246p = m.Rec(m.T(1), m.T(1), 1)
247--r, l, serror = p:match("ab")
248--assert(r == nil and l == 1 and serror == "ab")
249
250-- %1 //{1} 'a' (!. / %1)
251p = m.Rec(m.T(1), m.P"a" * (-m.P(1) + m.T(1)), 1)
252r, l, serror = p:match("ab")
253assert(r == nil and l == 0 and serror == "b")
254
255r, l, serror = p:match("cd")
256assert(r == nil and l == 0 and serror == "cd")
257
258-- %1 //{1} . (!. / %1)
259p = m.Rec(m.T(1), m.P(1) * (-m.P(1) + m.T(1)), 1)
260assert(p:match("abc") == 4)
261
193 262
194-- testing the limit of labels 263-- testing the limit of labels
195p = m.T(0) 264-- can only throw labels between 1 and 255
196s = "abc" 265local r = pcall(m.Rec, m.P"b", m.P"a", 0)
197r, l, serror = p:match(s) 266assert(r == false)
198assert(r == nil and l == 0 and serror == "abc")
199 267
200p = m.T(255) 268local r = pcall(m.Rec, m.P"b", m.P"a", 256)
201s = "abc" 269assert(r == false)
202r, l, serror = p:match(s)
203assert(r == nil and l == 255 and serror == "abc")
204 270
205local r = pcall(m.T, -1) 271local r = pcall(m.Rec, m.P"b", m.P"a", -1)
272assert(r == false)
273
274local r = pcall(m.T, 0)
206assert(r == false) 275assert(r == false)
207 276
208local r = pcall(m.T, 256) 277local r = pcall(m.T, 256)
209assert(r == false) 278assert(r == false)
210 279
280local r = pcall(m.T, -1)
281assert(r == false)
282
283
284local r = m.Rec(m.P"b", m.P"a", 255)
285assert(p:match("a") == 2)
286
287p = m.T(255)
288s = "abc"
289r, l, serror = p:match(s)
290assert(r == nil and l == 255 and serror == "abc")
291
292
211 293
212print("+") 294print("+")
213 295
214--[==[ TODO: labeled choice does not work anymore
215--[[ grammar based on Figure 8 of paper submitted to SCP 296--[[ grammar based on Figure 8 of paper submitted to SCP
216S -> S0 /{1} ID /{2} ID '=' Exp /{3} 'unsigned'* 'int' ID /{4} 'unsigned'* ID ID / %error 297S -> S0 //{1} ID //{2} ID '=' Exp //{3} 'unsigned'* 'int' ID //{4} 'unsigned'* ID ID / %error
217S0 -> ID S1 / 'unsigned' S2 / 'int' %3 298S0 -> S1 / S2 / &'int' %3
218S1 -> '=' %2 / !. %1 / ID %4 299S1 -> &(ID '=') %2 / &(ID !.) %1 / &ID %4
219S2 -> 'unsigned' S2 / ID %4 / 'int' %3 300S2 -> &('unsigned'+ ID) %4 / & ('unsigned'+ 'int') %3
220]] 301]]
221
222local sp = m.S" \t\n"^0 302local sp = m.S" \t\n"^0
223local eq = sp * m.P"=" 303local eq = sp * m.P"="
224 304
225g = m.P{ 305g = m.P{
226 "S", 306 "S",
227 S = m.Lc( 307 S = m.Rec(
228 m.Lc( 308 m.Rec(
229 m.Lc( 309 m.Rec(
230 m.Lc(m.V"S0", m.V"ID" * (m.P(1) + ""), 1), 310 m.Rec(m.V"S0", m.V"ID", 1),
231 m.V"ID" * eq * m.V"Exp", 2 311 m.V"ID" * eq * m.V"Exp", 2
232 ), 312 ),
233 m.V"U"^0 * m.V"I" * m.V"ID", 3 313 m.V"U"^0 * m.V"I" * m.V"ID", 3
234 ), 314 ),
235 m.V"U"^0 * m.V"ID" * m.V"ID", 4) 315 m.V"U"^0 * m.V"ID" * m.V"ID", 4)
236 + m.T(5), -- error 316 + m.T(5), -- error
237 S0 = m.V"ID" * m.V"S1" + m.V"U" * m.V"S2" + m.V"I" * m.T(3), 317 S0 = m.V"S1" + m.V"S2" + #m.V"I" * m.T(3),
238 S1 = eq * m.T(2) + sp * -m.P(1) * m.T(1) + m.V"ID" * m.T(4), 318 S1 = #(m.V"ID" * eq) * m.T(2) + sp * #(m.V"ID" * -m.P(1)) * m.T(1) + #m.V"ID" * m.T(4),
239 S2 = m.V"U" * m.V"S2" + m.V"ID" * m.T(4) + m.V"I" * m.T(3), 319 S2 = #(m.V"U"^1 * m.V"ID") * m.T(4) + #(m.V"U"^1 * m.V"I") * m.T(3),
240 ID = sp * m.P"a", 320 ID = sp * m.P"a",
241 U = sp * m.P"unsigned", 321 U = sp * m.P"unsigned",
242 I = sp * m.P"int", 322 I = sp * m.P"int",
@@ -273,53 +353,59 @@ assert(r == nil and l == 5 and serror == s)
273 353
274print("+") 354print("+")
275 355
276local re = require 'relabel'
277 356
278g = re.compile[['a' /{4,9} [a-z] 357local re = require 'relabelrec'
358
359g = re.compile[['a' //{4,9} [a-z]
279]] 360]]
280assert(g:match("a") == 2) 361assert(g:match("a") == 2)
281r, l, serror = g:match("b") 362r, l, serror = g:match("b")
282assert(r == nil and l == 0 and serror == "b") 363assert(r == nil and l == 0 and serror == "b")
283 364
284g = re.compile[['a' /{4,9} [a-f] /{5, 7} [a-z] 365g = re.compile[['a' //{4,9} [a-f] //{5, 7} [a-z]
285]] 366]]
286assert(g:match("a") == 2) 367assert(g:match("a") == 2)
287r, l, serror = g:match("b") 368r, l, serror = g:match("b")
288assert(r == nil and l == 0 and serror == "b") 369assert(r == nil and l == 0 and serror == "b")
289 370
290g = re.compile[[%{1} /{4,9} [a-z] 371g = re.compile[[%{1} //{4,9} [a-z]
291]] 372]]
292r, l, serror = g:match("a") 373r, l, serror = g:match("a")
293assert(r == nil and l == 1 and serror == "a") 374assert(r == nil and l == 1 and serror == "a")
294 375
295 376
296g = re.compile[[%{1} /{4,1} [a-f] 377g = re.compile[[%{1} //{4,1} [a-f]
297]] 378]]
298assert(g:match("a") == 2) 379assert(g:match("a") == 2)
299r, l, serror = g:match("h") 380r, l, serror = g:match("h")
300assert(r == nil and l == 0 and serror == "h") 381assert(r == nil and l == 0 and serror == "h")
301 382
302g = re.compile[[[a-f]%{9} /{4,9} [a-c]%{7} /{5, 7} [a-z] ]] 383g = re.compile[[[a-f]%{9} //{4,9} [a-c]%{7} //{5, 7} [a-z] ]]
303assert(g:match("a") == 2) 384r, l, serror = g:match("a")
304assert(g:match("c") == 2) 385assert(r == nil and l == 0 and serror == "")
305r, l, serror = g:match("d") 386r, l, serror = g:match("aa")
387assert(r == nil and l == 0 and serror == "")
388assert(g:match("aaa") == 4)
389
390r, l, serror = g:match("ad")
306assert(r == nil and l == 0 and serror == "d") 391assert(r == nil and l == 0 and serror == "d")
392
307r, l, serror = g:match("g") 393r, l, serror = g:match("g")
308assert(r == nil and l == 0 and serror == "g") 394assert(r == nil and l == 0 and serror == "g")
309 395
396
310--[[ grammar based on Figure 8 of paper submitted to SCP 397--[[ grammar based on Figure 8 of paper submitted to SCP
311S -> S0 /{1} ID /{2} ID '=' Exp /{3} 'unsigned'* 'int' ID /{4} 'unsigned'* ID ID / %error 398S -> S0 //{1} ID //{2} ID '=' Exp //{3} 'unsigned'* 'int' ID //{4} 'unsigned'* ID ID / %error
312S0 -> ID S1 / 'unsigned' S2 / 'int' %3 399S0 -> S1 / S2 / &'int' %3
313S1 -> '=' %2 / !. %1 / ID %4 400S1 -> &(ID '=') %2 / &(ID !.) %1 / &ID %4
314S2 -> 'unsigned' S2 / ID %4 / 'int' %3 401S2 -> &('unsigned'+ ID) %4 / & ('unsigned'+ 'int') %3
315]] 402]]
316 403
317
318g = re.compile([[ 404g = re.compile([[
319 S <- S0 /{1} ID /{2} ID %s* '=' Exp /{3} U* Int ID /{4} U ID ID /{0} %{5} 405 S <- S0 //{1} ID //{2} ID %s* '=' Exp //{3} U* Int ID //{4} U ID ID / %{5}
320 S0 <- ID S1 / U S2 / Int %{3} 406 S0 <- S1 / S2 / &Int %{3}
321 S1 <- %s* '=' %{2} / !. %{1} / ID %{4} 407 S1 <- &(ID %s* '=') %{2} / &(ID !.) %{1} / &ID %{4}
322 S2 <- U S2 / ID %{4} / Int %{3} 408 S2 <- &(U+ ID) %{4} / &(U+ Int) %{3}
323 ID <- %s* 'a' 409 ID <- %s* 'a'
324 U <- %s* 'unsigned' 410 U <- %s* 'unsigned'
325 Int <- %s* 'int' 411 Int <- %s* 'int'
@@ -349,6 +435,8 @@ s = "unsigned int"
349r, l, serror = g:match(s) 435r, l, serror = g:match(s)
350assert(r == nil and l == 5 and serror == s) 436assert(r == nil and l == 5 and serror == s)
351 437
438
439
352local terror = { ['cmdSeq'] = "Missing ';' in CmdSeq", 440local terror = { ['cmdSeq'] = "Missing ';' in CmdSeq",
353 ['ifExp'] = "Error in expresion of 'if'", 441 ['ifExp'] = "Error in expresion of 'if'",
354 ['ifThen'] = "Error matching 'then' keyword", 442 ['ifThen'] = "Error matching 'then' keyword",
@@ -370,12 +458,12 @@ local terror = { ['cmdSeq'] = "Missing ';' in CmdSeq",
370 ['undefined'] = "Undefined Error"} 458 ['undefined'] = "Undefined Error"}
371 459
372g = re.compile([[ 460g = re.compile([[
373 Tiny <- CmdSeq /{1} '' -> cmdSeq /{2} '' -> ifExp /{3} '' -> ifThen /{4} '' -> ifThenCmdSeq 461 Tiny <- CmdSeq //{1} '' -> cmdSeq //{2} '' -> ifExp //{3} '' -> ifThen //{4} '' -> ifThenCmdSeq
374 /{5} '' -> ifElseCmdSeq /{6} '' -> ifEnd /{7} '' -> repeatCmdSeq 462 //{5} '' -> ifElseCmdSeq //{6} '' -> ifEnd //{7} '' -> repeatCmdSeq
375 /{8} '' -> repeatUntil /{9} '' -> repeatExp /{10} '' -> assignOp 463 //{8} '' -> repeatUntil //{9} '' -> repeatExp //{10} '' -> assignOp
376 /{11} '' -> assignExp /{12} '' -> readName /{13} '' -> writeExp 464 //{11} '' -> assignExp //{12} '' -> readName //{13} '' -> writeExp
377 /{14} '' -> simpleExp /{15} '' -> term /{16} '' -> factor 465 //{14} '' -> simpleExp //{15} '' -> term //{16} '' -> factor
378 /{17} '' -> openParExp /{18} '' -> closePar /{0} '' -> undefined 466 //{17} '' -> openParExp //{18} '' -> closePar / '' -> undefined
379 CmdSeq <- (Cmd (SEMICOLON / %{1})) (Cmd (SEMICOLON / %{1}))* 467 CmdSeq <- (Cmd (SEMICOLON / %{1})) (Cmd (SEMICOLON / %{1}))*
380 Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd 468 Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd
381 IfCmd <- IF (Exp / %{2}) (THEN / %{3}) (CmdSeq / %{4}) (ELSE (CmdSeq / %{5}) / '') (END / %{6}) 469 IfCmd <- IF (Exp / %{2}) (THEN / %{3}) (CmdSeq / %{4}) (ELSE (CmdSeq / %{5}) / '') (END / %{6})
@@ -551,21 +639,14 @@ assert(g:match(s) == terror['undefined'])
551 639
552 640
553print("+") 641print("+")
554]==]
555 642
556-- test recovery operator
557p = m.Rec("a", "b")
558assert(p:match("a") == 2)
559--assert(p:match("b") == 2)
560checkeqlab({nil, 0, "b"}, p:match("b"))
561checkeqlab({nil, 0, "c"}, p:match("c"))
562 643
563p = m.Rec("a", "b", 3) 644p = m.Rec("a", "b", 3)
564assert(p:match("a") == 2) 645assert(p:match("a") == 2)
565checkeqlab({nil, 0, "b"}, p:match("b")) 646checkeqlab({nil, 0, "b"}, p:match("b"))
566checkeqlab({nil, 0, "c"}, p:match("c")) 647checkeqlab({nil, 0, "c"}, p:match("c"))
567 648
568p = m.Rec(m.T(3), "b") 649p = m.Rec(m.T(3), "b", 1)
569checkeqlab({nil, 3, "a"}, p:match("a")) 650checkeqlab({nil, 3, "a"}, p:match("a"))
570checkeqlab({nil, 3, "b"}, p:match("b")) 651checkeqlab({nil, 3, "b"}, p:match("b"))
571 652
@@ -574,56 +655,26 @@ checkeqlab({nil, 0, "a"}, p:match("a"))
574assert(p:match("b") == 2) 655assert(p:match("b") == 2)
575 656
576--[[ 657--[[
577S -> (A //{fail} (!c .)*) C 658S -> (A //{128} (!c .)*) C
578A -> a*b 659A -> a*b / %128
579C -> c+
580]]
581g = m.P{
582 "S",
583 S = m.Rec(m.V"A", (-m.P"c" * m.P(1))^0) * m.V"C",
584 A = m.P"a"^0 * "b",
585 C = m.P"c"^1,
586}
587
588assert(g:match("abc") == 4)
589assert(g:match("aabc") == 5)
590--assert(g:match("aadc") == 5) --old semantics
591checkeqlab({nil, 0, "dc"}, g:match("aadc")) --new semantics
592assert(g:match("bc") == 3) -- new semantics
593checkeqlab({nil, 0, "bc"}, g:match("bbc"))
594--assert(g:match("xxc") == 4) old semantics
595checkeqlab({nil, 0, "xxc"}, g:match("xxc")) --new semantics
596--assert(g:match("c") == 2) --old semantics
597checkeqlab({nil, 0, "c"}, g:match("c")) --new semantics
598--checkeqlab({nil, 0, ""}, g:match("fail")) --old semantics
599checkeqlab({nil, 0, "fail"}, g:match("fail")) --new semantics
600--checkeqlab({nil, 0, ""}, g:match("aaxx")) --old semantics
601checkeqlab({nil, 0, "xx"}, g:match("aaxx")) --new semantics
602
603
604--[[
605S -> (A //{0} (!c .)*) C
606A -> a*b / ^{0}
607C -> c+ 660C -> c+
608]] 661]]
609g = m.P{ 662g = m.P{
610 "S", 663 "S",
611 S = m.Rec(m.V"A", (-m.P"c" * m.P(1))^0, 0) * m.V"C", --explicitly put 0 in Rec 664 S = m.Rec(m.V"A", (-m.P"c" * m.P(1))^0, 128) * m.V"C",
612 A = m.P"a"^0 * m.P"b" + m.T(0), 665 A = m.P"a"^0 * "b" + m.T(128),
613 C = m.P"c"^1, 666 C = m.P"c"^1,
614} 667}
615 668
616assert(g:match("abc") == 4) 669assert(g:match("abc") == 4)
617assert(g:match("aabc") == 5) 670assert(g:match("aabc") == 5)
618assert(g:match("aadc") == 5) --updated 671assert(g:match("aadc") == 5)
619assert(g:match("bc") == 3) -- new semantics 672assert(g:match("dc") == 3)
620checkeqlab({nil, 0, "bc"}, g:match("bbc")) 673checkeqlab({nil, 0, "bc"}, g:match("bbc"))
621assert(g:match("xxc") == 4) 674assert(g:match("xxc") == 4)
622assert(g:match("c") == 2) --old semantics updated 675assert(g:match("c") == 2)
623checkeqlab({nil, 0, ""}, g:match("fail")) --old semantics updated 676checkeqlab({nil, 0, ""}, g:match("fail"))
624checkeqlab({nil, 0, ""}, g:match("aaxx")) --old semantics updated 677checkeqlab({nil, 0, ""}, g:match("aaxx"))
625
626
627 678
628 679
629--[[ 680--[[
@@ -810,6 +861,120 @@ checkeqlab({nil, 4, "dc"}, g3:match("dc"))
810checkeqlab({nil, 4, "d"}, g3:match(".d")) 861checkeqlab({nil, 4, "d"}, g3:match(".d"))
811 862
812 863
864-- testing more captures
865local g = re.compile[[
866 S <- ( %s* &. {A} )*
867 A <- [0-9]+ / %{5}
868]]
813 869
814print("OK") 870checkeq({"523", "624", "346", "888"} , {g:match("523 624 346\n888")})
871checkeq({nil, 5, "a 123"}, {g:match("44 a 123")})
872
873local g2 = m.Rec(g, ((-m.R("09") * m.P(1))^0) / "58", 5)
874
875checkeq({"523", "624", "346", "888"} , {g2:match("523 624 346\n888")})
876checkeq({"44", "a ", "58", "123"}, {g2:match("44 a 123")})
877
878
879local g = re.compile[[
880 S <- ( %s* &. A )*
881 A <- {[0-9]+} / %{5}
882]]
883
884checkeq({"523", "624", "346", "888"} , {g:match("523 624 346\n888")})
885checkeq({nil, 5, "a 123"}, {g:match("44 a 123")})
886
887local g2 = m.Rec(g, ((-m.R("09") * m.P(1))^0) / "58", 5)
888
889checkeq({"523", "624", "346", "888"} , {g2:match("523 624 346\n888")})
890checkeq({"44", "58", "123"}, {g2:match("44 a 123")})
891
892
893local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V
894local C, Cc, Ct, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt
895local T, Lc, Rec = lpeg.T, lpeg.Lc, lpeg.Rec
896
897local labels = {
898 {"NoExp", "no expression found"},
899 {"Extra", "extra characters found after the expression"},
900 {"ExpTerm", "expected a term after the operator"},
901 {"ExpExp", "expected an expression after the parenthesis"},
902 {"MisClose", "missing a closing ')' after the expression"},
903}
904
905local function labelindex(labname)
906 for i, elem in ipairs(labels) do
907 if elem[1] == labname then
908 return i
909 end
910 end
911 error("could not find label: " .. labname)
912end
913
914local errors = {}
915
916local function expect(patt, labname, recpatt)
917 local i = labelindex(labname)
918 function recorderror(input, pos)
919 table.insert(errors, {i, pos})
920 return true
921 end
922 if not recpatt then recpatt = P"" end
923 --return Rec(patt, Cmt("", recorderror) * recpatt)
924 return patt + T(i)
925end
926
927local num = R("09")^1 / tonumber
928local op = S("+-*/")
929
930local function compute(tokens)
931 local result = tokens[1]
932 for i = 2, #tokens, 2 do
933 if tokens[i] == '+' then
934 result = result + tokens[i+1]
935 elseif tokens[i] == '-' then
936 result = result - tokens[i+1]
937 elseif tokens[i] == '*' then
938 result = result * tokens[i+1]
939 elseif tokens[i] == '/' then
940 result = result / tokens[i+1]
941 else
942 error('unknown operation: ' .. tokens[i])
943 end
944 end
945 return result
946end
815 947
948
949local g = P {
950"Exp",
951Exp = Ct(V"Term" * (C(op) * V"Operand")^0) / compute,
952Operand = expect(V"Term", "ExpTerm"),
953Term = num,
954}
955local rg = Rec(g, Cc(3), labelindex("ExpTerm"))
956
957local function eval(input)
958 local result, label, suffix = rg:match(input)
959 if #errors == 0 then
960 return result
961 else
962 local out = {}
963 for i, err in ipairs(errors) do
964 local pos = err[2]
965 local msg = labels[err[1]][2]
966 table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")")
967 end
968 errors = {}
969 return nil, table.concat(out, "\n")
970 end
971end
972
973assert(eval("98-76*54/32") == 37.125)
974--> 37.125
975
976assert(eval("1+") == 4)
977--> syntax error: expected a term after the operator (at index 3)
978
979
980print("OK")