Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Raku, how does one create a Code object dynamically from a string?

Tags:

regex

raku


In Raku version v2022.06, I am trying to dynamically create grammar G having two productions …

  1. S → λ
  2. S → aSb

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 ?


Update …

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.


like image 490
user3134725 Avatar asked Aug 16 '26 09:08

user3134725


1 Answers

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 }'.

like image 68
Jonathan Worthington Avatar answered Aug 18 '26 11:08

Jonathan Worthington



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!