从特征控制移相器

CONTROL phasers from a trait

是否可以从特征中添加 CONTROL 移相器?

example from the docs之后,在运行时代码中添加自定义控件异常很简单:

class CX::Oops does X::Control {};
sub f { CONTROL { when CX::Oops { note 'Oops!'; .resume}}
        CX::Oops.new.throw;  }

f; # OUTPUT: «Oops»

然而,我尝试从一个特征中这样做并没有奏效:

sub trait_mod:<is>(Sub $fn, :$oopsable) {
    $fn.add_phaser: 'CONTROL', { when CX::Oops { note 'Oops!'; .resume} }}

sub g is oopsable { CX::Oops.new.throw; }
g; # OUTPUT: «control exception without handler»

.has_phasersfire_phasers(有趣的名字!)方法,我可以看出这个 添加控制移相器。我需要做些什么来将它注册为处理程序,还是我还缺少其他东西?

CATCHCONTROL 是否真的是移相器,这是一个有趣的问题。只要它们使用大写字母并且它们对特定时间发生的事情做出反应,它们就适合。然而,它们也在语法的不同部分被解析,作为语句控制,因此仅限于出现在语句级别。编译器也不会通过调用 add_phasers 来处理它们。异常处理程序意味着一些代码生成,并且是例程主体中生成的代码实际导致异常被处理。

可以合理地询问编译器是否不应该查看特征是否确实使用 CATCHCONTROL 调用了 add_phasers 然后相应地生成代码。但是,由于在当前的编译器实现中,处理程序是例程体的一部分,并且所有工作(优化除外)都在调用特征处理程序之前在例程体上完成,所以特征已经太晚了。

此外,CATCHCONTROL 块的主体不会像普通块一样简单编译,还会生成代码来处理 when 智能匹配,并重新抛出如果 none 的处理程序匹配则异常;至少这最后一步需要手动完成。还有一些关于更新$!,如果我没记错的话。

一个好消息是即将推出的基于 rakuast 的编译器前端将:

  1. 向特征处理程序中例程的 AST 提供 API。然后可以使用它在 AST 级别添加 CATCH/CONTROL 处理程序,从而获得所有正确的语义并执行与直接写入代码中的语义相同的操作。
  2. 将代码生成延迟到更晚的时间,以便时间也能计算出来。