In Raku version v2022.06, I am trying to dynamically create grammar G having two productions …
My draft program is …
sub MAIN ( )
{
my @variableRightHandSidesMap is Array[Pair] ;
@variableRightHandSidesMap.push: Pair.new("S", "") ;
@variableRightHandSidesMap.push: Pair.new("S", "'a' <S> 'b'") ;
constant Parser := Metamodel::GrammarHOW.new_type( name => 'Parser' ) ;
my $myTopCode = my token TOP { <S> } ;
my $mySCode = my token S { '' | 'a' <S> 'b' } ;
Parser.^add_method( 'TOP', $myTopCode ) ;
Parser.^add_method( 'S', $mySCode ) ;
Parser.^compose ;
say Parser.HOW.^name ;
say Parser.^methods( :local ) ;
say ?(Parser.parse: 'aabb') ;
say ?(Parser.parse: 'aaaaabbbbb') ;
say ?(Parser.parse: 'aabbb') ;
say ?(Parser.parse: 'abab') ;
} # end sub MAIN
Program output is …
Perl6::Metamodel::GrammarHOW
(token TOP { <S> } token S { '' | 'a' <S> 'b' })
True
True
False
False
The draft program shown above has $myTopCode and $mySCode hardcoded.
However, how does one dynamically (programmatically) create the Code objects $myTopCode and $mySCode from the pairs of strings in the @variableRightHandSidesMap ?
The answers below led me to the following draft, which produces the hoped‑for output (as shown above) …
use MONKEY-SEE-NO-EVAL ;
sub MAIN ( )
{
my @variableRightHandSidesMap is Array[Pair] ;
@variableRightHandSidesMap.push: Pair.new("S", "") ;
@variableRightHandSidesMap.push: Pair.new("S", "'a' <S> 'b'") ;
constant Parser := Metamodel::GrammarHOW.new_type( name => 'Parser' ) ;
my $startVariable = @variableRightHandSidesMap[0].key ; # 'S'
my $myTopCode = EVAL ( 'my token TOP { <' ~ $startVariable ~ '> }' ) ;
Parser.^add_method( 'TOP', $myTopCode ) ;
my Str $sCumulativeRightHandSide = '' ;
loop ( my $i = 0 ; $i < @variableRightHandSidesMap.elems ; $i++ )
{
if ( $i > 0 )
{
$sCumulativeRightHandSide ~= ( ' | ' ) ;
}
if ( @variableRightHandSidesMap[$i].value.chars <= 0 )
{
$sCumulativeRightHandSide ~= ( '\'\'' ) ;
}
else
{
$sCumulativeRightHandSide ~= ( @variableRightHandSidesMap[$i].value ) ;
} # end else
} # end loop
my $mySCode = EVAL ( 'my token ' ~ 'S' ~ ' { ' ~ $sCumulativeRightHandSide ~ ' }' ) ;
Parser.^add_method( 'S', $mySCode ) ;
Parser.^compose ;
say Parser.HOW.^name ;
say Parser.^methods( :local ) ;
say ?(Parser.parse: 'aabb') ;
say ?(Parser.parse: 'aaaaabbbbb') ;
say ?(Parser.parse: 'aabbb') ;
say ?(Parser.parse: 'abab') ;
} # end sub MAIN
Any suggestions (such as those making the above draft more concise) would be appreciated.
The EVAL function can be used to parse, compile, and evaluate Raku source. If you want to produce some kind of code object, then make sure the evaluated expression is a code object, e.g. EVAL 'anon regex { x }'.
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