在Raku中,如何从字符串中动态创建代码对象?
在Raku版本v2022.06中,我试图动态创建语法G具有两种作品……
- S→
- λS→ASB
我的草稿程序是…
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
程序输出是……
Perl6::Metamodel::GrammarHOW
(token TOP { <S> } token S { '' | 'a' <S> 'b' })
True
True
False
False
上面显示的草稿程序具有$ mytopcode
和$ myScode
硬编码。
但是,一个人如何(通过编程)动态地创建代码
对象$ mytopcode
和$ myScode
从@中的一对字符串。 variablerighthandsidesmap
?
更新…
下面的答案使我获得了以下草稿,该草稿产生了希望的产出(如上所示)……
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
任何建议(例如,提出上述草稿更简洁的建议)将不胜感激。
In Raku version v2022.06, I am trying to dynamically create grammar G having two productions …
- S → λ
- 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
函数可以用来解析,编译和评估Raku来源。如果要产生某种代码对象,请确保评估的表达式是一个代码对象,例如
evar'anon Regex {x}'
。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 }'
.在Rakuast分支降落之前,我会说使用
eval
。您可以在目前的Raku语法中使用Spelunk来找出目前的完成方式,但是不能保证在Rakuast分支降落之后仍然可以正常工作。
rakuast分支降落后,将是稳定的API。
Until the RakuAST branch lands, I'd say use
EVAL
.You could spelunk in the current Raku grammar to find out how that it is currently done, but there would be no guarantee that that would still work after the RakuAST branch lands.
After the RakuAST branch lands, there would be a stable API to do this.