[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: LPeg: inconsistencies regarding empty captures
- From: Pierre-Yves Gérardy <pygy79@...>
- Date: Wed, 8 May 2013 23:34:16 +0200
On Wed, May 8, 2013 at 4:23 PM, Roberto Ierusalimschy
<roberto@inf.puc-rio.br> wrote:
>> /number skips captures with no values, whereas /string counts them. Example:
>>
>> > (Cg(Cc"foo", "z") * Cb"z" / 1):match"" --> "foo"
>>
>> > (Cg(Cc"foo", "z") * Cb"z" / "%1"):match""
>> stdin:2: no values in capture index 1
>>
>> > (Cg(Cc"foo", "z") * Cb"z" / "%2"):match"" --> "foo"
>
> This is really weird, although compatible with the documentation :).
The tests also rely on this behavior :).
> This seems to be a different case. Cg works like other captures that
> take a variable number of captures (e.g., function captures and
> table captures): when there is no values, they use the entire capture as
> a single value. Cf also works with a variable number of captures, but,
> unlike the other captures, it handles its first value in a very special
> way. So, it makes sense for it to complain when that value is missing.
> Moreover, for Cg (and Ct and /function), the behavior of using the
> entire match is quite convenient. For Cf, it seems useless.
In some cases, a subsequent capture may also be used as accumulator.
Actually, in some cases, the first value is not special.
function min(array) return fold(array,function(a,b) return a<b and a or b end)
I'd rather have fold behave like the others, if only for the
simplification of the documentation.
Something like this :
static int foldcap (CapState *cs) {
int n;
lua_State *L = cs->L;
int idx = cs->cap->idx;
if (isfullcap(cs->cap++) || /* no nested captures? */
- isclosecap(cs->cap) || /* no nested captures (large subject)? */
+ isclosecap(cs->cap) /* no nested captures (large subject)? */
- (n = pushcapture(cs)) == 0) /* nested captures with no values? */
return luaL_error(L, "no initial value for fold capture");
+ do {
+ n = pushcapture(cs) /* get the first value */
+ } while (n == 0 && !isclosecap(cs->cap));
+ if (n == 0)
+ lua_pushlstring(cs->L, cs->cap->s, cs->cap->siz - 1);
+ /*? return luaL_error(L, "no value in fold capture"); */
if (n > 1)
lua_pop(L, n - 1); /* leave only one result for accumulator */
while (!isclosecap(cs->cap)) {
lua_pushvalue(L, updatecache(cs, idx)); /* get folding function */
lua_insert(L, -2); /* put it before accumulator */
n = pushcapture(cs); /* get next capture's values */
lua_call(L, n + 1, 1); /* call folding function */
}
cs->cap++; /* skip close entry */
return 1; /* only accumulator left on the stack */
}
Remains the case where the first capture returns more than one value.
It could also make sense to apply the function in that case, rather
than to truncate the list.
If the user wanted to truncate the first capture, he could use /1.
-- Pierre-Yves