🔬72. Superscripts in Perl 6

# 🔬72. Superscripts in Raku

N. B. Perl 6 has been renamed to Raku. Click to read more.

In Perl 6, you can use superscript indices to calculate powers of numbers, for example:

```> 2⁵
32

> 7³
343```

It also works with more than one digit in the superscript:

```> 10¹²
1000000000000```

You can guess that the above cases are equivalent to the following:

```> 2**5
32
> 7**3
343

> 10**12
1000000000000```

But the question is: How on Earth does it work? Let us find it out.

For the Numeric role, the following operation is defined:

```proto sub postfix:<ⁿ>(Mu \$, Mu \$) is pure {*}
multi sub postfix:<ⁿ>(\a, \b) { a ** b }```

Aha, that is what we need, and the superscript notation is converted to the simple ** operator here.

You can visualise what exactly is passed to the operation by printing the operands:

```multi sub postfix:<ⁿ>(\a, \b) {
nqp::say('# a = ' ~ a);
nqp::say('# b = ' ~ b);
a ** b
}```

In this case, you’ll see the following output for the test examples above:

```> 2⁵
# a = 2
# b = 5

> 10¹²
# a = 10
# b = 12```

Now, it is time to understand how the postfix that extracts superscripts works. Its name, , written in superscript, should not mislead you. This is not a magic trick of the parser, this is just a name of the symbol, and it can be found in the Grammar:

```token postfix:sym<ⁿ> {
<sign=[⁻⁺¯]>? <dig=[⁰¹²³⁴⁵⁶⁷⁸⁹]>+ <O(|%autoincrement)>
}```

You see, this symbol is a sequence of superscripted digits with an optional sign before them. (Did you think of a sign before we reached this moment in the Grammar?)

Let us try negative powers, by the way:

```> say 4⁻³
# a = 4
# b = -3
0.015625```

Also notice that the whole construct is treated as a postfix operator. It can also be applied to variables, for example:

```> my \$x = 9
9
> say \$x²
# a = 9
# b = 2
81```

So, a digit in superscript is not a part of the variable’s name.

OK, the final part of the trilogy, the code in Actions, which parses the index:

```method postfix:sym<ⁿ>(\$/) {
my \$Int := \$*W.find_symbol(['Int']);
my \$power := nqp::box_i(0, \$Int);
for \$<dig> {
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:<ⁿ>'),
`<dig=[⁰¹²³⁴⁵⁶⁷⁸⁹]>+`