diff options
| author | Sergio Queiroz <sqmedeiros@gmail.com> | 2017-01-03 10:02:52 -0300 |
|---|---|---|
| committer | Sergio Queiroz <sqmedeiros@gmail.com> | 2017-01-03 10:02:52 -0300 |
| commit | c6277dabce8428b49ff5df63b515c68a0386d9da (patch) | |
| tree | 36c6ae8ace4f1da3c8342324b415cfef2a50b750 | |
| parent | 2e5820c37e4e6cb2a2c01863619abd19eb5a8199 (diff) | |
| download | lpeglabel-c6277dabce8428b49ff5df63b515c68a0386d9da.tar.gz lpeglabel-c6277dabce8428b49ff5df63b515c68a0386d9da.tar.bz2 lpeglabel-c6277dabce8428b49ff5df63b515c68a0386d9da.zip | |
Tracking the farthest failure position in case of a regular fail
| -rw-r--r-- | lptypes.h | 4 | ||||
| -rw-r--r-- | lpvm.c | 13 | ||||
| -rw-r--r-- | testfarthest.lua | 16 | ||||
| -rw-r--r-- | testlabel.lua | 209 |
4 files changed, 150 insertions, 92 deletions
| @@ -161,6 +161,10 @@ typedef Charset Labelset; | |||
| 161 | #define IDXLFAIL 0 | 161 | #define IDXLFAIL 0 |
| 162 | 162 | ||
| 163 | #define LFAIL 0 | 163 | #define LFAIL 0 |
| 164 | |||
| 165 | /* update the farthest failure */ | ||
| 166 | #define updatefarthest(s1,s2) { if ((s2) > (s1)) s1 = s2; } | ||
| 167 | |||
| 164 | /* labeled failure end */ | 168 | /* labeled failure end */ |
| 165 | 169 | ||
| 166 | #endif | 170 | #endif |
| @@ -166,6 +166,7 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
| 166 | Labelset lsfail; | 166 | Labelset lsfail; |
| 167 | setlabelfail(&lsfail); | 167 | setlabelfail(&lsfail); |
| 168 | stack->p = &giveup; stack->s = s; stack->ls = &lsfail; stack->caplevel = 0; stack++; /* labeled failure */ | 168 | stack->p = &giveup; stack->s = s; stack->ls = &lsfail; stack->caplevel = 0; stack++; /* labeled failure */ |
| 169 | *sfail = s; /* labeled failure */ | ||
| 169 | lua_pushlightuserdata(L, stackbase); | 170 | lua_pushlightuserdata(L, stackbase); |
| 170 | for (;;) { | 171 | for (;;) { |
| 171 | #if defined(DEBUG) | 172 | #if defined(DEBUG) |
| @@ -196,7 +197,7 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
| 196 | else { | 197 | else { |
| 197 | *labelf = LFAIL; /* labeled failure */ | 198 | *labelf = LFAIL; /* labeled failure */ |
| 198 | pk = p + 1; | 199 | pk = p + 1; |
| 199 | *sfail = s; | 200 | updatefarthest(*sfail, s); /*labeled failure */ |
| 200 | goto fail; | 201 | goto fail; |
| 201 | } | 202 | } |
| 202 | continue; | 203 | continue; |
| @@ -211,7 +212,7 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
| 211 | else { | 212 | else { |
| 212 | *labelf = LFAIL; /* labeled failure */ | 213 | *labelf = LFAIL; /* labeled failure */ |
| 213 | pk = p + 1; | 214 | pk = p + 1; |
| 214 | *sfail = s; | 215 | updatefarthest(*sfail, s); /*labeled failure */ |
| 215 | goto fail; | 216 | goto fail; |
| 216 | } | 217 | } |
| 217 | continue; | 218 | continue; |
| @@ -228,7 +229,7 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
| 228 | else { | 229 | else { |
| 229 | *labelf = LFAIL; /* labeled failure */ | 230 | *labelf = LFAIL; /* labeled failure */ |
| 230 | pk = p + CHARSETINSTSIZE; | 231 | pk = p + CHARSETINSTSIZE; |
| 231 | *sfail = s; | 232 | updatefarthest(*sfail, s); /*labeled failure */ |
| 232 | goto fail; | 233 | goto fail; |
| 233 | } | 234 | } |
| 234 | continue; | 235 | continue; |
| @@ -245,7 +246,7 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
| 245 | if (n > s - o) { | 246 | if (n > s - o) { |
| 246 | *labelf = LFAIL; /* labeled failure */ | 247 | *labelf = LFAIL; /* labeled failure */ |
| 247 | pk = p + 1; | 248 | pk = p + 1; |
| 248 | *sfail = s; | 249 | updatefarthest(*sfail, s); /*labeled failure */ |
| 249 | goto fail; | 250 | goto fail; |
| 250 | } | 251 | } |
| 251 | s -= n; p++; | 252 | s -= n; p++; |
| @@ -329,7 +330,7 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
| 329 | case IFail: | 330 | case IFail: |
| 330 | *labelf = LFAIL; /* labeled failure */ | 331 | *labelf = LFAIL; /* labeled failure */ |
| 331 | pk = NULL; | 332 | pk = NULL; |
| 332 | *sfail = s; | 333 | updatefarthest(*sfail, s); /*labeled failure */ |
| 333 | fail: { /* pattern failed: try to backtrack */ | 334 | fail: { /* pattern failed: try to backtrack */ |
| 334 | const Labelset *auxlab = NULL; | 335 | const Labelset *auxlab = NULL; |
| 335 | Stack *pstack = stack; | 336 | Stack *pstack = stack; |
| @@ -366,8 +367,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
| 366 | res = resdyncaptures(L, fr, s - o, e - o); /* get result */ | 367 | res = resdyncaptures(L, fr, s - o, e - o); /* get result */ |
| 367 | if (res == -1) { /* fail? */ | 368 | if (res == -1) { /* fail? */ |
| 368 | *labelf = LFAIL; /* labeled failure */ | 369 | *labelf = LFAIL; /* labeled failure */ |
| 369 | *sfail = (const char *) s; | ||
| 370 | pk = NULL; | 370 | pk = NULL; |
| 371 | updatefarthest(*sfail, s); /*labeled failure */ | ||
| 371 | goto fail; | 372 | goto fail; |
| 372 | } | 373 | } |
| 373 | s = o + res; /* else update current position */ | 374 | s = o + res; /* else update current position */ |
diff --git a/testfarthest.lua b/testfarthest.lua index 386cbbd..e862d87 100644 --- a/testfarthest.lua +++ b/testfarthest.lua | |||
| @@ -6,20 +6,8 @@ function matchPrint(p, s) | |||
| 6 | print("Result:", r, l, sfail) | 6 | print("Result:", r, l, sfail) |
| 7 | end | 7 | end |
| 8 | 8 | ||
| 9 | local p = m.P"a"^0 * m.P"b" + m.P"c" | ||
| 10 | 9 | ||
| 10 | local p = (m.P"c" + m.P"a") * m.P("b" + m.P"d") + m.P"xxx" | ||
| 11 | p:pcode() | 11 | p:pcode() |
| 12 | matchPrint(p, "ba") | ||
| 12 | 13 | ||
| 13 | matchPrint(p, "aab") | ||
| 14 | matchPrint(p, "ck") | ||
| 15 | matchPrint(p, "dk") | ||
| 16 | matchPrint(p, "aak") | ||
| 17 | |||
| 18 | local p = m.P"a"^0 * m.P(1) * m.P(1) + m.P"a"^0 * m.P"c" | ||
| 19 | |||
| 20 | p:pcode() | ||
| 21 | |||
| 22 | matchPrint(p, "aabc") | ||
| 23 | matchPrint(p, "aac") | ||
| 24 | matchPrint(p, "aak") | ||
| 25 | matchPrint(p, "x") | ||
diff --git a/testlabel.lua b/testlabel.lua index 9fcdcfc..e2833ea 100644 --- a/testlabel.lua +++ b/testlabel.lua | |||
| @@ -2,7 +2,7 @@ local m = require 'lpeglabel' | |||
| 2 | 2 | ||
| 3 | local p, r, l, s, serror | 3 | local p, r, l, s, serror |
| 4 | 4 | ||
| 5 | local function checkeqlab (x, ...) | 5 | local function checklabeq (x, ...) |
| 6 | y = { ... } | 6 | y = { ... } |
| 7 | assert(type(x) == "table") | 7 | assert(type(x) == "table") |
| 8 | assert(#x == #y) | 8 | assert(#x == #y) |
| @@ -12,7 +12,7 @@ local function checkeqlab (x, ...) | |||
| 12 | end | 12 | end |
| 13 | 13 | ||
| 14 | local function checkeq (x, y, p) | 14 | local function checkeq (x, y, p) |
| 15 | if p then print(x,y) end | 15 | if p then print(x,y) end |
| 16 | if type(x) ~= "table" then assert(x == y) | 16 | if type(x) ~= "table" then assert(x == y) |
| 17 | else | 17 | else |
| 18 | for k,v in pairs(x) do checkeq(v, y[k], p) end | 18 | for k,v in pairs(x) do checkeq(v, y[k], p) end |
| @@ -20,27 +20,92 @@ if p then print(x,y) end | |||
| 20 | end | 20 | end |
| 21 | end | 21 | end |
| 22 | 22 | ||
| 23 | |||
| 24 | -- tests related to reporting the farthest failure position | ||
| 25 | -- when a label is not thrown | ||
| 26 | |||
| 27 | p = m.P"a"^0 * m.P"b" + m.P"c" | ||
| 28 | checklabeq({4, nil, nil}, p:match("aabk")) | ||
| 29 | checklabeq({2, nil, nil}, p:match("ck")) | ||
| 30 | checklabeq({nil, 0, "dk"}, p:match("dk")) | ||
| 31 | checklabeq({nil, 0, "k"}, p:match("aak")) | ||
| 32 | |||
| 33 | p = (m.P"a" + m.P"c")^0 * m.P"b" + m.P"c" | ||
| 34 | checklabeq({4, nil, nil}, p:match("aabk")) | ||
| 35 | checklabeq({2, nil, nil}, p:match("ck")) | ||
| 36 | checklabeq({nil, 0, "dk"}, p:match("dk")) | ||
| 37 | checklabeq({nil, 0, "k"}, p:match("aak")) | ||
| 38 | |||
| 39 | p = m.P"a"^0 * m.P"b" + m.P(1)^0 * m.P(1) | ||
| 40 | checklabeq({4, nil, nil}, p:match("aabk")) | ||
| 41 | checklabeq({nil, 0, ""}, p:match("ck")) | ||
| 42 | checklabeq({nil, 0, ""}, p:match("aak")) | ||
| 43 | |||
| 44 | p = m.P(1) * m.P"a" + m.P"c" | ||
| 45 | checklabeq({3, nil, nil}, p:match("bac")) | ||
| 46 | checklabeq({2, nil, nil}, p:match("c")) | ||
| 47 | checklabeq({nil, 0, ""}, p:match("x")) | ||
| 48 | checklabeq({nil, 0, "x"}, p:match("kx")) | ||
| 49 | |||
| 50 | p = m.P"a"^0 * m.P(1) * m.P(1) + m.P"a"^0 * m.P"c" | ||
| 51 | checklabeq({5, nil, nil}, p:match("aabc")) | ||
| 52 | checklabeq({4, nil, nil}, p:match("aac")) | ||
| 53 | checklabeq({nil, 0, ""}, p:match("aak")) | ||
| 54 | checklabeq({nil, 0, ""}, p:match("x")) | ||
| 55 | |||
| 56 | p = m.P"a"^0 * m.P(1) * m.P(1) + m.P"a"^0 * m.P"c" | ||
| 57 | checklabeq({5, nil, nil}, p:match("aabc")) | ||
| 58 | checklabeq({4, nil, nil}, p:match("aac")) | ||
| 59 | checklabeq({nil, 0, ""}, p:match("aak")) | ||
| 60 | checklabeq({nil, 0, ""}, p:match("x")) | ||
| 61 | |||
| 62 | p = m.Cmt(m.P"a"^0, function() return nil end) + m.P"x" | ||
| 63 | checklabeq({2, nil, nil}, p:match("xabc")) | ||
| 64 | checklabeq({nil, 0, "c"}, p:match("aac")) | ||
| 65 | checklabeq({nil, 0, "kx"}, p:match("kx")) | ||
| 66 | |||
| 67 | p = m.P"b" * -m.P"a" + m.P"c" | ||
| 68 | checklabeq({nil, 0, "a"}, p:match("ba")) | ||
| 69 | checklabeq({nil, 0, "kx"}, p:match("kx")) | ||
| 70 | |||
| 71 | p = (m.P"c" + m.P"a") * m.P("b" + m.P"d") + m.P"xxx" | ||
| 72 | checklabeq({nil, 0, "kk"}, p:match("kk")) | ||
| 73 | checklabeq({nil, 0, "k"}, p:match("ak")) | ||
| 74 | checklabeq({nil, 0, "y"}, p:match("xxy")) | ||
| 75 | checklabeq({nil, 0, "yz"}, p:match("xyz")) | ||
| 76 | |||
| 77 | print"+" | ||
| 78 | |||
| 79 | |||
| 23 | -- throws a label | 80 | -- throws a label |
| 24 | p = m.T(1) | 81 | p = m.T(1) |
| 25 | s = "abc" | 82 | s = "abc" |
| 26 | r, l, serror = p:match(s) | 83 | r, l, serror = p:match(s) |
| 27 | assert(r == nil and l == 1 and serror == "abc") | 84 | assert(r == nil and l == 1 and serror == "abc") |
| 28 | 85 | ||
| 29 | -- throws a label that is not caught by ordinary choice | 86 | -- throws a label, choice does not catch labels |
| 30 | p = m.T(1) + m.P"a" | 87 | p = m.T(1) + m.P"a" |
| 31 | r, l, serror = p:match(s) | 88 | r, l, serror = p:match(s) |
| 32 | assert(r == nil and l == 1 and serror == "abc") | 89 | assert(r == nil and l == 1 and serror == "abc") |
| 33 | 90 | ||
| 34 | -- again throws a label that is not caught by ordinary choice | 91 | -- again throws a label that is not caught by choice |
| 35 | local g = m.P{ | 92 | local g = m.P{ |
| 36 | "S", | 93 | "S", |
| 37 | S = m.V"A" + m.V"B", | 94 | S = m.V"A" + m.V"B", |
| 38 | A = m.T(1), | 95 | A = m.T(1), |
| 39 | B = m.P"a" | 96 | B = m.P"a" |
| 40 | } | 97 | } |
| 41 | r, l, serror = g:match(s) | 98 | r, l, serror = g:match(s) |
| 42 | assert(r == nil and l == 1 and serror == "abc") | 99 | assert(r == nil and l == 1 and serror == "abc") |
| 43 | 100 | ||
| 101 | -- throws a label in a position that is not the farthest one | ||
| 102 | -- but it is the position that should be reported | ||
| 103 | p = m.P(1) * m.P"a" + m.T(11) | ||
| 104 | checklabeq({3, nil, nil}, p:match("bac")) | ||
| 105 | checklabeq({nil, 11, "c"}, p:match("c")) | ||
| 106 | checklabeq({nil, 11, "x"}, p:match("x")) | ||
| 107 | checklabeq({nil, 11, "kx"}, p:match("kx")) | ||
| 108 | |||
| 44 | 109 | ||
| 45 | -- throws a label that is not caught by the recovery operator | 110 | -- throws a label that is not caught by the recovery operator |
| 46 | p = m.Rec(m.T(2), m.P"a", 1, 3) | 111 | p = m.Rec(m.T(2), m.P"a", 1, 3) |
| @@ -209,10 +274,10 @@ A -> B | |||
| 209 | B -> %1 | 274 | B -> %1 |
| 210 | ]] | 275 | ]] |
| 211 | g = m.P{ | 276 | g = m.P{ |
| 212 | "S", | 277 | "S", |
| 213 | S = m.Rec(m.V"A", m.P"a", 1), | 278 | S = m.Rec(m.V"A", m.P"a", 1), |
| 214 | A = m.V"B", | 279 | A = m.V"B", |
| 215 | B = m.T(1), | 280 | B = m.T(1), |
| 216 | } | 281 | } |
| 217 | assert(g:match("ab") == 2) | 282 | assert(g:match("ab") == 2) |
| 218 | r, l, serror = g:match("bc") | 283 | r, l, serror = g:match("bc") |
| @@ -225,10 +290,10 @@ A -> (B (';' / %{1}))* | |||
| 225 | B -> 'a' | 290 | B -> 'a' |
| 226 | ]] | 291 | ]] |
| 227 | g = m.P{ | 292 | g = m.P{ |
| 228 | "S", | 293 | "S", |
| 229 | S = m.V"A", | 294 | S = m.V"A", |
| 230 | A = m.P(m.V"B" * (";" + m.T(1)))^0, | 295 | A = m.P(m.V"B" * (";" + m.T(1)))^0, |
| 231 | B = m.P'a', | 296 | B = m.P'a', |
| 232 | } | 297 | } |
| 233 | assert(g:match("a;a;") == 5) | 298 | assert(g:match("a;a;") == 5) |
| 234 | 299 | ||
| @@ -312,8 +377,8 @@ local sp = m.S" \t\n"^0 | |||
| 312 | local eq = sp * m.P"=" | 377 | local eq = sp * m.P"=" |
| 313 | 378 | ||
| 314 | g = m.P{ | 379 | g = m.P{ |
| 315 | "S", | 380 | "S", |
| 316 | S = m.Rec( | 381 | S = m.Rec( |
| 317 | m.Rec( | 382 | m.Rec( |
| 318 | m.Rec( | 383 | m.Rec( |
| 319 | m.Rec(m.V"S0", m.V"ID", 1), | 384 | m.Rec(m.V"S0", m.V"ID", 1), |
| @@ -323,13 +388,13 @@ g = m.P{ | |||
| 323 | ), | 388 | ), |
| 324 | m.V"U"^0 * m.V"ID" * m.V"ID", 4) | 389 | m.V"U"^0 * m.V"ID" * m.V"ID", 4) |
| 325 | + m.T(5), -- error | 390 | + m.T(5), -- error |
| 326 | S0 = m.V"S1" + m.V"S2" + #m.V"I" * m.T(3), | 391 | S0 = m.V"S1" + m.V"S2" + #m.V"I" * m.T(3), |
| 327 | S1 = #(m.V"ID" * eq) * m.T(2) + sp * #(m.V"ID" * -m.P(1)) * m.T(1) + #m.V"ID" * m.T(4), | 392 | S1 = #(m.V"ID" * eq) * m.T(2) + sp * #(m.V"ID" * -m.P(1)) * m.T(1) + #m.V"ID" * m.T(4), |
| 328 | S2 = #(m.V"U"^1 * m.V"ID") * m.T(4) + #(m.V"U"^1 * m.V"I") * m.T(3), | 393 | S2 = #(m.V"U"^1 * m.V"ID") * m.T(4) + #(m.V"U"^1 * m.V"I") * m.T(3), |
| 329 | ID = sp * m.P"a", | 394 | ID = sp * m.P"a", |
| 330 | U = sp * m.P"unsigned", | 395 | U = sp * m.P"unsigned", |
| 331 | I = sp * m.P"int", | 396 | I = sp * m.P"int", |
| 332 | Exp = sp * m.P"E", | 397 | Exp = sp * m.P"E", |
| 333 | } | 398 | } |
| 334 | 399 | ||
| 335 | local s = "a" | 400 | local s = "a" |
| @@ -411,7 +476,7 @@ S2 -> &('unsigned'+ ID) %4 / & ('unsigned'+ 'int') %3 | |||
| 411 | ]] | 476 | ]] |
| 412 | 477 | ||
| 413 | g = re.compile([[ | 478 | g = re.compile([[ |
| 414 | S <- S0 //{1} ID //{2} ID %s* '=' Exp //{3} U* Int ID //{4} U ID ID / %{5} | 479 | S <- S0 //{1} ID //{2} ID %s* '=' Exp //{3} U* Int ID //{4} U ID ID / %{5} |
| 415 | S0 <- S1 / S2 / &Int %{3} | 480 | S0 <- S1 / S2 / &Int %{3} |
| 416 | S1 <- &(ID %s* '=') %{2} / &(ID !.) %{1} / &ID %{4} | 481 | S1 <- &(ID %s* '=') %{2} / &(ID !.) %{1} / &ID %{4} |
| 417 | S2 <- &(U+ ID) %{4} / &(U+ Int) %{3} | 482 | S2 <- &(U+ ID) %{4} / &(U+ Int) %{3} |
| @@ -504,8 +569,8 @@ g = re.compile([[ | |||
| 504 | THEN <- Sp 'then' | 569 | THEN <- Sp 'then' |
| 505 | UNTIL <- Sp 'until' | 570 | UNTIL <- Sp 'until' |
| 506 | WRITE <- Sp 'write' | 571 | WRITE <- Sp 'write' |
| 507 | RESERVED <- (IF / ELSE / END / READ / REPEAT / THEN / UNTIL / WRITE) ![a-z]+ | 572 | RESERVED <- (IF / ELSE / END / READ / REPEAT / THEN / UNTIL / WRITE) ![a-z]+ |
| 508 | Sp <- (%s / %nl)* | 573 | Sp <- (%s / %nl)* |
| 509 | ]], terror) | 574 | ]], terror) |
| 510 | 575 | ||
| 511 | s = [[ | 576 | s = [[ |
| @@ -652,15 +717,15 @@ print("+") | |||
| 652 | 717 | ||
| 653 | p = m.Rec("a", "b", 3) | 718 | p = m.Rec("a", "b", 3) |
| 654 | assert(p:match("a") == 2) | 719 | assert(p:match("a") == 2) |
| 655 | checkeqlab({nil, 0, "b"}, p:match("b")) | 720 | checklabeq({nil, 0, "b"}, p:match("b")) |
| 656 | checkeqlab({nil, 0, "c"}, p:match("c")) | 721 | checklabeq({nil, 0, "c"}, p:match("c")) |
| 657 | 722 | ||
| 658 | p = m.Rec(m.T(3), "b", 1) | 723 | p = m.Rec(m.T(3), "b", 1) |
| 659 | checkeqlab({nil, 3, "a"}, p:match("a")) | 724 | checklabeq({nil, 3, "a"}, p:match("a")) |
| 660 | checkeqlab({nil, 3, "b"}, p:match("b")) | 725 | checklabeq({nil, 3, "b"}, p:match("b")) |
| 661 | 726 | ||
| 662 | p = m.Rec(m.T(3), "b", 3) | 727 | p = m.Rec(m.T(3), "b", 3) |
| 663 | checkeqlab({nil, 0, "a"}, p:match("a")) | 728 | checklabeq({nil, 0, "a"}, p:match("a")) |
| 664 | assert(p:match("b") == 2) | 729 | assert(p:match("b") == 2) |
| 665 | 730 | ||
| 666 | --[[ | 731 | --[[ |
| @@ -669,21 +734,21 @@ A -> a*b / %128 | |||
| 669 | C -> c+ | 734 | C -> c+ |
| 670 | ]] | 735 | ]] |
| 671 | g = m.P{ | 736 | g = m.P{ |
| 672 | "S", | 737 | "S", |
| 673 | S = m.Rec(m.V"A", (-m.P"c" * m.P(1))^0, 128) * m.V"C", | 738 | S = m.Rec(m.V"A", (-m.P"c" * m.P(1))^0, 128) * m.V"C", |
| 674 | A = m.P"a"^0 * "b" + m.T(128), | 739 | A = m.P"a"^0 * "b" + m.T(128), |
| 675 | C = m.P"c"^1, | 740 | C = m.P"c"^1, |
| 676 | } | 741 | } |
| 677 | 742 | ||
| 678 | assert(g:match("abc") == 4) | 743 | assert(g:match("abc") == 4) |
| 679 | assert(g:match("aabc") == 5) | 744 | assert(g:match("aabc") == 5) |
| 680 | assert(g:match("aadc") == 5) | 745 | assert(g:match("aadc") == 5) |
| 681 | assert(g:match("dc") == 3) | 746 | assert(g:match("dc") == 3) |
| 682 | checkeqlab({nil, 0, "bc"}, g:match("bbc")) | 747 | checklabeq({nil, 0, "bc"}, g:match("bbc")) |
| 683 | assert(g:match("xxc") == 4) | 748 | assert(g:match("xxc") == 4) |
| 684 | assert(g:match("c") == 2) | 749 | assert(g:match("c") == 2) |
| 685 | checkeqlab({nil, 0, ""}, g:match("fail")) | 750 | checklabeq({nil, 0, ""}, g:match("fail")) |
| 686 | checkeqlab({nil, 0, ""}, g:match("aaxx")) | 751 | checklabeq({nil, 0, ""}, g:match("aaxx")) |
| 687 | 752 | ||
| 688 | 753 | ||
| 689 | --[[ | 754 | --[[ |
| @@ -692,23 +757,23 @@ A -> a+ (b / ^99) | |||
| 692 | C -> c+ | 757 | C -> c+ |
| 693 | ]] | 758 | ]] |
| 694 | g = m.P{ | 759 | g = m.P{ |
| 695 | "S", | 760 | "S", |
| 696 | S = m.Rec(m.V"A", (-m.P"c" * m.P(1))^0, 99) * m.V"C", | 761 | S = m.Rec(m.V"A", (-m.P"c" * m.P(1))^0, 99) * m.V"C", |
| 697 | A = m.P"a"^1 * ("b" + m.T(99)), | 762 | A = m.P"a"^1 * ("b" + m.T(99)), |
| 698 | C = m.P"c"^1, | 763 | C = m.P"c"^1, |
| 699 | } | 764 | } |
| 700 | 765 | ||
| 701 | assert(g:match("abc") == 4) | 766 | assert(g:match("abc") == 4) |
| 702 | assert(g:match("aabc") == 5) | 767 | assert(g:match("aabc") == 5) |
| 703 | assert(g:match("aadc") == 5) | 768 | assert(g:match("aadc") == 5) |
| 704 | checkeqlab({nil, 0, "bc"}, g:match("bc")) | 769 | checklabeq({nil, 0, "bc"}, g:match("bc")) |
| 705 | checkeqlab({nil, 0, "bbc"}, g:match("bbc")) | 770 | checklabeq({nil, 0, "bbc"}, g:match("bbc")) |
| 706 | checkeqlab({nil, 0, "b"}, g:match("abb")) | 771 | checklabeq({nil, 0, "b"}, g:match("abb")) |
| 707 | checkeqlab({nil, 0, ""}, g:match("axx")) | 772 | checklabeq({nil, 0, ""}, g:match("axx")) |
| 708 | assert(g:match("accc") == 5) | 773 | assert(g:match("accc") == 5) |
| 709 | assert(g:match("axxc") == 5) | 774 | assert(g:match("axxc") == 5) |
| 710 | checkeqlab({nil, 0, "c"}, g:match("c")) | 775 | checklabeq({nil, 0, "c"}, g:match("c")) |
| 711 | checkeqlab({nil, 0, "fail"}, g:match("fail")) | 776 | checklabeq({nil, 0, "fail"}, g:match("fail")) |
| 712 | 777 | ||
| 713 | 778 | ||
| 714 | 779 | ||
| @@ -824,25 +889,25 @@ print(eval "(1+1-1*(2/2+)-():") | |||
| 824 | print("+") | 889 | print("+") |
| 825 | 890 | ||
| 826 | local g = m.P{ | 891 | local g = m.P{ |
| 827 | "S", | 892 | "S", |
| 828 | S = V"End" + V'A' * V'S', | 893 | S = V"End" + V'A' * V'S', |
| 829 | A = P'a' + T(1), | 894 | A = P'a' + T(1), |
| 830 | End = P"." * (-P(1) + T(2)), | 895 | End = P"." * (-P(1) + T(2)), |
| 831 | } | 896 | } |
| 832 | 897 | ||
| 833 | assert(g:match("a.") == 3) | 898 | assert(g:match("a.") == 3) |
| 834 | assert(g:match("aa.") == 4) | 899 | assert(g:match("aa.") == 4) |
| 835 | assert(g:match(".") == 2) | 900 | assert(g:match(".") == 2) |
| 836 | checkeqlab({nil, 1, "ba."}, g:match("ba.")) | 901 | checklabeq({nil, 1, "ba."}, g:match("ba.")) |
| 837 | checkeqlab({nil, 1, "ba."}, g:match("aba.")) | 902 | checklabeq({nil, 1, "ba."}, g:match("aba.")) |
| 838 | checkeqlab({nil, 1, "cba."}, g:match("cba.")) | 903 | checklabeq({nil, 1, "cba."}, g:match("cba.")) |
| 839 | checkeqlab({nil, 2, "a"}, g:match("a.a")) | 904 | checklabeq({nil, 2, "a"}, g:match("a.a")) |
| 840 | 905 | ||
| 841 | 906 | ||
| 842 | local g2 = m.P{ | 907 | local g2 = m.P{ |
| 843 | "S", | 908 | "S", |
| 844 | S = m.Rec(g, V"B", 1), | 909 | S = m.Rec(g, V"B", 1), |
| 845 | B = P'b'^1 + T(3) | 910 | B = P'b'^1 + T(3) |
| 846 | } | 911 | } |
| 847 | 912 | ||
| 848 | assert(g2:match("a.") == 3) | 913 | assert(g2:match("a.") == 3) |
| @@ -850,13 +915,13 @@ assert(g2:match("aa.") == 4) | |||
| 850 | assert(g2:match(".") == 2) | 915 | assert(g2:match(".") == 2) |
| 851 | assert(g2:match("ba.") == 4) | 916 | assert(g2:match("ba.") == 4) |
| 852 | assert(g2:match("aba.") == 5) | 917 | assert(g2:match("aba.") == 5) |
| 853 | checkeqlab({nil, 3, "cba."}, g2:match("cba.")) | 918 | checklabeq({nil, 3, "cba."}, g2:match("cba.")) |
| 854 | checkeqlab({nil, 2, "a"}, g2:match("a.a")) | 919 | checklabeq({nil, 2, "a"}, g2:match("a.a")) |
| 855 | 920 | ||
| 856 | local g3 = m.P{ | 921 | local g3 = m.P{ |
| 857 | "S", | 922 | "S", |
| 858 | S = m.Rec(g2, V"C", 2, 3), | 923 | S = m.Rec(g2, V"C", 2, 3), |
| 859 | C = P'c'^1 + T(4) | 924 | C = P'c'^1 + T(4) |
| 860 | } | 925 | } |
| 861 | 926 | ||
| 862 | assert(g3:match("a.") == 3) | 927 | assert(g3:match("a.") == 3) |
| @@ -865,14 +930,14 @@ assert(g3:match(".") == 2) | |||
| 865 | assert(g3:match("ba.") == 4) | 930 | assert(g3:match("ba.") == 4) |
| 866 | assert(g3:match("aba.") == 5) | 931 | assert(g3:match("aba.") == 5) |
| 867 | assert(g3:match("cba.") == 5) | 932 | assert(g3:match("cba.") == 5) |
| 868 | checkeqlab({nil, 4, "a"}, g3:match("a.a")) | 933 | checklabeq({nil, 4, "a"}, g3:match("a.a")) |
| 869 | checkeqlab({nil, 4, "dc"}, g3:match("dc")) | 934 | checklabeq({nil, 4, "dc"}, g3:match("dc")) |
| 870 | checkeqlab({nil, 4, "d"}, g3:match(".d")) | 935 | checklabeq({nil, 4, "d"}, g3:match(".d")) |
| 871 | 936 | ||
| 872 | 937 | ||
| 873 | -- testing more captures | 938 | -- testing more captures |
| 874 | local g = re.compile[[ | 939 | local g = re.compile[[ |
| 875 | S <- ( %s* &. {A} )* | 940 | S <- ( %s* &. {A} )* |
| 876 | A <- [0-9]+ / %{5} | 941 | A <- [0-9]+ / %{5} |
| 877 | ]] | 942 | ]] |
| 878 | 943 | ||
| @@ -886,7 +951,7 @@ checkeq({"44", "a ", "58", "123"}, {g2:match("44 a 123")}) | |||
| 886 | 951 | ||
| 887 | 952 | ||
| 888 | local g = re.compile[[ | 953 | local g = re.compile[[ |
| 889 | S <- ( %s* &. A )* | 954 | S <- ( %s* &. A )* |
| 890 | A <- {[0-9]+} / %{5} | 955 | A <- {[0-9]+} / %{5} |
| 891 | ]] | 956 | ]] |
| 892 | 957 | ||
| @@ -928,7 +993,7 @@ local function expect(patt, labname, recpatt) | |||
| 928 | table.insert(errors, {i, pos}) | 993 | table.insert(errors, {i, pos}) |
| 929 | return true | 994 | return true |
| 930 | end | 995 | end |
| 931 | if not recpatt then recpatt = P"" end | 996 | if not recpatt then recpatt = P"" end |
| 932 | --return Rec(patt, Cmt("", recorderror) * recpatt) | 997 | --return Rec(patt, Cmt("", recorderror) * recpatt) |
| 933 | return patt + T(i) | 998 | return patt + T(i) |
| 934 | end | 999 | end |
