【问题标题】:How do I write a perl6 macro to enquote text?如何编写 perl6 宏来引用文本?
【发布时间】:2017-04-22 16:23:57
【问题描述】:

我希望在 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 '>'

我该如何解决这个问题?

【问题讨论】:

  • 只有 8 个字符 age &lt; 50 的程序会出现同样的错误。
  • Afaik,在当前(实验)宏设计/实现中,宏的所有参数都是ASTs。目前我不知道您如何(或是否)可以恢复到原始源代码。
  • @ralph 感谢您的 cmets。也许我所做的一开始并不是一个特别好的主意。我不是 Lisp 专家,但我认为如果这是一个 Lisp 宏,它不会对无与伦比的 '
  • 报错信息很差但是和宏无关。你还没有定义age。 Perl 6 必须立即 放弃 猜测您的意图,如果猜测错误则失败。社区选择让编译器猜测;当它看到一个未定义的“名词”时,它会猜测你稍后会将它定义为一个接受参数的子(函数)。所以它猜测&lt; 是争论的开始。 &lt; 可以作为参数开始的唯一方法是它是否是 "quote words" construct 的一部分。因此出现错误消息。

标签: macros raku


【解决方案1】:

您的用例,通过宏将一些代码转换为字符串,非常合理。尽管我遇到并考虑过相同的用例,但还没有为此建立的 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。 (人们应该这样做。并将这种“合成 Qtree”与来自程序的自然 Qtree 混合。)

所以也许我们正在查看的是 Q 节点上的一个属性,称为 .source 或其他东西。然后我们就可以这样做了:

$ bin/007 -e='say((quasi { 2 + 2 }).source)'
 2 + 2 

(注意:还不行。)

这是一个有趣的问题,.source 应该为合成 Qtree 输出什么。它应该抛出异常吗?还是只输出&lt;black box source&gt;?还是尽最大努力将自己变成字符串化的源?

回到你原来的代码,这行让我着迷:

my $str = Q ({{{$expr}}});

这实际上是一个非常有说服力的尝试来表达你想做的事情(将 AST 转换为它的字符串表示)。但我怀疑它是否会按原样工作。最后,它仍然是基于源代码作为字符串的一种思维方式 à la C。它的根本问题是您放置 {{{$expr}}} (在字符串引用环境中)的位置是不是表达式 AST 能够去的地方。从 AST 节点类型的角度来看,它不进行类型检查,因为表达式不是引用环境的子类型。

希望有帮助!

(PS: 退后一步,我认为你让filter-sub 接受一个字符串参数是在伤害自己。你将如何处理这个函数内部的字符串?解析它以获取信息?在这种情况下你最好分析 AST,而不是字符串。)

(PPS: Moritz++ on #perl6 指出age &lt; 50 中有一个不相关的语法错误需要解决。Perl 6 对在使用之前定义的东西很挑剔;宏不会对这个等式有太大的改变。因此,Perl 6 解析器会假设age 是一个你还没有声明的函数。然后它会认为&lt; 是一个开头的引号字符。最终它会因为没有&gt; 而感到失望. 再次强调,宏并不能让您免于预先声明变量。(尽管请参阅#159 以进行进一步讨论。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 2011-08-08
    • 1970-01-01
    • 2013-09-01
    相关资源
    最近更新 更多