Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

perl6 grammar actions: unable to make anything if not using $/

I wrote a test program, and now it seems that if I don't use $/ in a method signature because I have to use .match inside the method, I can no long make anything. What did I do wrong?

A further question is that if .match sets $/, and $/ is read-only, then I cannot have $/ in the signature of a method that contains a .match statement, and I cannot have more than one .match inside the method because each .match will try to set the read-only $/. This will be very awkward to program.

Here is the test program with only one .match statement inside and the results:

The test program:

grammar test {
    regex TOP   { <foo><bar> }
    regex foo   { :i \s* foo \s* }
    regex bar   { :i \s  bar \s* }
}

class actTest {
    method foo ($x) {              # program fails if I use $/ in signature
      print "1 "; say $x;          # how to combine the 2 and show $x as match?
      print "2 "; say $x.WHAT;
      my $newStr = $x.Str;
      print "3 "; say $newStr;
      my $newMatch 
         = $newStr.match(/:i(f)(oo)/); # adverb cannot be outside?
      print "4 "; say $newMatch.WHAT;
      print "5 "; say $newMatch;
      print "6 "; say $/;
      my $oo = $newMatch[1].Str;
      print "10 "; say $oo;
      my $f = $newMatch[0].Str;
      print "11 "; say $f;
      my $result = $oo ~ $f;
      print "12 "; say $result;
      make $result;                # now I cannot make anything; huh???
    }
    method TOP ($/) { 
      print "8 "; say $<bar>;
      print "9 "; say $<foo>.made; # failed, method 'foo' makes nothing
      make $<bar> ~ $<foo>.made; 
    }
}

my $m = test.parse("Foo bar", actions => actTest.new);
print "7 "; say $m;

And the results:

1 「Foo 」
2 (Match)
3 Foo 
4 (Match)
5 「Foo」
 0 => 「F」
 1 => 「oo」
6 「Foo」
 0 => 「F」
 1 => 「oo」
10 oo
 11 F
 12 ooF
1 「Foo」
2 (Match)
3 Foo
4 (Match)
5 「Foo」
 0 => 「F」
 1 => 「oo」
6 「Foo」
 0 => 「F」
 1 => 「oo」
10 oo
11 F
12 ooF
8 「 bar」
9 (Any)
Use of uninitialized value of type Any in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to
something meaningful.
in method TOP at matchTest.pl line 28
7 「Foo bar」
 foo => 「Foo」
 bar => 「 bar」
like image 642
lisprogtor Avatar asked Dec 07 '16 21:12

lisprogtor


1 Answers

1) How to make without $/

make ... is just a shortcut for $/.make(...).

If you want to affect a different Match object than the one stored in $/, you have to use the method form directly, i.e. in your case $x.make($result).

2) When and why $/ is read-only

By default, $/ is bound to a normal item container (like a variable declared with my), i.e. not read-only. So there shouldn't be any problem with using the .match method multiple times in a routine.

It's only when you explicitly declare $/ as a parameter in a routine signature, that $/ will be bound directly to the Match object passed to that routine (not wrapped in an item container), and will thus be read-only inside the routine – because that's how normal signature binding works.

You could use the is copy trait to override the normal read-only parameter binding, and force $/ to be a mutable item container inside the routine:

method foo ($/ is copy) { ... }

This way, using .match inside the routine would work, and would store a new Match object in $/. But then you wouldn't have access to the original Match object passed to the routine anymore, and thus couldn't affect it with make. So for an action method that needs to use .match, using a custom parameter name like you did is the way to go.

like image 115
smls Avatar answered Nov 01 '22 10:11

smls