Recently, I experimented with some grammars for modifying small parts of a file. In those test cases, I would keep much of the file as it was, only modifying small pieces here and there, see this review question for an example.
So I needed one (or a few) action methods (i.e. methods in the action class of the
grammar) where I would attach the modified parts of the file to the
match object using its
make method. The problem was that the grammar itself would have many more
token/rules/regex with complicated
nesting. Hence, there was a need to propagate (by successively calling
make()
) the small change (currently attached to
a token's match object) up to the TOP()
method in the action class
such that everything
else (all other tokens/rules/regexes) in the file was kept untouched
in the result returned from the grammar's .parse()
call.
So all methods in the action class except for one, was on the exact same form:
method make-data ($match-data) {
$match-data.make( [~] $match-data.chunks.map: {$_.value.?made // $_.value} );
}
Now, this explicit repetition of the same code for all action methods seems to me very verbose, and also breaks with the DRY programming principle.
Is there a way to tell the grammar class that if an action method
(corresponding to a token in the grammar) is
not specified , it will default to the make-data
method above (or a similar one)?
So in this case, I envision a DEFAULT()
method in the action class:
method DEFAULT ($match-data) {
$match-data.make( [~] $match-data.chunks.map: {$_.value.?made // $_.value} );
}
that is called if a token in the grammar class does not have a corresponding method in the action class.
Perl 6's Type system will call a FALLBACK method, if it's present in a class and an unknown method call is made.
The following solution adds default construction methods to the Calculations
actions class.
grammar Calculator {
token TOP { [ <add> | <sub> ] }
rule add { <num> '+' <num> }
rule sub { <num> '-' <num> }
token num { \d+ }
}
class Calculations {
method ws($) {}
method FALLBACK($token, $match-data) {
$match-data.make( [~] $match-data.chunks.map: {
$_.value.?made // $_.value;
} );
}
}
say Calculator.parse('2 + 3', actions => Calculations).made;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With