Raku 中的 Superscripts
在 Raku 中,可以使用上标索引来计算数字的幂数,例如:
> 2⁵
32
> 7³
343
也可以在上标中使用多个数字:
> 10¹²
1000000000000
你可以猜到,上面的代码等同于这样:
> 2**5
32
> 7**3
343
> 10**12
1000000000000
但问题是:上标到底是如何工作的?让我们找出答案。
对于 Numeric
角色,定义了以下操作:
proto sub postfix:<ⁿ>(Mu $, Mu $) is pure {*}
multi sub postfix:<ⁿ>(\a, \b) { a ** b }
啊哈,这就是我们需要的,上标符号在这里转换为简单的 **
运算符。
您可以通过打印操作数来可视化传递给操作的确切内容:
multi sub postfix:<ⁿ>(\a, \b) {
nqp::say('# a = ' ~ a);
nqp::say('# b = ' ~ b);
a ** b
}
这个时候,你会看到上面的测试示例输出如下:
> 2⁵
# a = 2
# b = 5
> 10¹²
# a = 10
# b = 12
现在,是时候理解提取上标的后缀是如何工作的了。它的名字 ⁿ
用上标写成,不应误导你。这不是解析器的魔术,这只是符号的名称,它可以在 Grammar 中找到:
token postfix:sym<ⁿ> {
<sign=[⁻⁺¯]>? <dig=[⁰¹²³⁴⁵⁶⁷⁸⁹]>+ <O(|%autoincrement)>
}
你看,这个符号是一系列的上标数字,在它们之前有一个可选的符号。 (在 Grammar 到达这个时刻之前,你有没有想到过一个标志?)
顺便说一下,我们可以试试负数作为幂:
> say 4⁻³
# a = 4
# b = -3
0.015625
另请注意,整个构造被视为后缀运算符。它也可以应用于变量,例如:
> my $x = 9
9
> say $x²
# a = 9
# b = 2
81
所以,上标中的数字不是变量名称的一部分。
好的,三部曲的最后一部分,是解析索引的 Actions 代码:
method postfix:sym<ⁿ>($/) {
my $Int := $*W.find_symbol(['Int']);
my $power := nqp::box_i(0, $Int);
for $<dig> {
$power := nqp::add_I(
nqp::mul_I($power, nqp::box_i(10, $Int), $Int),
nqp::box_i(nqp::index("⁰¹²³⁴⁵⁶⁷⁸⁹", $_), $Int),
$Int);
}
$power := nqp::neg_I($power, $Int)
if $<sign> eq '⁻' || $<sign> eq '¯';
make QAST::Op.new(:op<call>, :name('&postfix:<ⁿ>'),
$*W.add_numeric_constant($/, 'Int', $power));
}
正如你在这里看到的那样,它扫描数字并通过在下一个小数位上添加值(在上面的代码中选择它)来更新 $power
变量。
可用字符在一个字符串中列出,为了得到它的值,使用字符串中的偏移量。 $<dig>
match 包含一个数字,您可以在 Grammar 中看到它:
<dig=[⁰¹²³⁴⁵⁶⁷⁸⁹]>+