给 for 添加 else 分支
— 焉知非鱼标准 Raku 中, for
关键字是没有 else
分支的, 但是 Raku 可以实现 for...else
方言, 新建一个模块, 命名为 Slang::ForElse
, 其目录结构如下:
Slang/ForElse.pm6
其中 ForElse.pm6
的内容如下:
role ForElse::Grammar {
rule statement_control:sym<for> {
<sym><.kok> {}
<.vetPerl5Syntax>
<xblock(2)> {}
[ 'else' <elseblock=pblock> ]?
}
rule vetPerl5Syntax {
[ <?before 'my'? '$'\w+\s+'(' >
<.typed_panic: 'X::Syntax::P5'> ]?
[ <?before '(' <.EXPR>? ';' <.EXPR>? ';' <.EXPR>? ')' >
<.obs('C-style "for (;;)" loop', '"loop (;;)"')> ]?
}
}
role ForElse::Actions {
use nqp;
use QAST:from<NQP>;
sub lookup(Mu \match, \key) {
nqp::atkey(
nqp::findmethod(match, 'hash')(match),
key
).?ast
}
method statement_control:sym<for> (Mu $match) {
my $forloop := callsame;
if lookup($match, 'elseblock') -> $elseblock {
$match.make:
QAST::Op.new: :op<unless>, $forloop,
QAST::Op.new: :op<call>, $elseblock
}
}
}
sub EXPORT {
$*LANG.define_slang:
"MAIN",
$*LANG.slangs<MAIN> but ForElse::Grammar,
$*LANG.slangs<MAIN-actions> but ForElse::Actions;
return hash();
}
我们来测试一下这个模块, 在和 Slang 同一层级的目录中新建一个 for-else-example.pl6
的脚本, 其内容如下:
use lib 'Slang';
use ForElse;
my @values;
for @values -> $value {
say "Got $value";
}
else {
say "No values :("
}
发现打印出来是: No values :(
。