From e31e13f59ef1a4df1698b15ff1fe0198553cc3c2 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Tue, 6 Jun 2023 17:50:31 -0300 Subject: First implementation for the accumulator capture --- lpeg.html | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 9 deletions(-) (limited to 'lpeg.html') diff --git a/lpeg.html b/lpeg.html index f50d327..9faa1c7 100644 --- a/lpeg.html +++ b/lpeg.html @@ -638,6 +638,10 @@ or no value when number is zero. patt / function the returns of function applied to the captures of patt +patt % function + the return of function applied to the previous + capture plus the captures of patt; + the returned value becomes the value of the previous capture lpeg.Cmt(patt, function) the returns of function applied to the captures of patt; the application is done at match time @@ -889,6 +893,75 @@ there is no captured value.

+

patt % function

+

+Creates an accumulator capture. +This pattern behaves similarly to a +function capture, +with the following differences: +The last captured value is added as a first argument to +the call; +the return of the function is adjusted to one single value; +that value becomes the last captured value. +

+ +

+As an example, +consider the following code fragment: +

+
+local name = lpeg.C(lpeg.R("az")^1)
+local p = name * (lpeg.P("^") % string.upper)^-1
+print(p:match("count"))    --> count
+print(p:match("count^"))   --> COUNT
+
+

+In the first match, +the accumulator capture does not match, +and so the match results in its first capture, a name. +In the second match, +the accumulator capture matches, +so the function string.upper +is called with the previous capture (created by name) +plus the string "^"; +the function ignores its second argument and returns the first argument +changed to upper case; +that value then becomes the first and only +capture value created by the match. +

+-- matches a numeral and captures its numerical value +number = lpeg.R"09"^1 / tonumber + +-- auxiliary function to add two numbers +function add (acc, newvalue) return acc + newvalue end + +-- matches a list of numbers, adding their values +sum = number * ("," * number % add)^0 + +-- example of use +print(sum:match("10,30,43")) --> 83 + +

+First, the initial number captures a number; +that first capture will play the role of an accumulator. +Then, each time number matches inside the loop +there is a accumulator capture: +It calls add with the current value of the accumulator +and the value of the new number, +and their sum replaces the value of the accumulator. +At the end of the match, +the accumulator with all sums is the final value. +

+ +

+Due to the nature of this capture, +you should avoid using it in places where it is not clear +what is its "previous" capture. +Due to implementation details, +you should not use this capture inside a substitution capture. +

+ +

lpeg.Cmt(patt, function)

Creates a match-time capture. @@ -968,19 +1041,17 @@ lpeg.locale(lpeg) -- adds locale entries into 'lpeg' table local space = lpeg.space^0 local name = lpeg.C(lpeg.alpha^1) * space local sep = lpeg.S(",;") * space -local pair = lpeg.Cg(name * "=" * space * name) * sep^-1 -local list = lpeg.Cf(lpeg.Ct("") * pair^0, rawset) +local pair = name * "=" * space * name * sep^-1 +local list = lpeg.Ct("") * (pair % rawset)^0 t = list:match("a=b, c = hi; next = pi") --> { a = "b", c = "hi", next = "pi" }

Each pair has the format name = name followed by an optional separator (a comma or a semicolon). -The pair pattern encloses the pair in a group pattern, -so that the names become the values of a single capture. -The list pattern then folds these captures. +The list pattern then folds these captures. It starts with an empty table, created by a table capture matching an empty string; -then for each capture (a pair of names) it applies rawset +then for each a pair of names it applies rawset over the accumulator (the table) and the capture values (the pair of names). rawset returns the table itself, so the accumulator is always the table. @@ -1295,8 +1366,8 @@ end -- Grammar local V = lpeg.V G = lpeg.P{ "Exp", - Exp = lpeg.Cf(V"Term" * lpeg.Cg(TermOp * V"Term")^0, eval); - Term = lpeg.Cf(V"Factor" * lpeg.Cg(FactorOp * V"Factor")^0, eval); + Exp = V"Term" * (TermOp * V"Term" % eval)^0; + Term = V"Factor" * (FactorOp * V"Factor" % eval)^0; Factor = Number / tonumber + Open * V"Exp" * Close; } @@ -1304,7 +1375,7 @@ G = lpeg.P{ "Exp", print(lpeg.match(G, "3 + 5*9 / (1+1) - 12")) --> 13.5

-Note the use of the fold (accumulator) capture. +Note the use of the accumulator capture. To compute the value of an expression, the accumulator starts with the value of the first term, and then applies eval over -- cgit v1.2.3-55-g6feb