宏定义中的"位置太少"

jjm*_*elo 7 macros perl6

我试图用这种方式创建一些使用(实验)宏的例子:

use experimental :macros;
macro cards_vars() { 
  (<hearts clubs diamonds spades> X~ 1..10).map: { "my \$$^x = False;" }  
};
cards_vars(); 
say $hearts1;
Run Code Online (Sandbox Code Playgroud)

这将创建并运行宏,然后检查是否存在已定义的变量之一.但我得到这个错误:

Too few positionals passed; expected 3 arguments but got 2
Run Code Online (Sandbox Code Playgroud)

我甚至不知道那个错误来自哪里.我认为它在cards_vars()中,但我不知道是否是这种情况.声明没有括号的宏会产生相同的错误.

rai*_*iph 6

让我们从您的代码高尔夫开始:

use experimental :macros;
macro foo { 42 }
foo
Run Code Online (Sandbox Code Playgroud)

这会产生相同的编译时错误:

Too few positionals passed; expected 3 arguments but got 2
Run Code Online (Sandbox Code Playgroud)

如果AST从宏返回除对象之外的任何内容,则会出现此错误.鉴于这是macro构造的全部要点,这是合理的.1错误消息不是很棒 - 但是再次宏是一个实验性功能.


所以你需要返回一个AST.这是一种方式:

use experimental :macros;
macro foo { AST.new }
foo
Run Code Online (Sandbox Code Playgroud)

这会产生运行时错误:

Useless use of constant value foo in sink context (line 3)
Run Code Online (Sandbox Code Playgroud)

这表明宏已经完成了它的工作.编译器已完成编译并继续运行.


显式返回AST对象是错误的继续进行方式.第一个原因在ASTdoc页面上给出:

尚未为AST定义API.希望这将成为宏工作的一部分.

第二个原因是有一个更高级别的构造用于构造AST对象,即在doc页面和Scimon上提到的quasi { ... }构造3:

use experimental :macros;
macro foo { quasi { 42 } }
say foo; # 42
Run Code Online (Sandbox Code Playgroud)

quasi块告诉编译器将所包含的语句编译为AST形式.

注意,结果不是对应于块的AST.在上面它是一个对应的AST对象42.


所以,最后,回到你想要做的事情.

简化:

use experimental :macros;
macro foo { quasi { my $bar } }
foo;
say $bar
Run Code Online (Sandbox Code Playgroud)

收益率:

Error while compiling ... Variable '$bar' is not declared
Run Code Online (Sandbox Code Playgroud)

鉴于:

use experimental :macros;
macro foo { quasi { class bar {} } }
foo;
say bar; # (bar)
Run Code Online (Sandbox Code Playgroud)

因此,底线,词汇声明目前未能成功.

实验还没有那么远.

Rakudo实验宏的创建者CarlMäsak将在007继续进行实验.如果你在GH回购中留下问题,Carl会回答.


1当编译器遇到对它知道是宏2的例程的调用时,它会用其结果替换宏调用.更详细的编译器:

  • 将所有宏的参数编译为AST格式;

  • 调用宏(在编译时)以AST形式传递参数;

  • 运行预期返回AST对象的宏例程;

  • 将生成的AST对象拼接到正在构造的整个AST中.

如果您没有返回AST对象,则最后一步会出现标题中的错误消息.

2目前,如果在调用之后放置宏定义,则编译器不会意识到它是一个宏并将其视为普通例程:

use experimental :macros;
say foo; # 42
macro foo { 42 }
say bar; # AST.new
macro bar { quasi { 42 } }
say bar; # 42
Run Code Online (Sandbox Code Playgroud)

如果这会导致编译时错误,那么可能会更好.

3卡尔,宏冠军,喜欢这个词quasi.它吸取了来自数学遗产的lisp遗产.Imo这是一个"太可爱"的选择,它不太适合P6.我的理由是,Perl哲学建议选择具有新手熟悉意义的关键词."准"这个词有一个众所周知的正常英语含义,意思是"有点,但不是真的".这根本没用.(我建议toAST卡尔,但他更喜欢quasi.)


Sci*_*mon 5

所以有点戳,我找到了这个古老的万圣节文章:https://perl6advent.wordpress.com/2012/12/23/day-23-macros/

这给了一些指针.您需要使用quasi突出显示要输出的代码.但是让它创建一个变量?不确定.如果可能的话,我还在设定.