diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-19 16:55:37 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-19 16:55:37 -0300 |
commit | c2680687d148820847607e13ed7100e60d94c79e (patch) | |
tree | 4a1bdc70a0f56bb1fa6dadebc90f99bb903bb548 | |
parent | ec24caa52eebabbba29d96875c8c62395849b5e2 (diff) | |
download | lpeg-c2680687d148820847607e13ed7100e60d94c79e.tar.gz lpeg-c2680687d148820847607e13ed7100e60d94c79e.tar.bz2 lpeg-c2680687d148820847607e13ed7100e60d94c79e.zip |
Bug: IBackCommit must remove dynamic captures, too
Like a fail, a IBackCommit instruction must remove any dynamic capture
made inside an 'and' pattern. (The added test for this problem
needs assertions on to detect the bug.)
-rw-r--r-- | lpvm.c | 2 | ||||
-rw-r--r-- | lpvm.h | 2 | ||||
-rwxr-xr-x | test.lua | 11 |
3 files changed, 14 insertions, 1 deletions
@@ -320,6 +320,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
320 | case IBackCommit: { | 320 | case IBackCommit: { |
321 | assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL); | 321 | assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL); |
322 | s = (--stack)->s; | 322 | s = (--stack)->s; |
323 | if (ndyncap > 0) /* are there matchtime captures? */ | ||
324 | ndyncap -= removedyncap(L, capture, stack->caplevel, captop); | ||
323 | captop = stack->caplevel; | 325 | captop = stack->caplevel; |
324 | p += getoffset(p); | 326 | p += getoffset(p); |
325 | continue; | 327 | continue; |
@@ -27,7 +27,7 @@ typedef enum Opcode { | |||
27 | IOpenCall, /* call rule number 'key' (must be closed to a ICall) */ | 27 | IOpenCall, /* call rule number 'key' (must be closed to a ICall) */ |
28 | ICommit, /* pop choice and jump to 'offset' */ | 28 | ICommit, /* pop choice and jump to 'offset' */ |
29 | IPartialCommit, /* update top choice to current position and jump */ | 29 | IPartialCommit, /* update top choice to current position and jump */ |
30 | IBackCommit, /* "fails" but jump to its own 'offset' */ | 30 | IBackCommit, /* backtrack like "fail" but jump to its own 'offset' */ |
31 | IFailTwice, /* pop one choice and then fail */ | 31 | IFailTwice, /* pop one choice and then fail */ |
32 | IFail, /* go back to saved state on choice and jump to saved offset */ | 32 | IFail, /* go back to saved state on choice and jump to saved offset */ |
33 | IGiveup, /* internal use */ | 33 | IGiveup, /* internal use */ |
@@ -1032,6 +1032,17 @@ local function id (s, i, ...) | |||
1032 | return true, ... | 1032 | return true, ... |
1033 | end | 1033 | end |
1034 | 1034 | ||
1035 | do -- run-time capture in an end predicate (should discard its value) | ||
1036 | local x = 0 | ||
1037 | function foo (s, i) | ||
1038 | x = x + 1 | ||
1039 | return true, x | ||
1040 | end | ||
1041 | |||
1042 | local p = #(m.Cmt("", foo) * "xx") * m.Cmt("", foo) | ||
1043 | assert(p:match("xx") == 2) | ||
1044 | end | ||
1045 | |||
1035 | assert(m.Cmt(m.Cs((m.Cmt(m.S'abc' / { a = 'x', c = 'y' }, id) + | 1046 | assert(m.Cmt(m.Cs((m.Cmt(m.S'abc' / { a = 'x', c = 'y' }, id) + |
1036 | m.R'09'^1 / string.char + | 1047 | m.R'09'^1 / string.char + |
1037 | m.P(1))^0), id):match"acb98+68c" == "xyb\98+\68y") | 1048 | m.P(1))^0), id):match"acb98+68c" == "xyb\98+\68y") |