6

... Or how to change $<sigil>.Str value from token sigil { ... } idependently from the matched text. Yes I'm asking how to cheat grammars above (i.e. calling) me.

I am trying to write a Slang for Raku without sigil.

So I want the nogil token, matching anything <?> to return NqpMatch that stringifies: $<sigil>.Str to '$'.

Currently, my token sigil look like that

token sigil {
    | <[$@%&]>
    | <nogil> { say "Nogil returned: ", lk($/, 'nogil').Str; # Here It should print "$"
              }
}
token nogil-proxy {
    | '€'
    | <?>
    {log "No sigil:", get-stack; }
}

And the method with that should return a NQPMatch with method Str overwritten

method nogil {
    my $cursor := self.nogil-proxy;
    # .. This si where Nqp expertise would be nice
    say "string is:", $cursor.Str;    # here also it should print "$"
    return $cursor;
}

Failed try:

$cursor.^cache_add('Str', sub { return '$'; } );
$cursor.^publish_method_cache;
for $cursor.^attributes { .name.say };
for $cursor.^methods { .name.say };
say $cursor.WHAT.Str;
nqp::setmethcacheauth($cursor, 0);

Currently, most of my tests work but I have problems in declarations without my (with no strict) like my-var = 42; because they are considered as method call.

@Arne-Sommer already made a post and an article. This is closely related. But this questions aims:

How can we customize the return value of a compile-time token and not how to declare it.

Tinmarino
  • 3,693
  • 24
  • 33
  • 2
    Perhaps try mixing a role that overrides `Str` into the match object, perhaps in a `sigil` action method. Though I suspect that'll only get you so far. Ultimately, the Raku grammar is formally ambiguous without sigils (that's why sigilless vars have to be introduced with `my \foo = ...`), so I suspect you'll run into endless problems trying to do this. – Jonathan Worthington Apr 02 '20 at 11:10
  • 1
    @JonathanWorthington What I think you're saying is that practical raku grammars in general are predominantly predictive; and the existing raku one is written to predictively expect, for example, `foo` in `my foo...` to be a type; and this and other such predictive presumptions run deep. However, aiui, an actual raku grammar "SHOULD" never be formally ambiguous unless it involves ["specified" scenarios declared to be ambiguous](https://stackoverflow.com/questions/49943078/whats-an-additional-tie-breaker-for-perl-6-longest-token-matching#comment87009542_49943078). Is that right afauk? – raiph Apr 02 '20 at 15:30
  • @JonathanWorthington: You __solved__ my problem. I did overlook `mixin` vs composition. And `Compose` method do not exists in `NQPMatch` but mixin is working. Thank You! – Tinmarino Apr 02 '20 at 16:08
  • 3
    @Tinmarino I was being a little informal there, yes; a concrete Raku grammar has tie-breakers that decide what will be parsed, and a parse thus doesn't ever fail with some kind of ambiguity error. My point was that the language design of Raku itself leans quite heavily on sigils. There's many examples; for instance, `:$foo` means `:foo($foo)`, but `:foo` means `:foo(True)`, and you thus can't have a convenience form of the colonpair construct for passing a variable on without sigils - or you have to drop the one for passing `True`. – Jonathan Worthington Apr 02 '20 at 16:33
  • 3
    @Tinmarino More fundamentally, though, you'll also have to arrange for things declared as variables to be recognized as terms rather than listops. Otherwise, `foo + bar` will parse as `foo` (listop) calling `bar` and applying the prefix `+` operator to it. Not an infix operator on two variables. – Jonathan Worthington Apr 02 '20 at 16:36
  • @JonathanWorthington: In short: You were right: all my test fail now. I managed to get what I wanted. Yippeee. I had to modify both actions and grammars. So `my foo = 37; say MY::` -> `{$foo => 37}`. So `foo` and `$foo` is the same thing in declaration: I can `say "Seems cool $foo"`. But then I cannot `foo + $foo` because no `foo` in `MY::` scope. So I'll have to cheat in many places. – Tinmarino Apr 02 '20 at 20:33
  • Anyway even permitting `foo` in scope (`>`) in ``. I have to check on routine call for `foo = 42` to be considered as a declaration. – Tinmarino Apr 02 '20 at 20:35

1 Answers1

6

Intro: The answer, pointed by @JonathanWorthington:

Brief: Use the mixin meta function. (And NOT the but requiring compose method.)

Demo:

  1. Create a NQPMatch object by retrieving another token: here the token sigil-my called by self.sigil-my.
  2. Use ^mixin with a role
method sigil { return self.sigil-my.^mixin(Nogil::StrGil); }

Context: full reproducible code:

So you can see what type are sigil-my and Nogil::StrGil. But I told you: token (more than method) and role (uninstantiable classes).

role Nogil::StrGil {
    method Str() {
        return sigilize(callsame);
    }
}


sub EXPORT(|) {

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

role Nogil::NogilGrammar {
    method sigil {
        return self.sigil-my.^mixin(Nogil::StrGil);
    }
}

token sigil-my { | <[$@%&]> | <?> }

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

# Return empty hash -> specify that we’re not exporting anything extra
return {};

}

Note: This opens the door to mush more problems (also pointed by jnthn question comments) -> -0fun !

Tinmarino
  • 3,693
  • 24
  • 33
  • @p6steve, yes it is crazy, so easy to modify many things at onces. Modules are very small in Raku for that reason I guess. – Tinmarino Apr 04 '20 at 02:47