如何获取Raku语言中Grammar的token或regex的指针?
这个问题和类方法调用的类似场景逻辑不同,直接用Grammar实例的^lookup获取token后调用会触发类型错误。
测试代码
grammar TestGrammar { token num { \d+ } } my $test-grammar = TestGrammar.new(); my $token = $test-grammar.^lookup('num'); say "3" ~~ $token;
运行错误信息
Type check failed in binding to parameter '
'; expected TestGrammar but got Match (Match.new(:orig("3")...)
in regex num at pointer-to-token.raku line 2
in blockat pointer-to-token.raku line 9
这个错误说明token需要绑定到Grammar实例上下文,而非直接调用“裸”token方法引用。但尝试传入Grammar类型对象或实例时,又会触发另一个错误:
Cannot look up attributes in a TestGrammar type object. Did you forget a '.new'?
更新记录
更新:尝试使用^find_method方法,报错情况和之前一致;用assuming绑定实例也无法解决问题。
更新2:调整代码后不再报语法错误,但无论输入什么内容都返回False:
my $token = $test-grammar.^lookup('num').assuming($test-grammar); say "33" ~~ $token;
原因分析与解决方法
在Raku中,Grammar里的token本质是方法,但它的调用逻辑和普通方法存在差异:token在匹配时,Raku会自动处理Grammar实例、Match上下文等隐式参数的传递,而通过^lookup直接获取的方法引用没有正确绑定这些必要的上下文。
当使用~~操作符时,它期望右侧是一个可直接执行的匹配器,而非未绑定上下文的方法引用。正确的实现方式有两种:
写法1:直接调用实例的token
grammar TestGrammar { token num { \d+ } } my $test-grammar = TestGrammar.new(); say "3" ~~ $test-grammar.num; # 输出True
写法2:获取绑定实例的方法引用
如果需要先保存token的引用再调用,可以用&语法绑定实例上下文:
grammar TestGrammar { token num { \d+ } } my $test-grammar = TestGrammar.new(); my $token = &($test-grammar.num); say "33" ~~ $token; # 输出True
为什么assuming无效?
assuming只能绑定显式定义的参数,但token的调用还依赖隐式的Match上下文参数。~~操作符会把左侧字符串包装成Match对象传递给token,而用assuming绑定实例后,参数顺序和token期望的上下文结构不匹配,最终导致匹配失败。
内容的提问来源于stack exchange,提问作者jjmerelo

