OneTrueDabe has asked for the wisdom of the Perl Monks concerning the following question:
I admit this example is a bit contrived, but it helps focus on what I'm trying to do...
Say I have a file like:
bang !some text! at @more words@ percent %good stuff% star !not in stars!
I'm trying to match lines where the delimiter is specified by the keyword in the first column.
I can hard-code everything statically, like this:
#!/usr/bin/env perl6 use Test; our grammar StatGrammar { rule TOP { [ <bang-line> | <at-line> | <hash-line> | <dollar-line> | <percent-line> | <caret-line> | <and-line> | <star-line> ] } regex bang-line { ^ 'bang' \s+ '!' (.*?) '!' \n? $ } regex at-line { ^ 'at' \s+ '@' (.*?) '@' \n? $ } regex hash-line { ^ 'hash' \s+ '#' (.*?) '#' \n? $ } regex dollar-line { ^ 'dollar' \s+ '$' (.*?) '$' \n? $ } regex percent-line { ^ 'percent' \s+ '%' (.*?) '%' \n? $ } regex caret-line { ^ 'caret' \s+ '^' (.*?) '^' \n? $ } regex and-line { ^ 'and' \s+ '&' (.*?) '&' \n? $ } regex star-line { ^ 'star' \s+ '*' (.*?) '*' \n? $ } } our class StatActions { method TOP($/) { make $<bang-line>[0] if $<bang-line>; make $<at-line>[0] if $<at-line>; make $<hash-line>[0] if $<hash-line>; make $<dollar-line>[0] if $<dollar-line>; make $<percent-line>[0] if $<percent-line>; make $<caret-line>[0] if $<caret-line>; make $<and-line>[0] if $<and-line>; make $<star-line>[0] if $<star-line>; } } sub static(Str $str) { StatGrammar.parse($str, :actions(StatActions)).made } is static('bang !one!' ), 'one', 'parse bang!one ok'; isnt static('bang @one@' ), 'one', 'isnt bang@one ok'; nok StatGrammar.parse('bang @one@', :actions(StatActions)), 'nok';
But that feels kind of gross, and not very DRY...
I can also do this:
#!/usr/bin/env perl6 use Test; our %sigils = ( bang => '!', at => '@', hash => '#', dollar => '$', percent => '%', caret => '^', and => '&', star => '*', ); our grammar DynGrammar { regex TOP { ^ (\w+) \s+ (.*?) \n? $ } } our class DynActions { method TOP($/) { if $1.match( rx/ ^ "{%sigils{$0}}" (.*?) "{%sigils{$0}}" $ / ) - +> $match { make $match[0]; } } } sub dyn(Str $str) { DynGrammar.parse($str, :actions(DynActions)).made } is dyn('bang !one!' ), 'one', 'parse bang!one ok'; isnt dyn('bang @one@' ), 'one', 'isnt bang@one ok'; nok DynGrammar.parse('bang @one@', :actions(DynActions)), 'nok';
Which *ALMOST* works... Except that the mismatch, erm, "fails to fail".
Can anybody think of a way to either A: 'fail' a match from within an action, or B: move my pattern matching up into the grammar itself? (or C: tell me I'm going about it all wrong, and suggest a better way, hehe!)
Cheers! :-D
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Perl6: Dynamic Grammars
by OneTrueDabe (Acolyte) on Jun 01, 2016 at 14:43 UTC | |
by stevieb (Canon) on Jun 01, 2016 at 18:51 UTC | |
by bduggan (Pilgrim) on Jun 06, 2016 at 00:19 UTC | |
by Anonymous Monk on Jun 07, 2016 at 13:01 UTC | |
by OneTrueDabe (Acolyte) on Jun 10, 2016 at 03:30 UTC | |
by Anonymous Monk on Jun 13, 2016 at 22:58 UTC | |
by raiph (Deacon) on Jun 12, 2016 at 18:16 UTC |