🔬72. Superscripts in Perl 6

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> {
        $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));
}

As you can see here, it scans the digits and updates the $power variable by adding the value at the next decimal position (it is selected in the code above).

The available characters are listed in a string, and to get its value, the offset in the string is used. The $<dig> match contains a digit, you can see it in the Grammar:

<dig=[⁰¹²³⁴⁵⁶⁷⁸⁹]>+

 

One thought on “🔬72. Superscripts in Perl 6

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s