🔬70. Examining the enum type in Perl 6

🔬70. Examining the enum type in Raku

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


In Perl 6, you can create enumerations like this:

enum colour <red orange yellow green blue violet>;

Having this said, you can use the new name as a type name and create variables of that type:

my colour $c;

$c = green;
say $c;     # green
say $c.Int; # 3

As you would rightly expect, the type of the variable is very predictable:

say $c.^name; # colour

Now, try to find the class implementation in Rakudo sources. Surprisingly, there is no file src/core/Enum.pm, but instead, there is src/core/Enumeration.pm. Looking at that file, you cannot say how our program works. Let us dig a bit.

In Grammar (src/Perl6/Grammar.nqp), you can find the following piece:

proto token type_declarator { <...> }

token type_declarator:sym<enum> {
    . . .
}

So, the enum is not a name of the data type but a predefined keyword, one of a few that exist for type declarations (together with subset and constant).

The token starts with consuming the keyword and making some preparations, which are not very interesting for us at the moment:

<sym><.kok>
:my $*IN_DECL := 'enum';
:my $*DOC := $*DECLARATOR_DOCS;
{ $*DECLARATOR_DOCS := '' }
:my $*POD_BLOCK;
:my $*DECLARAND;
{
    my $line_no := HLL::Compiler.lineof(self.orig(), self.from(), :cache(1));
    if $*PRECEDING_DECL_LINE < $line_no {
        $*PRECEDING_DECL_LINE := $line_no;
        $*PRECEDING_DECL := Mu; # actual declarand comes later, in Actions::type_declarator:sym<enum>
    }
}
<.attach_leading_docs>

Then, we expect either a name of the new type or a variable or nothing(?):

[
| <longname>
    {
     . . .
    }
| <variable>
| <?>
]

The variable part is not yet implemented:

> enum $x <a b c>
===SORRY!=== Error while compiling:
Variable case of enums not yet implemented. Sorry.
at line 2

Our test program falls to the first branch:

<longname>
  {
      my $longname := $*W.dissect_longname($<longname>);
      my @name := $longname.type_name_parts('enum name', :decl(1));
      if $*W.already_declared($*SCOPE, self.package, $*W.cur_lexpad(), @name) {
          $*W.throw($/, ['X', 'Redeclaration'],
                    symbol => $longname.name(),
          );
      }
  }

For example, if you declare enum colour, then the $longname.name() returns colour colour. Thus, we extracted it. (Also notice how redeclaration is handled.)

Finally, here is the rest of the token body:

{ $*IN_DECL := ''; }
<.ws>
<trait>*
:my %*MYSTERY;
[ <?[<(«]> <term> <.ws> || <.panic: 'An enum must supply an expression using <>, «», or ()'> ]
<.explain_mystery> <.cry_sorrows>

Indeed, we need to explain the mystery here. So, there’s room for optional traits, fine:

<trait>*

There’s another construct that should match to avoid panic messages:

<?[<(«]> <term> <.ws>

Don’t be confused by the different number of opening and closing angle brackets here. The first part is a forward assertion with a character class:

<?  [<(«]  >

It looks if there is one of the <, (, or « opening bracket at this position. The panic message is displayed if it is not found there.

Our next expected guest is a term. Obviously, the whole part <red orange . . . violet> matches with it. Not that bad; what we need to do now is to understand what happens next.

One thought on “🔬70. Examining the enum type in Perl 6”

Leave a Reply

Your email address will not be published. Required fields are marked *

Retype the CAPTCHA code from the image
Change the CAPTCHA codeSpeak the CAPTCHA code