更新:需要明确的是,宏不仅是实验性的,而且非常初级和有缺陷。如需了解更多信息,请参阅Moritz's answer to another macros question。
让我们从你的代码开始吧:
use experimental :macros;
macro foo { 42 }
foo
这会产生相同的编译时错误:
Too few positionals passed; expected 3 arguments but got 2
如果从宏中返回 AST 对象以外的任何对象,则会出现此错误。1 这是合理的,因为这是 macro 构造的全部要点。错误消息不太好——但宏又是一个实验性功能。
所以你需要返回一个 AST。这是一种方法:
use experimental :macros;
macro foo { AST.new }
foo
这会产生 run-time 错误:
Useless use of constant value foo in sink context (line 3)
这表明宏已经完成了它的工作。编译器已完成编译并进入运行时。
显式返回AST 对象是错误的处理方式。第一个原因在AST doc 页面上给出:
目前还没有为 AST 定义 API。希望这将成为the work on macros 的一部分。
第二个原因是构造AST对象的更高级别的构造,即文档页面和Scimon提到的quasi { ... }构造3:
use experimental :macros;
macro foo { quasi { 42 } }
say foo; # 42
quasi 块告诉编译器将包含的语句编译成 AST 形式。
请注意,结果不是对应于块的 AST。在上面它是一个对应于42的AST对象。
所以,最后,回到你想要做的事情。
简化:
use experimental :macros;
macro foo { quasi { my $bar } }
foo;
say $bar
产量:
Error while compiling ... Variable '$bar' is not declared
鉴于:
use experimental :macros;
macro foo { quasi { class bar {} } }
foo;
say bar; # (bar)
因此,最重要的是,词法声明目前无法坚持。
实验还没有走到那一步。
Rakudo 实验宏的创建者 Carl Mäsak 正在007 继续实验。如果您在其 GH 回购中留下问题,Carl 会回答。
1 当编译器遇到对它知道是宏的例程的调用2 时,它会将宏调用替换为其结果。更详细的编译器:
如果您不返回 AST(ish) 对象,则最后一步会出现错误,并显示标题中的错误消息。
2 目前,如果您将宏定义放在调用之后,那么编译器不会意识到它是一个宏并将其视为普通例程:
use experimental :macros;
say foo; # 42
macro foo { 42 }
say bar; # AST.new
macro bar { quasi { 42 } }
say bar; # 42
如果这会导致编译时错误可能会更好。
3 宏冠军 Carl 喜欢 quasi 这个词。它借鉴了 lisp 的传统,而后者又来自于数学的传统。 Imo 这是一个“太可爱”的选择,不适合 P6。我的理由是 Perl 哲学建议新手选择具有熟悉含义的关键字。 “准”这个词有一个众所周知的正常英语含义,意思是“有点,但不是真的”。这根本没有帮助。 (我向 Carl 推荐了 toAST,但他更喜欢 quasi。)