At the beginning of the year, we began reading Perl 6’s Grammar. That exercise is very interesting but not that easy.
Today, let us take one more step and look at the statement.
The statement token is relatively compact. It is reproduced here with some simplifications (refer to src/Perl6/Grammar.nqp for the full code):
token statement($*LABEL = '') { <!before <.[\])}]> | $ > <!stopper> [ | <label> <statement($*LABEL)> { $*LABEL := '' if $*LABEL } | <statement_control> | <EXPR> [ || <?MARKED('endstmt')> || <.ws> <statement_mod_cond> <statement_mod_loop>? || <.ws> <statement_mod_loop> { my $sp := $<EXPR><statement_prefix>; if $sp && $sp<sym> eq 'do' { my $s := $<statement_mod_loop><sym>; $/.obs("do..." ~ $s, "repeat...while or repeat...until"); } } ]? | <?[;]> | <?stopper> | {} <.panic: "Bogus statement"> ] }
According to the definition, a statement cannot start with the closing ], ), or }. Neither it can be an empty string (don’t be confused by the word before).
<!before <.[\])}]> | $ >
If you are not familiar with Perl 6 regexes, this is a character class <[ ]> that includes the above-listed characters, having the square brackets escaped within the character class.
The stopper rule is a bit difficult to track down immediately, so let us skip it for now.
Finally, a list of alternatives follows in the pair of square brackets (which create a non-capturing group in Perl 6 regexes).
One of the alternatives is a labelled statement:
<label> <statement($*LABEL)>
Notice that as rules and tokens are methods (and grammar is a class), you can pass parameters to them.
A label is an identifier followed by a colon:
token label { <identifier> ':' <?[\s]> <.ws> }
(Again, I do not show the code which is not important for us at the moment; real definition includes some NQP code.)
Another alternative is a statement_control. It is a subject of separate research. Just look at the list of different rules and tokens that fall under the definition of statement controls:
proto rule statement_control { <...> } rule statement_control:sym<if> { . . . } rule statement_control:sym<unless> { . . . } rule statement_control:sym<without> { . . . } rule statement_control:sym<while> { . . . } rule statement_control:sym<repeat> { . . . } rule statement_control:sym<for> { . . . } rule statement_control:sym<whenever> { . . . } rule statement_control:sym<foreach> { . . . } token statement_control:sym<loop> { . . . } rule statement_control:sym<need> { . . . } token statement_control:sym<import> { . . . } token statement_control:sym<no> { . . . } token statement_control:sym<use> { . . . }
Finally, a statement can be an expression, EXPR. An expression can be followed by one of the keywords like if or unless:
proto rule statement_mod_cond { <...> } rule statement_mod_cond:sym<if> { <sym><.kok> <modifier_expr('if')> } rule statement_mod_cond:sym<unless> { <sym><.kok> <modifier_expr('unless')> } rule statement_mod_cond:sym<when> { <sym><.kok> <modifier_expr('when')> } rule statement_mod_cond:sym<with> { <sym><.kok> <modifier_expr('with')> } rule statement_mod_cond:sym<without>{ <sym><.kok> <modifier_expr('without')> }
proto rule statement_mod_loop { <...> } rule statement_mod_loop:sym<while> { <sym><.kok> <smexpr('while')> } rule statement_mod_loop:sym<until> { <sym><.kok> <smexpr('until')> } rule statement_mod_loop:sym<for> { <sym><.kok> <smexpr('for')> } rule statement_mod_loop:sym<given> { <sym><.kok> <smexpr('given')> }
The two alternative ending schemes:
|| <.ws> <statement_mod_cond> <statement_mod_loop>? || <.ws> <statement_mod_loop>
Double vertical bar allows the grammar to stop after the first match. Unlike a single bar, which chooses the longest match.
In the case the statement modifier comes with the do keyword, an error occurs:
{ my $sp := $<EXPR><statement_prefix>; if $sp && $sp<sym> eq 'do' { my $s := $<statement_mod_loop><sym>; $/.obs("do..." ~ $s, "repeat...while or repeat...until"); }
We already talked about this piece of code when we were discussing error messages for obsolete syntax.
And it’s time to stop for today. See you tomorrow with more exciting details about Perl 6’s internals.
Unless I’m reading this wrong, I think you’ve made a slight “thinko”…
Where you say, “Finally, a statement can be an expression, EXPR. An expression can be prefixed with one of the keywords like if or unless:”, I believe you mean “… can be followed by …”. If the EXPR is proceeded by “if” or “unless” it’s picked up by the branch. rule is for catching modifiers after the EXPR only.
Still loving the series…
Of course it is “followed by”. Thanks for spotting this.