Re: parsing in different modes
> > I am working with a grammar that I would like to have operate in two > different modes. In both modes the rules are identical, but the methods > should behave differently. ... > As an illustration (not the actual problem), say we want to proces > arithmetical expressions in two modes: normally we just copy the input, but > within a pair of braces we directly calculate the result. My first thought was to subclass the grammar, and re-use the parsing while overriding some actions. But I didn't look into it, and saw you had an answer that keeps track of parsing depth. Still I wanted to try this by having different actions on the top-level vs inner parsing. To work with the example, I started with a grammar with no actions. grammar Sums { rule TOP { } token any-expr { + % } token operand { | } token bracketed-expr { '{' '}' } token op { <[-+]> } token int { \d+ } } and I realized that the differing actions can be hung on the different parts of the tree. "bracketed-expr" computes "any-expr", while "TOP" simply converts it to a string. class do-sums { method TOP($/) { make $.caps.map: { ($_ || $_.made).Str } } method operand($/) { make $ // $.made } method bracketed-expr($/) { make evaluate( $/ ) } sub evaluate($expr) { if $expr.caps.elems > 1 { return ($expr.caps).reduce: -> $left is rw, (:value(:$op),|), $right is rw { $left = evaluate($left) unless $left ~~ Numeric; $right= evaluate($right); given $op { when '+' { $left + $right } when '-' { $left - $right } } } } return $expr ?? evaluate($expr) !! $expr; } } # Try it out say Sums.parse('5', actions => do-sums.new).made; # 5 say Sums.parse('{6}+{8-{9+1+2}}-5', actions => do-sums.new).made; # 6 + -4 - 5 Which is a solution to "how do I keep one grammar, but do different things when the same token matches in different contexts." Not quite Theo's original question of "how to make a method behave differently at different parse depths" still it was a fun way to spend all morning... I'd like to simplify "sub evaluate"- in particular the deconstructed argument $op. That positional parameter is a Pair keyed on 'op', is there a clearer way of assigning it to $op? -y
Re: Special token names, or my mistake
Thanks! Timo's explanation nailed it, the problem is with the action not defining a method for "sum" so Any.sum becomes the action. The parsing works in grammar B without actions; "sum" is fine as a token name in that case. grammar B { rule TOP { } token sum { + % '+' } token int { \d+ } } say B.parse('5'); # OK
Re: Special token names, or my mistake
The grammar will never by itself try to call a subroutine, it only looks for methods in the action object. However, there is a "sum" method that An-Action inherits from Any. You can find it here: https://github.com/rakudo/rakudo/blob/master/src/core/Any.pm6#L440 It's probably a good idea to put an empty method of the same name that accepts one argument (the match object) into the action class. The same problem occurs with any of the other methods that already exist on Any. You can find them like this: perl6 -e 'Any.^methods(:all).>>.name.put'
Re: Special token names, or my mistake
Hi Yary, I'm not sure whether this is really the reason, but sum is the name of a built-in function (see https://docs.perl6.org/routine/sum). It seems that the compiler interprets your token as a subroutine call of that builtin. HTH, Laurent. 2018-08-12 9:28 GMT+02:00 yary : > If I call a token "sum", this example gives an error. If I call it > "something-else", it doesn't. I didn't expect an error in either case. > What's going on? > > ~~ actions-test.p6 ~~ > grammar A { > rule TOP { } > token something-else { + % '+' } > token int { \d+ } > } > > grammar B { > rule TOP { } > token sum { + % '+' } > token int { \d+ } > } > > class An-Action { > } > > say A.parse('5',actions => An-Action.new); # OK > say B.parse('5',actions => An-Action.new); # hopes, dashed > > __END__ > > The B.parse says "Too many positionals passed; expected 1 argument but got > 2 > in regex sum at action-test.p6 line 9 > in regex TOP at action-test.p6 line 8 > in block at action-test.p6 line 17" > > perl6 -v > This is Rakudo Star version 2018.06 built on MoarVM version 2018.06 > > > -y >
Special token names, or my mistake
If I call a token "sum", this example gives an error. If I call it "something-else", it doesn't. I didn't expect an error in either case. What's going on? ~~ actions-test.p6 ~~ grammar A { rule TOP { } token something-else { + % '+' } token int { \d+ } } grammar B { rule TOP { } token sum { + % '+' } token int { \d+ } } class An-Action { } say A.parse('5',actions => An-Action.new); # OK say B.parse('5',actions => An-Action.new); # hopes, dashed __END__ The B.parse says "Too many positionals passed; expected 1 argument but got 2 in regex sum at action-test.p6 line 9 in regex TOP at action-test.p6 line 8 in block at action-test.p6 line 17" perl6 -v This is Rakudo Star version 2018.06 built on MoarVM version 2018.06 -y