我想在P6中创建一个宏,将其参数转换为字符串。 这是我的宏:
macro tfilter($expr) {
quasi {
my $str = Q ({{{$expr}}});
filter-sub $str;
};
}
以下是我的称呼方式:
my @some = tfilter(age < 50);
但是,当我运行程序时,我收到错误:
Unable to parse expression in quote words; couldn't find final '>'
我该如何解决这个问题?
答案 0 :(得分:9)
您的用例,通过宏将一些代码转换为字符串是非常合理的。虽然我遇到了同样的用例,但是还没有一个已建立的API(即使在我脑海中)。在以下情况下会很好:
assert a ** 2 + b ** 2 == c ** 2;
此assert
语句宏可以评估其表达式,如果失败,则可以将其打印出来。打印出来需要对其进行字符串化。 (事实上,在这种情况下,拥有文件和行信息也会很好。)
(编辑:007是一个语言实验室,可以在Perl 6中充实宏。)
现在在007中,如果你对Q对象(AST)进行字符串化,你会获得AST本身的精简对象表示,而不是它代表的代码:
$ bin/007 -e='say(~quasi { 2 + 2 })'
Q::Infix::Addition {
identifier: Q::Identifier "infix:+",
lhs: Q::Literal::Int 2,
rhs: Q::Literal::Int 2
}
这比输出源代码更有意义和更直接。还要考虑这样一个事实:首先可以构建永远不是源代码的AST。 (人们应该这样做。并将这些“合成Qtrees”与程序中的自然Qtrees混合。)
所以我们正在看的是Q节点上的一个名为.source
的属性。然后我们就可以做到这一点:
$ bin/007 -e='say((quasi { 2 + 2 }).source)'
2 + 2
(注意:还不行。)
这是一个有趣的问题.source
应该为合成Qtree输出什么。它应该抛出异常吗?或者只输出<black box source>
?或者尽最大努力将自己变成字符串源?
回到原来的代码,这条线让我着迷:
my $str = Q ({{{$expr}}});
这实际上是一个非常有说服力的尝试来表达你想要做的事情(将AST转换成它的字符串表示)。但我怀疑它是否会按原样运作。最后,它仍然是基于源代码作为字符串的C类思维。它的基本问题是你放置{{{$expr}}}
的地方(在字符串引用环境中) )不是表达式AST能够去的地方。从AST节点类型的角度来看,它没有进行类型检查,因为表达式不是引用环境的子类型。
希望有所帮助!
(PS:退一步,我认为你通过让filter-sub
接受一个字符串参数来做自己的伤害。你将对这个函数中的字符串做什么?解析它以获取信息?在这种情况下,你最好不要分析AST,而不是字符串。)
(PPS:Moritz ++ on #perl6
指出age < 50
中有一个不相关的语法错误需要解决.Perl 6在使用它们之前对它们的定义很挑剔;宏不会改变这个等式很多。因此,Perl 6解析器会假设age
是一个你尚未声明的函数。然后它会考虑<
一个开头的引号字符。最后它会感到失望的是没有>
。再次,宏不会让你不需要预先声明你的变量。(虽然请参阅#159进一步讨论。)