Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Raku: Mutually recursive tokens cause a "method not found" error

Tags:

regex

raku

I've simplified a more complicated pattern I'm trying to match down to the following program:

my token paren { '(' <tok> ')' }
my token tok { <paren>? foo }

say "(foo)foo" ~~ /<tok>/;

This seems straightforward enough to me, but I get this error:

No such method 'tok' for invocant of type 'Match'.  Did you mean 'to'?
  in regex paren at a.p6 line 1
  in regex tok at a.p6 line 2
  in block <unit> at a.p6 line 4

What's the reason for this error?

The pattern matches without error if I change the first <tok> to <&tok>, but then I don't get a capture of that named pattern, which, in my original, more-complicated case, I need.

like image 959
Sean Avatar asked Jun 18 '21 21:06

Sean


2 Answers

The problem is that tok isn't in the current lexical namespace yet, so <tok> gets compiled as a method call instead.

If you force it to be a lexical call with &, it works.

my token paren { '(' <&tok> ')' }
my token tok { <paren>? foo }

say "(foo)foo" ~~ /<tok>/;

If <…> starts with anything other than a letter it doesn't capture.

So to capture it under the name tok, we add tok= to the <…>

my token paren { '(' <tok=&tok> ')' }
my token tok { <paren>? foo }

say "(foo)foo" ~~ /<tok>/;
like image 167
Brad Gilbert Avatar answered Oct 19 '22 10:10

Brad Gilbert


Brad's answer is correct, but I wanted to offer another possible solution: you can recurse within a single regex using the special <~~> token. Using that, plus a regular named capture, would create the captures you want in the simplified example in your question; here's how that would look:

my token paren { $<tok> = ['(' <~~> ')']? foo }

I'm not sure whether your more complicated case can be as easily re-written to recurse on itself rather than with two mutually recursive tokens. But, when this pattern works, it can simplify the code quite a bit.

like image 9
codesections Avatar answered Oct 19 '22 09:10

codesections