in reply to Re: Perl6: Dynamic Grammars
in thread Perl6: Dynamic Grammars

A tweaked and simplified version:
my %sigils = bang => '!', at => '@', hash => '#', dollar => '$', percent => '%', caret => '^', and => '&', star => '*', zero => '0'; my regex line { ^^ :my $s; (\w+) <?{ $s = %sigils{$0} }> \h+ $s (\N*) $s $$ } .say for "star *foo*\nat @bar\nat @baz@" ~~ m:g/<line>/;

Replies are listed 'Best First'.
Re^3: Perl6: Dynamic Grammars
by OneTrueDabe (Acolyte) on Jun 10, 2016 at 03:30 UTC
    my regex line {
        ^^ :my $s; (\w+) <?{ $s = %sigils{$0} }> \h+ $s (\N*) $s $$
    }
    
    .say for "star *foo*\nat @bar\nat @baz@" ~~ m:g/<line>/;
    

    That's HOT! :-D

    But how would I rewrite my tests, then — which actually want to operate on the captured value?

    This seems clunky and naïve: (Not unlike myself... «grin»)

    #!/usr/bin/env perl6 use Test; my %sigils = bang => '!', at => '@', hash => '#', dollar => '$', percent => '%', caret => '^', and => '&', star => '*', zero => '0'; my regex line { ^^ :my $s; (\w+) <?{ $s = %sigils{$0} }> \h+ $s (\N*) $s $$ } is ('bang !one!' ~~ m/<line>/)<line>[1], 'one', 'is bang!one'; is ('zero 0one0' ~~ m/<line>/)<line>[1], 'one', 'is zero0one'; isnt 'bang @one@' ~~ m/<line>/ && $<line>[1], 'one', 'isnt bang@one'; isnt 'BONK !one!' ~~ m/<line>/ && $<line>[1], 'one', 'isnt BONK!one'; nok 'bang @one@' ~~ m/<line>/, 'mismatch fails'; nok 'BONK !one!' ~~ m/<line>/, 'unknown fails';
      But how would I rewrite my tests, then — which actually want to operate on the captured value?
      This is Perl, so there's more than one way to do it, eg
      my %sigils = bang => '!', at => '@', hash => '#', dollar => '$', percent => '%', caret => '^', and => '&', star => '*', zero => '0'; my regex line { ^^ :my $s; (\w+) <?{ $s = %sigils{$0} }> \h+ $s (\N*) $s $$ { make ~$0 => ~$1 } } sub parse($_) { map *.<line>.made, m:g/<line>/ } say parse "star *foo*\nat @bar\nat @baz@";
      will generate a sequence of pairs with the key being the name of the sigil and the value the enclosed text.
      You can name a capture if you think that's an improvement over numbered captures (see the two lines with comments):

      my regex line { ^^ (\w+) :my $s; <?{ $s = %sigils{$0} }> \h+ $s $<foo>=\N* $s # Note the foo bit here ... $$ } is ('bang !one!' ~~ m/<line>/)<line><foo>, 'one', 'is bang!one'; # +... and here

      Another tweak is to drop one level of hash keys by using a grammar (again, see the two lines with comments):

      grammar g { regex TOP { # drop 'my'; name 'TOP' to simplify .parse call in `is +` test ^^ (\w+) :my $s; <?{ $s = %sigils{$0} }> \h+ $s $<foo>=\N* $s $$ } } is g.parse('bang !one!')<foo>, 'one', 'is bang!one'; # calling +.parse method on grammar defaults to starting with rule (regex) named + 'TOP'

      perl6.party (not mine)