diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-06-06 17:50:31 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-06-06 17:50:31 -0300 |
commit | e31e13f59ef1a4df1698b15ff1fe0198553cc3c2 (patch) | |
tree | c16ea4f41bdd378734afd4e475d7d7973a5a2b5d | |
parent | 44fab2a44d06a956c3121ceba2b39ca7b00dc428 (diff) | |
download | lpeg-e31e13f59ef1a4df1698b15ff1fe0198553cc3c2.tar.gz lpeg-e31e13f59ef1a4df1698b15ff1fe0198553cc3c2.tar.bz2 lpeg-e31e13f59ef1a4df1698b15ff1fe0198553cc3c2.zip |
First implementation for the accumulator capture
-rw-r--r-- | HISTORY | 3 | ||||
-rw-r--r-- | lpcap.c | 24 | ||||
-rw-r--r-- | lpcap.h | 4 | ||||
-rw-r--r-- | lpeg.html | 89 | ||||
-rw-r--r-- | lpprint.c | 4 | ||||
-rw-r--r-- | lptree.c | 10 | ||||
-rw-r--r-- | makefile | 2 | ||||
-rwxr-xr-x | test.lua | 17 |
8 files changed, 131 insertions, 22 deletions
@@ -2,9 +2,12 @@ HISTORY for LPeg 1.1.0 | |||
2 | 2 | ||
3 | * Changes from version 1.0.2 to 1.1.0 | 3 | * Changes from version 1.0.2 to 1.1.0 |
4 | --------------------------------- | 4 | --------------------------------- |
5 | + accumulator capture | ||
5 | + UTF-8 ranges | 6 | + UTF-8 ranges |
6 | + Larger limit for number of rules in a grammar | 7 | + Larger limit for number of rules in a grammar |
8 | + Larger limit for number of captures in a match | ||
7 | + bug fixes | 9 | + bug fixes |
10 | + other small improvements | ||
8 | 11 | ||
9 | * Changes from version 1.0.1 to 1.0.2 | 12 | * Changes from version 1.0.1 to 1.0.2 |
10 | --------------------------------- | 13 | --------------------------------- |
@@ -231,6 +231,22 @@ static int functioncap (CapState *cs) { | |||
231 | 231 | ||
232 | 232 | ||
233 | /* | 233 | /* |
234 | ** Accumulator capture | ||
235 | */ | ||
236 | static int accumulatorcap (CapState *cs) { | ||
237 | lua_State *L = cs->L; | ||
238 | int n; | ||
239 | if (lua_gettop(L) < cs->firstcap) | ||
240 | luaL_error(L, "no previous value for accumulator capture"); | ||
241 | pushluaval(cs); /* push function */ | ||
242 | lua_insert(L, -2); /* previous value becomes first argument */ | ||
243 | n = pushnestedvalues(cs, 0); /* push nested captures */ | ||
244 | lua_call(L, n + 1, 1); /* call function */ | ||
245 | return 0; /* did not add any extra value */ | ||
246 | } | ||
247 | |||
248 | |||
249 | /* | ||
234 | ** Select capture | 250 | ** Select capture |
235 | */ | 251 | */ |
236 | static int numcap (CapState *cs) { | 252 | static int numcap (CapState *cs) { |
@@ -422,13 +438,16 @@ static int addonestring (luaL_Buffer *b, CapState *cs, const char *what) { | |||
422 | case Csubst: | 438 | case Csubst: |
423 | substcap(b, cs); /* add capture directly to buffer */ | 439 | substcap(b, cs); /* add capture directly to buffer */ |
424 | return 1; | 440 | return 1; |
441 | case Cacc: /* accumulator capture? */ | ||
442 | return luaL_error(cs->L, "accumulator capture inside substitution capture"); | ||
425 | default: { | 443 | default: { |
426 | lua_State *L = cs->L; | 444 | lua_State *L = cs->L; |
427 | int n = pushcapture(cs); | 445 | int n = pushcapture(cs); |
428 | if (n > 0) { | 446 | if (n > 0) { |
429 | if (n > 1) lua_pop(L, n - 1); /* only one result */ | 447 | if (n > 1) lua_pop(L, n - 1); /* only one result */ |
430 | if (!lua_isstring(L, -1)) | 448 | if (!lua_isstring(L, -1)) |
431 | luaL_error(L, "invalid %s value (a %s)", what, luaL_typename(L, -1)); | 449 | return luaL_error(L, "invalid %s value (a %s)", |
450 | what, luaL_typename(L, -1)); | ||
432 | luaL_addvalue(b); | 451 | luaL_addvalue(b); |
433 | } | 452 | } |
434 | return n; | 453 | return n; |
@@ -512,6 +531,7 @@ static int pushcapture (CapState *cs) { | |||
512 | case Cbackref: res = backrefcap(cs); break; | 531 | case Cbackref: res = backrefcap(cs); break; |
513 | case Ctable: res = tablecap(cs); break; | 532 | case Ctable: res = tablecap(cs); break; |
514 | case Cfunction: res = functioncap(cs); break; | 533 | case Cfunction: res = functioncap(cs); break; |
534 | case Cacc: res = accumulatorcap(cs); break; | ||
515 | case Cnum: res = numcap(cs); break; | 535 | case Cnum: res = numcap(cs); break; |
516 | case Cquery: res = querycap(cs); break; | 536 | case Cquery: res = querycap(cs); break; |
517 | case Cfold: res = foldcap(cs); break; | 537 | case Cfold: res = foldcap(cs); break; |
@@ -537,9 +557,11 @@ int getcaptures (lua_State *L, const char *s, const char *r, int ptop) { | |||
537 | CapState cs; | 557 | CapState cs; |
538 | cs.ocap = cs.cap = capture; cs.L = L; cs.reclevel = 0; | 558 | cs.ocap = cs.cap = capture; cs.L = L; cs.reclevel = 0; |
539 | cs.s = s; cs.valuecached = 0; cs.ptop = ptop; | 559 | cs.s = s; cs.valuecached = 0; cs.ptop = ptop; |
560 | cs.firstcap = lua_gettop(L) + 1; /* where first value (if any) will go */ | ||
540 | do { /* collect their values */ | 561 | do { /* collect their values */ |
541 | n += pushcapture(&cs); | 562 | n += pushcapture(&cs); |
542 | } while (!isclosecap(cs.cap)); | 563 | } while (!isclosecap(cs.cap)); |
564 | assert(lua_gettop(L) - cs.firstcap == n - 1); | ||
543 | } | 565 | } |
544 | if (n == 0) { /* no capture values? */ | 566 | if (n == 0) { /* no capture values? */ |
545 | lua_pushinteger(L, r - s + 1); /* return only end position */ | 567 | lua_pushinteger(L, r - s + 1); /* return only end position */ |
@@ -16,6 +16,7 @@ typedef enum CapKind { | |||
16 | Csimple, /* next node is pattern */ | 16 | Csimple, /* next node is pattern */ |
17 | Ctable, /* next node is pattern */ | 17 | Ctable, /* next node is pattern */ |
18 | Cfunction, /* ktable[key] is function; next node is pattern */ | 18 | Cfunction, /* ktable[key] is function; next node is pattern */ |
19 | Cacc, /* ktable[key] is function; next node is pattern */ | ||
19 | Cquery, /* ktable[key] is table; next node is pattern */ | 20 | Cquery, /* ktable[key] is table; next node is pattern */ |
20 | Cstring, /* ktable[key] is string; next node is pattern */ | 21 | Cstring, /* ktable[key] is string; next node is pattern */ |
21 | Cnum, /* numbered capture; 'key' is number of value to return */ | 22 | Cnum, /* numbered capture; 'key' is number of value to return */ |
@@ -38,7 +39,8 @@ typedef struct CapState { | |||
38 | Capture *cap; /* current capture */ | 39 | Capture *cap; /* current capture */ |
39 | Capture *ocap; /* (original) capture list */ | 40 | Capture *ocap; /* (original) capture list */ |
40 | lua_State *L; | 41 | lua_State *L; |
41 | int ptop; /* index of last argument to 'match' */ | 42 | int ptop; /* stack index of last argument to 'match' */ |
43 | int firstcap; /* stack index of first capture pushed in the stack */ | ||
42 | const char *s; /* original string */ | 44 | const char *s; /* original string */ |
43 | int valuecached; /* value stored in cache slot */ | 45 | int valuecached; /* value stored in cache slot */ |
44 | int reclevel; /* recursion level */ | 46 | int reclevel; /* recursion level */ |
@@ -638,6 +638,10 @@ or no value when <code>number</code> is zero.</td></tr> | |||
638 | <tr><td><a href="#cap-func"><code>patt / function</code></a></td> | 638 | <tr><td><a href="#cap-func"><code>patt / function</code></a></td> |
639 | <td>the returns of <code>function</code> applied to the captures | 639 | <td>the returns of <code>function</code> applied to the captures |
640 | of <code>patt</code></td></tr> | 640 | of <code>patt</code></td></tr> |
641 | <tr><td><a href="#cap-rep"><code>patt % function</code></a></td> | ||
642 | <td>the return of <code>function</code> applied to the previous | ||
643 | capture plus the captures of <code>patt</code></td></tr>; | ||
644 | the returned value becomes the value of the previous capture | ||
641 | <tr><td><a href="#matchtime"><code>lpeg.Cmt(patt, function)</code></a></td> | 645 | <tr><td><a href="#matchtime"><code>lpeg.Cmt(patt, function)</code></a></td> |
642 | <td>the returns of <code>function</code> applied to the captures | 646 | <td>the returns of <code>function</code> applied to the captures |
643 | of <code>patt</code>; the application is done at match time</td></tr> | 647 | of <code>patt</code>; the application is done at match time</td></tr> |
@@ -889,6 +893,75 @@ there is no captured value. | |||
889 | </p> | 893 | </p> |
890 | 894 | ||
891 | 895 | ||
896 | <h3><a name="cap-rep"></a><code>patt % function</code></h3> | ||
897 | <p> | ||
898 | Creates an <em>accumulator capture</em>. | ||
899 | This pattern behaves similarly to a | ||
900 | <a href="cap-func">function capture</a>, | ||
901 | with the following differences: | ||
902 | The last captured value is added as a first argument to | ||
903 | the call; | ||
904 | the return of the function is adjusted to one single value; | ||
905 | that value becomes the last captured value. | ||
906 | </p> | ||
907 | |||
908 | <p> | ||
909 | As an example, | ||
910 | consider the following code fragment: | ||
911 | </p> | ||
912 | <pre class="example"> | ||
913 | local name = lpeg.C(lpeg.R("az")^1) | ||
914 | local p = name * (lpeg.P("^") % string.upper)^-1 | ||
915 | print(p:match("count")) --> count | ||
916 | print(p:match("count^")) --> COUNT | ||
917 | </pre> | ||
918 | <p> | ||
919 | In the first match, | ||
920 | the accumulator capture does not match, | ||
921 | and so the match results in its first capture, a name. | ||
922 | In the second match, | ||
923 | the accumulator capture matches, | ||
924 | so the function <code>string.upper</code> | ||
925 | is called with the previous capture (created by <code>name</code>) | ||
926 | plus the string <code>"^"</code>; | ||
927 | the function ignores its second argument and returns the first argument | ||
928 | changed to upper case; | ||
929 | that value then becomes the first and only | ||
930 | capture value created by the match. | ||
931 | </p> | ||
932 | -- matches a numeral and captures its numerical value | ||
933 | number = lpeg.R"09"^1 / tonumber | ||
934 | |||
935 | -- auxiliary function to add two numbers | ||
936 | function add (acc, newvalue) return acc + newvalue end | ||
937 | |||
938 | -- matches a list of numbers, adding their values | ||
939 | sum = number * ("," * number % add)^0 | ||
940 | |||
941 | -- example of use | ||
942 | print(sum:match("10,30,43")) --> 83 | ||
943 | </pre> | ||
944 | <p> | ||
945 | First, the initial <code>number</code> captures a number; | ||
946 | that first capture will play the role of an accumulator. | ||
947 | Then, each time <code>number</code> matches inside the loop | ||
948 | there is a accumulator capture: | ||
949 | It calls <code>add</code> with the current value of the accumulator | ||
950 | and the value of the new number, | ||
951 | and their sum replaces the value of the accumulator. | ||
952 | At the end of the match, | ||
953 | the accumulator with all sums is the final value. | ||
954 | </p> | ||
955 | |||
956 | <p> | ||
957 | Due to the nature of this capture, | ||
958 | you should avoid using it in places where it is not clear | ||
959 | what is its "previous" capture. | ||
960 | Due to implementation details, | ||
961 | you should not use this capture inside a substitution capture. | ||
962 | </p> | ||
963 | |||
964 | |||
892 | <h3><a name="matchtime"></a><code>lpeg.Cmt(patt, function)</code></h3> | 965 | <h3><a name="matchtime"></a><code>lpeg.Cmt(patt, function)</code></h3> |
893 | <p> | 966 | <p> |
894 | Creates a <em>match-time capture</em>. | 967 | Creates a <em>match-time capture</em>. |
@@ -968,19 +1041,17 @@ lpeg.locale(lpeg) -- adds locale entries into 'lpeg' table | |||
968 | local space = lpeg.space^0 | 1041 | local space = lpeg.space^0 |
969 | local name = lpeg.C(lpeg.alpha^1) * space | 1042 | local name = lpeg.C(lpeg.alpha^1) * space |
970 | local sep = lpeg.S(",;") * space | 1043 | local sep = lpeg.S(",;") * space |
971 | local pair = lpeg.Cg(name * "=" * space * name) * sep^-1 | 1044 | local pair = name * "=" * space * name * sep^-1 |
972 | local list = lpeg.Cf(lpeg.Ct("") * pair^0, rawset) | 1045 | local list = lpeg.Ct("") * (pair % rawset)^0 |
973 | t = list:match("a=b, c = hi; next = pi") --> { a = "b", c = "hi", next = "pi" } | 1046 | t = list:match("a=b, c = hi; next = pi") --> { a = "b", c = "hi", next = "pi" } |
974 | </pre> | 1047 | </pre> |
975 | <p> | 1048 | <p> |
976 | Each pair has the format <code>name = name</code> followed by | 1049 | Each pair has the format <code>name = name</code> followed by |
977 | an optional separator (a comma or a semicolon). | 1050 | an optional separator (a comma or a semicolon). |
978 | The <code>pair</code> pattern encloses the pair in a group pattern, | 1051 | The <code>list</code> pattern then <em>folds</em> these captures. |
979 | so that the names become the values of a single capture. | ||
980 | The <code>list</code> pattern then folds these captures. | ||
981 | It starts with an empty table, | 1052 | It starts with an empty table, |
982 | created by a table capture matching an empty string; | 1053 | created by a table capture matching an empty string; |
983 | then for each capture (a pair of names) it applies <code>rawset</code> | 1054 | then for each a pair of names it applies <code>rawset</code> |
984 | over the accumulator (the table) and the capture values (the pair of names). | 1055 | over the accumulator (the table) and the capture values (the pair of names). |
985 | <code>rawset</code> returns the table itself, | 1056 | <code>rawset</code> returns the table itself, |
986 | so the accumulator is always the table. | 1057 | so the accumulator is always the table. |
@@ -1295,8 +1366,8 @@ end | |||
1295 | -- Grammar | 1366 | -- Grammar |
1296 | local V = lpeg.V | 1367 | local V = lpeg.V |
1297 | G = lpeg.P{ "Exp", | 1368 | G = lpeg.P{ "Exp", |
1298 | Exp = lpeg.Cf(V"Term" * lpeg.Cg(TermOp * V"Term")^0, eval); | 1369 | Exp = V"Term" * (TermOp * V"Term" % eval)^0; |
1299 | Term = lpeg.Cf(V"Factor" * lpeg.Cg(FactorOp * V"Factor")^0, eval); | 1370 | Term = V"Factor" * (FactorOp * V"Factor" % eval)^0; |
1300 | Factor = Number / tonumber + Open * V"Exp" * Close; | 1371 | Factor = Number / tonumber + Open * V"Exp" * Close; |
1301 | } | 1372 | } |
1302 | 1373 | ||
@@ -1304,7 +1375,7 @@ G = lpeg.P{ "Exp", | |||
1304 | print(lpeg.match(G, "3 + 5*9 / (1+1) - 12")) --> 13.5 | 1375 | print(lpeg.match(G, "3 + 5*9 / (1+1) - 12")) --> 13.5 |
1305 | </pre> | 1376 | </pre> |
1306 | <p> | 1377 | <p> |
1307 | Note the use of the fold (accumulator) capture. | 1378 | Note the use of the accumulator capture. |
1308 | To compute the value of an expression, | 1379 | To compute the value of an expression, |
1309 | the accumulator starts with the value of the first term, | 1380 | the accumulator starts with the value of the first term, |
1310 | and then applies <code>eval</code> over | 1381 | and then applies <code>eval</code> over |
@@ -60,7 +60,7 @@ static void printTcharset (TTree *tree) { | |||
60 | static const char *capkind (int kind) { | 60 | static const char *capkind (int kind) { |
61 | const char *const modes[] = { | 61 | const char *const modes[] = { |
62 | "close", "position", "constant", "backref", | 62 | "close", "position", "constant", "backref", |
63 | "argument", "simple", "table", "function", | 63 | "argument", "simple", "table", "function", "replace", |
64 | "query", "string", "num", "substitution", "fold", | 64 | "query", "string", "num", "substitution", "fold", |
65 | "runtime", "group"}; | 65 | "runtime", "group"}; |
66 | return modes[kind]; | 66 | return modes[kind]; |
@@ -147,7 +147,6 @@ void printpatt (Instruction *p) { | |||
147 | } | 147 | } |
148 | 148 | ||
149 | 149 | ||
150 | #if defined(LPEG_DEBUG) | ||
151 | static void printcap (Capture *cap) { | 150 | static void printcap (Capture *cap) { |
152 | printf("%s (idx: %d - size: %d) -> %p\n", | 151 | printf("%s (idx: %d - size: %d) -> %p\n", |
153 | capkind(cap->kind), cap->idx, cap->siz, cap->s); | 152 | capkind(cap->kind), cap->idx, cap->siz, cap->s); |
@@ -160,7 +159,6 @@ void printcaplist (Capture *cap, Capture *limit) { | |||
160 | printcap(cap); | 159 | printcap(cap); |
161 | printf("=======\n"); | 160 | printf("=======\n"); |
162 | } | 161 | } |
163 | #endif | ||
164 | 162 | ||
165 | /* }====================================================== */ | 163 | /* }====================================================== */ |
166 | 164 | ||
@@ -19,7 +19,7 @@ | |||
19 | const byte numsiblings[] = { | 19 | const byte numsiblings[] = { |
20 | 0, 0, 0, /* char, set, any */ | 20 | 0, 0, 0, /* char, set, any */ |
21 | 0, 0, 0, /* true, false, utf-range */ | 21 | 0, 0, 0, /* true, false, utf-range */ |
22 | 1, /* rep */ | 22 | 1, /* acc */ |
23 | 2, 2, /* seq, choice */ | 23 | 2, 2, /* seq, choice */ |
24 | 1, 1, /* not, and */ | 24 | 1, 1, /* not, and */ |
25 | 0, 0, 2, 1, 1, /* call, opencall, rule, prerule, grammar */ | 25 | 0, 0, 2, 1, 1, /* call, opencall, rule, prerule, grammar */ |
@@ -850,6 +850,11 @@ static int lp_divcapture (lua_State *L) { | |||
850 | } | 850 | } |
851 | 851 | ||
852 | 852 | ||
853 | static int lp_acccapture (lua_State *L) { | ||
854 | return capture_aux(L, Cacc, 2); | ||
855 | } | ||
856 | |||
857 | |||
853 | static int lp_substcapture (lua_State *L) { | 858 | static int lp_substcapture (lua_State *L) { |
854 | return capture_aux(L, Csubst, 0); | 859 | return capture_aux(L, Csubst, 0); |
855 | } | 860 | } |
@@ -1250,7 +1255,7 @@ static int lp_match (lua_State *L) { | |||
1250 | int ptop = lua_gettop(L); | 1255 | int ptop = lua_gettop(L); |
1251 | lua_pushnil(L); /* initialize subscache */ | 1256 | lua_pushnil(L); /* initialize subscache */ |
1252 | lua_pushlightuserdata(L, capture); /* initialize caplistidx */ | 1257 | lua_pushlightuserdata(L, capture); /* initialize caplistidx */ |
1253 | lua_getuservalue(L, 1); /* initialize penvidx */ | 1258 | lua_getuservalue(L, 1); /* initialize ktableidx */ |
1254 | r = match(L, s, s + i, s + l, code, capture, ptop); | 1259 | r = match(L, s, s + i, s + l, code, capture, ptop); |
1255 | if (r == NULL) { | 1260 | if (r == NULL) { |
1256 | lua_pushnil(L); | 1261 | lua_pushnil(L); |
@@ -1369,6 +1374,7 @@ static struct luaL_Reg metareg[] = { | |||
1369 | {"__gc", lp_gc}, | 1374 | {"__gc", lp_gc}, |
1370 | {"__len", lp_and}, | 1375 | {"__len", lp_and}, |
1371 | {"__div", lp_divcapture}, | 1376 | {"__div", lp_divcapture}, |
1377 | {"__mod", lp_acccapture}, | ||
1372 | {"__unm", lp_not}, | 1378 | {"__unm", lp_not}, |
1373 | {"__sub", lp_sub}, | 1379 | {"__sub", lp_sub}, |
1374 | {NULL, NULL} | 1380 | {NULL, NULL} |
@@ -3,7 +3,7 @@ LUADIR = ./lua/ | |||
3 | 3 | ||
4 | # COPT = -O2 -DNDEBUG | 4 | # COPT = -O2 -DNDEBUG |
5 | # COPT = -g | 5 | # COPT = -g |
6 | COPT = -DLPEG_DEBUG -g | 6 | COPT = -O0 -DLPEG_DEBUG -g |
7 | 7 | ||
8 | CWARNS = -Wall -Wextra -pedantic \ | 8 | CWARNS = -Wall -Wextra -pedantic \ |
9 | -Waggregate-return \ | 9 | -Waggregate-return \ |
@@ -493,8 +493,8 @@ local function f_term (v1, op, v2, d) | |||
493 | end | 493 | end |
494 | 494 | ||
495 | G = m.P{ "Exp", | 495 | G = m.P{ "Exp", |
496 | Exp = m.Cf(V"Factor" * m.Cg(FactorOp * V"Factor")^0, f_factor); | 496 | Exp = V"Factor" * (FactorOp * V"Factor" % f_factor)^0; |
497 | Factor = m.Cf(V"Term" * m.Cg(TermOp * V"Term")^0, f_term); | 497 | Factor = V"Term" * (TermOp * V"Term" % f_term)^0; |
498 | Term = Number / tonumber + Open * V"Exp" * Close; | 498 | Term = Number / tonumber + Open * V"Exp" * Close; |
499 | } | 499 | } |
500 | 500 | ||
@@ -866,6 +866,7 @@ print"+" | |||
866 | -- accumulator capture | 866 | -- accumulator capture |
867 | function f (x) return x + 1 end | 867 | function f (x) return x + 1 end |
868 | assert(m.match(m.Cf(m.Cc(0) * m.C(1)^0, f), "alo alo") == 7) | 868 | assert(m.match(m.Cf(m.Cc(0) * m.C(1)^0, f), "alo alo") == 7) |
869 | assert(m.match(m.Cc(0) * (m.C(1) % f)^0, "alo alo") == 7) | ||
869 | 870 | ||
870 | t = {m.match(m.Cf(m.Cc(1,2,3), error), "")} | 871 | t = {m.match(m.Cf(m.Cc(1,2,3), error), "")} |
871 | checkeq(t, {1}) | 872 | checkeq(t, {1}) |
@@ -875,7 +876,7 @@ t = p:match("a=b;c=du;xux=yuy;") | |||
875 | checkeq(t, {a="b", c="du", xux="yuy"}) | 876 | checkeq(t, {a="b", c="du", xux="yuy"}) |
876 | 877 | ||
877 | 878 | ||
878 | -- errors in accumulator capture | 879 | -- errors in fold capture |
879 | 880 | ||
880 | -- no initial capture | 881 | -- no initial capture |
881 | checkerr("no initial value", m.match, m.Cf(m.P(5), print), 'aaaaaa') | 882 | checkerr("no initial value", m.match, m.Cf(m.P(5), print), 'aaaaaa') |
@@ -883,8 +884,14 @@ checkerr("no initial value", m.match, m.Cf(m.P(5), print), 'aaaaaa') | |||
883 | checkerr("no initial value", m.match, m.Cf(m.P(500), print), | 884 | checkerr("no initial value", m.match, m.Cf(m.P(500), print), |
884 | string.rep('a', 600)) | 885 | string.rep('a', 600)) |
885 | 886 | ||
886 | -- nested capture produces no initial value | 887 | |
887 | checkerr("no initial value", m.match, m.Cf(m.P(1) / {}, print), "alo") | 888 | -- errors in accumulator capture |
889 | |||
890 | -- no initial capture | ||
891 | checkerr("no previous value", m.match, m.P(5) % print, 'aaaaaa') | ||
892 | -- no initial capture (very long match forces fold to be a pair open-close) | ||
893 | checkerr("no previous value", m.match, m.P(500) % print, | ||
894 | string.rep('a', 600)) | ||
888 | 895 | ||
889 | 896 | ||
890 | -- tests for loop checker | 897 | -- tests for loop checker |