aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lpcode.c15
-rw-r--r--lpprint.c5
-rw-r--r--lptypes.h5
-rw-r--r--lpvm.c82
-rw-r--r--lpvm.h2
-rw-r--r--testlabel.lua55
6 files changed, 114 insertions, 50 deletions
diff --git a/lpcode.c b/lpcode.c
index 1036fdf..ef357bc 100644
--- a/lpcode.c
+++ b/lpcode.c
@@ -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*/
749static void codeand (CompileState *compst, TTree *tree, int tt) { 749static 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);
diff --git a/lpprint.c b/lpprint.c
index 21fb038..3c6a8f6 100644
--- a/lpprint.c
+++ b/lpprint.c
@@ -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 }
diff --git a/lptypes.h b/lptypes.h
index 25e84a2..d523e27 100644
--- a/lptypes.h
+++ b/lptypes.h
@@ -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
diff --git a/lpvm.c b/lpvm.c
index 9812e19..f56f1d5 100644
--- a/lpvm.c
+++ b/lpvm.c
@@ -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 */
diff --git a/lpvm.h b/lpvm.h
index 37c8522..c5457c4 100644
--- a/lpvm.h
+++ b/lpvm.h
@@ -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)
194r, l, poserr = p:match("cab") 194r, l, poserr = p:match("cab")
195assert(r == nil and l == 'fail' and poserr == 1) 195assert(r == nil and l == 'fail' and poserr == 1)
196 196
197
198-- tests related to predicates 197-- tests related to predicates
198p = #m.T(1)
199r, l, poserr = p:match("abc")
200assert(r == nil and l == 'fail' and poserr == 1)
201
199p = #m.T(1) + m.P"a" 202p = #m.T(1) + m.P"a"
200r, l, poserr = p:match("abc") 203r, l, poserr = p:match("abc")
201assert(r == nil and l == 1 and poserr == 1) 204assert(r == 2)
205
206p = #m.T(1) * m.P"a"
207r, l, poserr = p:match("abc")
208assert(r == nil and l == 'fail' and poserr == 1)
202 209
203p = ##m.T(1) + m.P"a" 210p = ##m.T(1) + m.P"a"
204r, l, poserr = p:match("abc") 211r, l, poserr = p:match("abc")
205assert(r == nil and l == 1 and poserr == 1) 212assert(r == 2)
206 213
207p = -m.T(1) * m.P"a" 214p = -#m.T(1) + m.P"a"
208r, l, poserr = p:match("abc") 215r, l, poserr = p:match("abc")
209assert(r == nil and l == 1 and poserr == 1) 216assert(r == 1)
210 217
211p = -m.T(1) * m.P"a" 218p = -m.T(1) * m.P"a"
219r, l, poserr = p:match("abc")
220assert(r == 2)
221
222p = -m.T(1)
212r, l, poserr = p:match("bbc") 223r, l, poserr = p:match("bbc")
213assert(r == nil and l == 1 and poserr == 1) 224assert(r == 1)
225
226p = -#m.T(1)
227r, l, poserr = p:match("bbc")
228assert(r == 1)
214 229
215p = -(-m.T(1)) * m.P"a" 230p = -(-m.P'a')
216r, l, poserr = p:match("abc") 231r, l, poserr = p:match("abc")
217assert(r == nil and l == 1 and poserr == 1) 232assert(r == 1)
233
234p = -(-m.P'a')
235r, l, poserr = p:match("bbc")
236assert(r == nil and l == 'fail' and poserr == 1)
237
238p = #(m.P"a" * m.T(1))
239r, l, poserr = p:match("abc")
240assert(r == nil and l == 'fail' and poserr == 1)
241
242p = #(m.P"a" * m.P'a')
243r, l, poserr = p:match("abc")
244assert(r == nil and l == 'fail' and poserr == 1)
245
246
247p = -(-m.T(1))
248r, l, poserr = p:match("bbc")
249assert(r == nil and l == 'fail' and poserr == 1)
218 250
219p = m.P{ 251p = 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}
224r, l, poserr = p:match("abc") 256r, l, poserr = p:match("abc")
225assert(r == nil and l == 'fail' and poserr == 2) 257assert(r == 1)
226 258
227assert(p:match("bbc") == 1) 259assert(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}
234assert(p:match("abc") == 1) 266r, l, poserr = p:match("abc")
267assert(r == nil and l == 'fail' and poserr == 1)
235 268
236p = m.P{ 269p = 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}
264r, l, poserr = p:match("abc") 297r, l, poserr = p:match("abc")
265assert(r == nil and l == 15 and poserr == 2) 298assert(r == nil and l == 'fail' and poserr == 1)
266 299
267 300
268-- tests related to repetition 301-- tests related to repetition