diff options
author | Sérgio Queiroz <sqmedeiros@gmail.com> | 2017-12-27 14:13:25 -0300 |
---|---|---|
committer | Sérgio Queiroz <sqmedeiros@gmail.com> | 2017-12-27 14:13:25 -0300 |
commit | 772df00e061db3cd7d0af92c8ab65bc023d8121d (patch) | |
tree | 48e343e06a4b3ea4a4423330e1256606db4d53f3 | |
parent | e4cc8be34e590dc22f0a25ecfa269624b1569925 (diff) | |
download | lpeglabel-772df00e061db3cd7d0af92c8ab65bc023d8121d.tar.gz lpeglabel-772df00e061db3cd7d0af92c8ab65bc023d8121d.tar.bz2 lpeglabel-772df00e061db3cd7d0af92c8ab65bc023d8121d.zip |
Implementing the new semantics of predicates when a label is thrown
-rw-r--r-- | lpcode.c | 15 | ||||
-rw-r--r-- | lpprint.c | 5 | ||||
-rw-r--r-- | lptypes.h | 5 | ||||
-rw-r--r-- | lpvm.c | 82 | ||||
-rw-r--r-- | lpvm.h | 2 | ||||
-rw-r--r-- | testlabel.lua | 55 |
6 files changed, 114 insertions, 50 deletions
@@ -449,7 +449,7 @@ int sizei (const Instruction *i) { | |||
449 | case ITestChar: case ITestAny: case IChoice: case IJmp: case ICall: | 449 | case ITestChar: case ITestAny: case IChoice: case IJmp: case ICall: |
450 | case IOpenCall: case ICommit: case IPartialCommit: case IBackCommit: | 450 | case IOpenCall: case ICommit: case IPartialCommit: case IBackCommit: |
451 | return 2; | 451 | return 2; |
452 | case IThrow: /* labeled failure */ | 452 | case IThrow: case IPredChoice: /* labeled failure */ |
453 | return 2; | 453 | return 2; |
454 | case IThrowRec: /* labeled failure */ | 454 | case IThrowRec: /* labeled failure */ |
455 | return 3; | 455 | return 3; |
@@ -747,15 +747,19 @@ static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt, | |||
747 | ** (valid only when 'p' has no captures) | 747 | ** (valid only when 'p' has no captures) |
748 | */ | 748 | */ |
749 | static void codeand (CompileState *compst, TTree *tree, int tt) { | 749 | static void codeand (CompileState *compst, TTree *tree, int tt) { |
750 | int n = fixedlen(tree); | 750 | /* labeled failure: optimization disabled bacause in case of a failure it |
751 | does not report the expected error position (the current subject position | ||
752 | when begin the matching of <&p>) */ | ||
753 | /*int n = fixedlen(tree); | ||
751 | if (n >= 0 && n <= MAXBEHIND && !hascaptures(tree)) { | 754 | if (n >= 0 && n <= MAXBEHIND && !hascaptures(tree)) { |
752 | codegen(compst, tree, 0, tt, fullset); | 755 | codegen(compst, tree, 0, tt, fullset); |
753 | if (n > 0) | 756 | if (n > 0) |
754 | addinstruction(compst, IBehind, n); | 757 | addinstruction(compst, IBehind, n); |
755 | } | 758 | } |
756 | else { /* default: Choice L1; p1; BackCommit L2; L1: Fail; L2: */ | 759 | else */{ /* default: Choice L1; p1; BackCommit L2; L1: Fail; L2: */ |
757 | int pcommit; | 760 | int pcommit; |
758 | int pchoice = addoffsetinst(compst, IChoice); | 761 | int pchoice = addoffsetinst(compst, IPredChoice); /* labeled failure */ |
762 | getinstr(compst, pchoice).i.aux = ANDPRED; | ||
759 | codegen(compst, tree, 0, tt, fullset); | 763 | codegen(compst, tree, 0, tt, fullset); |
760 | pcommit = addoffsetinst(compst, IBackCommit); | 764 | pcommit = addoffsetinst(compst, IBackCommit); |
761 | jumptohere(compst, pchoice); | 765 | jumptohere(compst, pchoice); |
@@ -857,7 +861,8 @@ static void codenot (CompileState *compst, TTree *tree) { | |||
857 | addinstruction(compst, IFail, 0); | 861 | addinstruction(compst, IFail, 0); |
858 | else { | 862 | else { |
859 | /* test(fail(p))-> L1; choice L1; <p>; failtwice; L1: */ | 863 | /* test(fail(p))-> L1; choice L1; <p>; failtwice; L1: */ |
860 | int pchoice = addoffsetinst(compst, IChoice); | 864 | int pchoice = addoffsetinst(compst, IPredChoice); /* labeled failure */ |
865 | getinstr(compst, pchoice).i.aux = NOTPRED; | ||
861 | codegen(compst, tree, 0, NOINST, fullset); | 866 | codegen(compst, tree, 0, NOINST, fullset); |
862 | addinstruction(compst, IFailTwice, 0); | 867 | addinstruction(compst, IFailTwice, 0); |
863 | jumptohere(compst, pchoice); | 868 | jumptohere(compst, pchoice); |
@@ -58,7 +58,7 @@ void printinst (const Instruction *op, const Instruction *p) { | |||
58 | "testany", "testchar", "testset", | 58 | "testany", "testchar", "testset", |
59 | "span", "behind", | 59 | "span", "behind", |
60 | "ret", "end", | 60 | "ret", "end", |
61 | "choice", "jmp", "call", "open_call", | 61 | "choice", "pred_choice", "jmp", "call", "open_call", /* labeled failure */ |
62 | "commit", "partial_commit", "back_commit", "failtwice", "fail", "giveup", | 62 | "commit", "partial_commit", "back_commit", "failtwice", "fail", "giveup", |
63 | "fullcapture", "opencapture", "closecapture", "closeruntime", | 63 | "fullcapture", "opencapture", "closecapture", "closeruntime", |
64 | "throw", "throw_rec", /* labeled failure */ | 64 | "throw", "throw_rec", /* labeled failure */ |
@@ -103,7 +103,8 @@ void printinst (const Instruction *op, const Instruction *p) { | |||
103 | break; | 103 | break; |
104 | } | 104 | } |
105 | case IJmp: case ICall: case ICommit: case IChoice: | 105 | case IJmp: case ICall: case ICommit: case IChoice: |
106 | case IPartialCommit: case IBackCommit: case ITestAny: { | 106 | case IPartialCommit: case IBackCommit: case ITestAny: |
107 | case IPredChoice: { /* labeled failure */ | ||
107 | printjmp(op, p); | 108 | printjmp(op, p); |
108 | break; | 109 | break; |
109 | } | 110 | } |
@@ -150,6 +150,11 @@ typedef struct Charset { | |||
150 | /* update the farthest failure */ | 150 | /* update the farthest failure */ |
151 | #define updatefarthest(s1,s2) { if ((s2) > (s1)) s1 = s2; } | 151 | #define updatefarthest(s1,s2) { if ((s2) > (s1)) s1 = s2; } |
152 | 152 | ||
153 | /* indicate whether the machine is matching a predicate or not */ | ||
154 | #define OUTPRED 0 | ||
155 | #define NOTPRED 1 | ||
156 | #define ANDPRED 2 | ||
157 | |||
153 | /* labeled failure end */ | 158 | /* labeled failure end */ |
154 | 159 | ||
155 | #endif | 160 | #endif |
@@ -39,6 +39,7 @@ typedef struct Stack { | |||
39 | const Instruction *p; /* next instruction */ | 39 | const Instruction *p; /* next instruction */ |
40 | int caplevel; | 40 | int caplevel; |
41 | byte labenv; /* labeled failure */ | 41 | byte labenv; /* labeled failure */ |
42 | byte predchoice; /* labeled failure */ | ||
42 | } Stack; | 43 | } Stack; |
43 | 44 | ||
44 | 45 | ||
@@ -156,8 +157,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
156 | int captop = 0; /* point to first empty slot in captures */ | 157 | int captop = 0; /* point to first empty slot in captures */ |
157 | int ndyncap = 0; /* number of dynamic captures (in Lua stack) */ | 158 | int ndyncap = 0; /* number of dynamic captures (in Lua stack) */ |
158 | const Instruction *p = op; /* current instruction */ | 159 | const Instruction *p = op; /* current instruction */ |
159 | byte labenv = 1; /* labeled failure: label environment is on */ | 160 | byte insidepred = OUTPRED; /* labeled failure: label environment is off inside predicates */ |
160 | stack->p = &giveup; stack->s = s; stack->caplevel = 0; stack->labenv = 1; stack++; /* labeled failure */ | 161 | stack->p = &giveup; stack->s = s; stack->caplevel = 0; stack->labenv = insidepred; stack++; /* labeled failure */ |
161 | *sfail = s; /* labeled failure */ | 162 | *sfail = s; /* labeled failure */ |
162 | lua_pushlightuserdata(L, stackbase); | 163 | lua_pushlightuserdata(L, stackbase); |
163 | for (;;) { | 164 | for (;;) { |
@@ -168,9 +169,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
168 | s, (int)(stack - getstackbase(L, ptop)), ndyncap, captop); | 169 | s, (int)(stack - getstackbase(L, ptop)), ndyncap, captop); |
169 | printinst(op, p); | 170 | printinst(op, p); |
170 | #endif | 171 | #endif |
171 | printinst(op, p); | ||
172 | assert(stackidx(ptop) + ndyncap == lua_gettop(L) && ndyncap <= captop); | 172 | assert(stackidx(ptop) + ndyncap == lua_gettop(L) && ndyncap <= captop); |
173 | assert(labenv == 1); | 173 | assert(insidepred == NOTPRED || insidepred == ANDPRED || insidepred == OUTPRED); |
174 | switch ((Opcode)p->i.code) { | 174 | switch ((Opcode)p->i.code) { |
175 | case IEnd: { | 175 | case IEnd: { |
176 | assert(stack == getstackbase(L, ptop) + 1); | 176 | assert(stack == getstackbase(L, ptop) + 1); |
@@ -191,7 +191,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
191 | if (s < e) { p++; s++; } | 191 | if (s < e) { p++; s++; } |
192 | else { | 192 | else { |
193 | *labelf = LFAIL; /* labeled failure */ | 193 | *labelf = LFAIL; /* labeled failure */ |
194 | updatefarthest(*sfail, s); /*labeled failure */ | 194 | if (insidepred == OUTPRED) |
195 | updatefarthest(*sfail, s); /*labeled failure */ | ||
195 | goto fail; | 196 | goto fail; |
196 | } | 197 | } |
197 | continue; | 198 | continue; |
@@ -205,7 +206,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
205 | if ((byte)*s == p->i.aux && s < e) { p++; s++; } | 206 | if ((byte)*s == p->i.aux && s < e) { p++; s++; } |
206 | else { | 207 | else { |
207 | *labelf = LFAIL; /* labeled failure */ | 208 | *labelf = LFAIL; /* labeled failure */ |
208 | updatefarthest(*sfail, s); /*labeled failure */ | 209 | if (insidepred == OUTPRED) |
210 | updatefarthest(*sfail, s); /*labeled failure */ | ||
209 | goto fail; | 211 | goto fail; |
210 | } | 212 | } |
211 | continue; | 213 | continue; |
@@ -221,7 +223,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
221 | { p += CHARSETINSTSIZE; s++; } | 223 | { p += CHARSETINSTSIZE; s++; } |
222 | else { | 224 | else { |
223 | *labelf = LFAIL; /* labeled failure */ | 225 | *labelf = LFAIL; /* labeled failure */ |
224 | updatefarthest(*sfail, s); /*labeled failure */ | 226 | if (insidepred == OUTPRED) |
227 | updatefarthest(*sfail, s); /*labeled failure */ | ||
225 | goto fail; | 228 | goto fail; |
226 | } | 229 | } |
227 | continue; | 230 | continue; |
@@ -237,7 +240,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
237 | int n = p->i.aux; | 240 | int n = p->i.aux; |
238 | if (n > s - o) { | 241 | if (n > s - o) { |
239 | *labelf = LFAIL; /* labeled failure */ | 242 | *labelf = LFAIL; /* labeled failure */ |
240 | updatefarthest(*sfail, s); /*labeled failure */ | 243 | if (insidepred == OUTPRED) |
244 | updatefarthest(*sfail, s); /*labeled failure */ | ||
241 | goto fail; | 245 | goto fail; |
242 | } | 246 | } |
243 | s -= n; p++; | 247 | s -= n; p++; |
@@ -261,10 +265,24 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
261 | stack->p = p + getoffset(p); | 265 | stack->p = p + getoffset(p); |
262 | stack->s = s; | 266 | stack->s = s; |
263 | stack->caplevel = captop; | 267 | stack->caplevel = captop; |
264 | stack->labenv = labenv; /* labeled failure */ | 268 | stack->labenv = insidepred; /* labeled failure */ |
269 | stack->predchoice = 0; /* labeled failure */ | ||
265 | stack++; | 270 | stack++; |
266 | p += 2; | 271 | p += 2; |
267 | continue; | 272 | continue; |
273 | } | ||
274 | case IPredChoice: { /* labeled failure: new instruction */ | ||
275 | if (stack == stacklimit) | ||
276 | stack = doublestack(L, &stacklimit, ptop); | ||
277 | stack->p = p + getoffset(p); | ||
278 | stack->s = s; | ||
279 | stack->caplevel = captop; | ||
280 | stack->labenv = insidepred; | ||
281 | stack->predchoice = 1; | ||
282 | stack++; | ||
283 | insidepred = p->i.aux; | ||
284 | p += 2; | ||
285 | continue; | ||
268 | } | 286 | } |
269 | case ICall: { | 287 | case ICall: { |
270 | if (stack == stacklimit) | 288 | if (stack == stacklimit) |
@@ -292,38 +310,30 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
292 | case IBackCommit: { | 310 | case IBackCommit: { |
293 | assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL); | 311 | assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL); |
294 | s = (--stack)->s; | 312 | s = (--stack)->s; |
295 | labenv = stack->labenv; /* labeled failure */ | 313 | insidepred = stack->labenv; /* labeled failure */ |
296 | assert(labenv == 1); /* labeled failure */ | ||
297 | captop = stack->caplevel; | 314 | captop = stack->caplevel; |
298 | p += getoffset(p); | 315 | p += getoffset(p); |
299 | continue; | 316 | continue; |
300 | } | 317 | } |
301 | case IThrow: { /* labeled failure */ | 318 | case IThrow: { /* labeled failure */ |
302 | /*printf("IThrow here: key=%d, key+1=%d aux = %d top = %d\n", p->i.key, (p+1)->i.key, p->i.aux, lua_gettop(L)); | 319 | if (insidepred == OUTPRED) { |
303 | lua_rawgeti(L, ktableidx(ptop), (p+1)->i.key); | ||
304 | printf("IThrow there %s top = %d\n", lua_tostring(L, -1), lua_gettop(L)); | ||
305 | lua_pop(L, 1);*/ | ||
306 | if (labenv) { | ||
307 | *labelf = (p+1)->i.key; | 320 | *labelf = (p+1)->i.key; |
308 | if (*labelf == LFAIL) | 321 | if (*labelf == LFAIL) |
309 | luaL_error(L, "labelf is %d", *labelf); | 322 | luaL_error(L, "labelf is %d", *labelf); |
310 | stack = getstackbase(L, ptop); | 323 | stack = getstackbase(L, ptop); |
311 | stack++; | 324 | stack++; |
312 | printf("IThrow stack->labenv = %d\n", stack->labenv); | 325 | *sfail = s; |
313 | } | 326 | } |
314 | else { | 327 | else { |
315 | labelf = LFAIL; | 328 | while (!(stack-1)->predchoice) { |
329 | --stack; | ||
330 | } | ||
331 | *labelf = LFAIL; | ||
316 | } | 332 | } |
317 | *sfail = s; | ||
318 | goto fail; | 333 | goto fail; |
319 | } | 334 | } |
320 | case IThrowRec: { /* labeled failure */ | 335 | case IThrowRec: { /* labeled failure */ |
321 | /*printf("IThrowRec here: key=%d, key+2=%d aux = %d top = %d\n", p->i.key, (p+2)->i.key, p->i.aux, lua_gettop(L)); | 336 | if (insidepred == OUTPRED) { |
322 | lua_rawgeti(L, ktableidx(ptop), (p+2)->i.key); | ||
323 | printf("IThrowRec there %s top = %d\n", lua_tostring(L, -1), lua_gettop(L)); | ||
324 | lua_pop(L, 1);*/ | ||
325 | printf("labenv here = %d\n", labenv); | ||
326 | if (labenv) { | ||
327 | *labelf = (p+2)->i.key; | 337 | *labelf = (p+2)->i.key; |
328 | if (*labelf == LFAIL) | 338 | if (*labelf == LFAIL) |
329 | luaL_error(L, "labelf is %d", *labelf); | 339 | luaL_error(L, "labelf is %d", *labelf); |
@@ -334,12 +344,19 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
334 | stack->p = p + 3; | 344 | stack->p = p + 3; |
335 | stack->caplevel = captop; | 345 | stack->caplevel = captop; |
336 | stack++; | 346 | stack++; |
347 | *sfail = s; | ||
337 | p += getoffset(p); | 348 | p += getoffset(p); |
338 | continue; | 349 | continue; |
339 | } else { | 350 | } else { |
340 | labelf = LFAIL; | 351 | while (!(stack-1)->predchoice) { |
352 | --stack; | ||
353 | } | ||
354 | /*if ((stack-1)->labenv == ANDPRED) { | ||
355 | printf("ANDPRED: stack - 1\n"); | ||
356 | stack--; | ||
357 | }*/ | ||
358 | *labelf = LFAIL; | ||
341 | } | 359 | } |
342 | *sfail = s; | ||
343 | goto fail; | 360 | goto fail; |
344 | } | 361 | } |
345 | case IFailTwice: | 362 | case IFailTwice: |
@@ -348,7 +365,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
348 | /* go through */ | 365 | /* go through */ |
349 | case IFail: | 366 | case IFail: |
350 | *labelf = LFAIL; /* labeled failure */ | 367 | *labelf = LFAIL; /* labeled failure */ |
351 | updatefarthest(*sfail, s); /*labeled failure */ | 368 | if (insidepred == OUTPRED) |
369 | updatefarthest(*sfail, s); /*labeled failure */ | ||
352 | fail: { /* pattern failed: try to backtrack */ | 370 | fail: { /* pattern failed: try to backtrack */ |
353 | do { /* remove pending calls */ | 371 | do { /* remove pending calls */ |
354 | assert(stack > getstackbase(L, ptop)); | 372 | assert(stack > getstackbase(L, ptop)); |
@@ -357,8 +375,9 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
357 | if (ndyncap > 0) /* is there matchtime captures? */ | 375 | if (ndyncap > 0) /* is there matchtime captures? */ |
358 | ndyncap -= removedyncap(L, capture, stack->caplevel, captop); | 376 | ndyncap -= removedyncap(L, capture, stack->caplevel, captop); |
359 | captop = stack->caplevel; | 377 | captop = stack->caplevel; |
360 | labenv = stack->labenv; | 378 | assert(((insidepred == ANDPRED || insidepred == NOTPRED) && (stack->labenv == OUTPRED)) || insidepred == stack->labenv |
361 | assert(labenv == 1); | 379 | || (insidepred != OUTPRED && stack->labenv != OUTPRED)); |
380 | insidepred = stack->labenv; | ||
362 | p = stack->p; | 381 | p = stack->p; |
363 | #if defined(DEBUG) | 382 | #if defined(DEBUG) |
364 | printf("**FAIL**\n"); | 383 | printf("**FAIL**\n"); |
@@ -377,7 +396,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
377 | res = resdyncaptures(L, fr, s - o, e - o); /* get result */ | 396 | res = resdyncaptures(L, fr, s - o, e - o); /* get result */ |
378 | if (res == -1) { /* fail? */ | 397 | if (res == -1) { /* fail? */ |
379 | *labelf = LFAIL; /* labeled failure */ | 398 | *labelf = LFAIL; /* labeled failure */ |
380 | updatefarthest(*sfail, s); /*labeled failure */ | 399 | if (insidepred == OUTPRED) |
400 | updatefarthest(*sfail, s); /*labeled failure */ | ||
381 | goto fail; | 401 | goto fail; |
382 | } | 402 | } |
383 | s = o + res; /* else update current position */ | 403 | s = o + res; /* else update current position */ |
@@ -21,7 +21,7 @@ typedef enum Opcode { | |||
21 | IRet, /* return from a rule */ | 21 | IRet, /* return from a rule */ |
22 | IEnd, /* end of pattern */ | 22 | IEnd, /* end of pattern */ |
23 | IChoice, /* stack a choice; next fail will jump to 'offset' */ | 23 | IChoice, /* stack a choice; next fail will jump to 'offset' */ |
24 | /*IPredChoice,*/ /* labeld failure: stack a choice; changes label env next fail will jump to 'offset' */ | 24 | IPredChoice, /* labeld failure: stack a choice; changes label env next fail will jump to 'offset' */ |
25 | IJmp, /* jump to 'offset' */ | 25 | IJmp, /* jump to 'offset' */ |
26 | ICall, /* call rule at 'offset' */ | 26 | ICall, /* call rule at 'offset' */ |
27 | IOpenCall, /* call rule number 'key' (must be closed to a ICall) */ | 27 | IOpenCall, /* call rule number 'key' (must be closed to a ICall) */ |
diff --git a/testlabel.lua b/testlabel.lua index b834be3..7461206 100644 --- a/testlabel.lua +++ b/testlabel.lua | |||
@@ -194,27 +194,59 @@ assert(p:match("bac") == 3) | |||
194 | r, l, poserr = p:match("cab") | 194 | r, l, poserr = p:match("cab") |
195 | assert(r == nil and l == 'fail' and poserr == 1) | 195 | assert(r == nil and l == 'fail' and poserr == 1) |
196 | 196 | ||
197 | |||
198 | -- tests related to predicates | 197 | -- tests related to predicates |
198 | p = #m.T(1) | ||
199 | r, l, poserr = p:match("abc") | ||
200 | assert(r == nil and l == 'fail' and poserr == 1) | ||
201 | |||
199 | p = #m.T(1) + m.P"a" | 202 | p = #m.T(1) + m.P"a" |
200 | r, l, poserr = p:match("abc") | 203 | r, l, poserr = p:match("abc") |
201 | assert(r == nil and l == 1 and poserr == 1) | 204 | assert(r == 2) |
205 | |||
206 | p = #m.T(1) * m.P"a" | ||
207 | r, l, poserr = p:match("abc") | ||
208 | assert(r == nil and l == 'fail' and poserr == 1) | ||
202 | 209 | ||
203 | p = ##m.T(1) + m.P"a" | 210 | p = ##m.T(1) + m.P"a" |
204 | r, l, poserr = p:match("abc") | 211 | r, l, poserr = p:match("abc") |
205 | assert(r == nil and l == 1 and poserr == 1) | 212 | assert(r == 2) |
206 | 213 | ||
207 | p = -m.T(1) * m.P"a" | 214 | p = -#m.T(1) + m.P"a" |
208 | r, l, poserr = p:match("abc") | 215 | r, l, poserr = p:match("abc") |
209 | assert(r == nil and l == 1 and poserr == 1) | 216 | assert(r == 1) |
210 | 217 | ||
211 | p = -m.T(1) * m.P"a" | 218 | p = -m.T(1) * m.P"a" |
219 | r, l, poserr = p:match("abc") | ||
220 | assert(r == 2) | ||
221 | |||
222 | p = -m.T(1) | ||
212 | r, l, poserr = p:match("bbc") | 223 | r, l, poserr = p:match("bbc") |
213 | assert(r == nil and l == 1 and poserr == 1) | 224 | assert(r == 1) |
225 | |||
226 | p = -#m.T(1) | ||
227 | r, l, poserr = p:match("bbc") | ||
228 | assert(r == 1) | ||
214 | 229 | ||
215 | p = -(-m.T(1)) * m.P"a" | 230 | p = -(-m.P'a') |
216 | r, l, poserr = p:match("abc") | 231 | r, l, poserr = p:match("abc") |
217 | assert(r == nil and l == 1 and poserr == 1) | 232 | assert(r == 1) |
233 | |||
234 | p = -(-m.P'a') | ||
235 | r, l, poserr = p:match("bbc") | ||
236 | assert(r == nil and l == 'fail' and poserr == 1) | ||
237 | |||
238 | p = #(m.P"a" * m.T(1)) | ||
239 | r, l, poserr = p:match("abc") | ||
240 | assert(r == nil and l == 'fail' and poserr == 1) | ||
241 | |||
242 | p = #(m.P"a" * m.P'a') | ||
243 | r, l, poserr = p:match("abc") | ||
244 | assert(r == nil and l == 'fail' and poserr == 1) | ||
245 | |||
246 | |||
247 | p = -(-m.T(1)) | ||
248 | r, l, poserr = p:match("bbc") | ||
249 | assert(r == nil and l == 'fail' and poserr == 1) | ||
218 | 250 | ||
219 | p = m.P{ | 251 | p = m.P{ |
220 | "S", | 252 | "S", |
@@ -222,7 +254,7 @@ p = m.P{ | |||
222 | ["22"] = m.P"a" | 254 | ["22"] = m.P"a" |
223 | } | 255 | } |
224 | r, l, poserr = p:match("abc") | 256 | r, l, poserr = p:match("abc") |
225 | assert(r == nil and l == 'fail' and poserr == 2) | 257 | assert(r == 1) |
226 | 258 | ||
227 | assert(p:match("bbc") == 1) | 259 | assert(p:match("bbc") == 1) |
228 | 260 | ||
@@ -231,7 +263,8 @@ p = m.P{ | |||
231 | S = #m.T(22), | 263 | S = #m.T(22), |
232 | ["22"] = m.P"a" | 264 | ["22"] = m.P"a" |
233 | } | 265 | } |
234 | assert(p:match("abc") == 1) | 266 | r, l, poserr = p:match("abc") |
267 | assert(r == nil and l == 'fail' and poserr == 1) | ||
235 | 268 | ||
236 | p = m.P{ | 269 | p = m.P{ |
237 | "S", | 270 | "S", |
@@ -262,7 +295,7 @@ p = m.P{ | |||
262 | ["22"] = m.T(15) | 295 | ["22"] = m.T(15) |
263 | } | 296 | } |
264 | r, l, poserr = p:match("abc") | 297 | r, l, poserr = p:match("abc") |
265 | assert(r == nil and l == 15 and poserr == 2) | 298 | assert(r == nil and l == 'fail' and poserr == 1) |
266 | 299 | ||
267 | 300 | ||
268 | -- tests related to repetition | 301 | -- tests related to repetition |