in reply to Parse::Recdescent optional subrule commit

I would say this is a bug, but I can't really be sure :)

According to my reading of http://search.cpan.org/~jtbraun/Parse-RecDescent-1.967009/lib/Parse/RecDescent.pm#Rejecting_a_production, if you replace reject:$failed with the equivalent

<reject: defined $failed> { print "WHAT!\n"; exit }

The program will print "WHAT!" and exit

So it could be that its a bug, or it could be the gotcha http://search.cpan.org/~jtbraun/Parse-RecDescent-1.967009/lib/Parse/RecDescent.pm#1._Expecting_an_error_to_always_invalidate_a_parse

update: It probably is a bug, because the actual equivalent would return UNDEF on failure and not EXIT, and when I do that, the error propagates, so it is probably a bug in reject autohandler or something ... Hooray, I can't fix it :)

#!/usr/bin/perl -- use Parse::RecDescent; my $grammar = q( myrule : <rulevar: local $failed> myrule : 'stuff' mysubrule(?) <reject: defined $failed> { print "WHAT +($failed)!\n"; undef } | <error> mysubrule: 'ID' <commit> '[' ']' | <error?> { $failed++ } ); my $parser = Parse::RecDescent->new($grammar) or die "hi"; for my $text ( "stuff ID something", "stuff something", ){ print "text => $text\n"; my $tree = eval { $parser->myrule($text) }; warn $@ if $@; use Data::Dump qw/ dd /; dd $tree; } __END__ text => stuff ID something WHAT ()! ERROR (line 1): Invalid mysubrule: Was expecting '[' but found "something" instead ERROR (line 1): Invalid myrule: Was expecting 'stuff' undef text => stuff something ERROR (line 1): Invalid myrule: Was expecting 'stuff' undef

update: It think this might be related issue, Bug #62892 for Parse-RecDescent: failed subrules eat text

Replies are listed 'Best First'.
Re^2: Parse::Recdescent optional subrule commit
by campugnatus (Initiate) on Apr 30, 2012 at 12:52 UTC
    Thanks for your attention!

    I don't see anything that looks like a bug here. Your program prints "WHAT ()!" and that is exactly what it should print when parsing "stuff ID something". Due to presence of 'ID' after 'stuff', mysubrule gets committed, therefore not increasing $failed but triggering <error?> instead.

    Anyway, that is not the case. As far as I see, my example works exactly as it is written, no unexpected behavior. However, that behaviour is not the one that solves the question that bothers me and the one asked in the FAQ.

    This is not even about <reject>, it is about the fact that $failed is increased only when mysubrule is NOT committed. And that seems just pointless! I think that $failed should only be increased when mysubrule gets committed and fails afterwards. I.e. <error?> and {$failed++} should happen simultaneously, and only that way. And I don't see any way to make that happen.

      I suspected I was completely off base :)