How to reuse a language token in a custom Grammar (Raku)
Asked Answered
L

1

6

I want to reuse the token parameter from Perl6::Grammar in my custom slang to add a "custom-param" parameter without cargo culting.

What I mean:

my $main-grammar = $*LANG.slang_grammar('MAIN');
my $main-actions = $*LANG.slang_actions('MAIN');

role Nogil::NogilGrammar {
    token parameter { # the new one
        "custom-param" || < here the token stolen from $main-grammar.^find_method('parameter'); >
    }

my $grammar = $main-grammar.^mixin(Nogil::NogilGrammar);
my $actions = $main-actions.^mixin(Nogil::NogilActions);
$*LANG.define_slang('MAIN', $grammar, $actions);

Not sure it is clear: it is like calling the parent token in a token of a role. I know the role will overwrite it so I kept a backup of pristine object in $grammar.

Already tested:

  1. Define it as a method returning the Match object of the parent but got the following error:
P6opaque: no such attribute '$!pos' on type NQPMatch in a Scalar when trying to get a value 
  1. Return from a Regex code interpolation
Attempt to return outside of immediately-enclosing Routine (i.e. `return` execution is outside the dynamic scope of the Routine where `return` was used)
Lawn answered 1/4, 2020 at 16:6 Comment(1)
Maybe easyer: Can I transform a NQPMatch object in Match ?Lawn
L
5

Intro: After many similar errors with nqp, I figured out:

Brief: nqp + Scalar in error message -> replace = by :=

Explain: Use the bind operator := and not assignment = which autobox in a Scalar hence the error message with Scalar.

Demo: A fully working example (use in BEGIN phaser). Trying "my" sigil and "their" (compile in the language) in case mine fails.

my $main-grammar = $*LANG.slang_grammar('MAIN');
my $main-actions = $*LANG.slang_actions('MAIN');

role Nogil::NogilGrammar {

    method sigil {
        # Bind
        my $sigil-they := $main-grammar.^find_method('sigil');
        my $sigil-me := self.sigil-eu;
        # Check My
        return $sigil-me if $sigil-me;
        # Return Their
        return $sigil-they(self);
    }

    token sigil-eu { '€' }
}

my $grammar = $main-grammar.^mixin(Nogil::NogilGrammar);
$*LANG.define_slang('MAIN', $grammar, $main-actions);

Note1: I removed some say essential for the demo. Just add .Str to those exoteric objects (NQPMatches).

Note2: If you want to create temporary variables (like $res), keep binding (:=).

Lawn answered 2/4, 2020 at 7:2 Comment(3)
Hello, I've run your code and get the error: Dynamic variable $*LANG not found in block <unit> at - line 2. Not sure what to do, thanks.Highsounding
I may have forgotten to prepend use nqp; use QAST:from<NQP>; The LANG dynamic variable is defined in nqp parsers.Lawn
there is the grammar.rakumod code I ended up withLawn

© 2022 - 2024 — McMap. All rights reserved.