Raku Books / Creating a Compiler in Raku / Control Flow

Implementing if

The language construction we are going to implement first is the prefix if clause, demonstrated on the following example:

my flag = 42;
if flag say "Depends";
say "Always";

The if keyword is followed by a value and a statement. A value is a value in sense of our grammar, thus it is either a variable as in the example, or a string, or an expression. A statement can be any statement recognised by the statement rule.

Embedding the if clause to the grammar is simple, as we have all statement definitions in one rule:

rule condition {
    'if' <value>
}

rule statement {
    <condition> ? [
        | <statement=variable-declaration>
        | <statement=assignment>
        | <statement=function-call>
    ]
}

We have seen earlier that we should not execute the statement before we know if the condition is true. In the AST world, we can pick the statement node out of the tree and place it to an attribute of the condition node. Later, evaluator will decide whether to execute the statement node. So, we need a new kind of AST nodes:

class AST::Condition is ASTNode {
    has ASTNode $.value;
    has ASTNode $.statement;
}

In the actions class, the method trigged in response to a parsed statement should now be split into two branches. When there is no if clause, everything remains as is. When there is such a clause, the statement node is not put directly to the tree, but instead, an AST::Condition node is inserted in as a proxy:

multi method statement($/ where !$<condition>) {
    $/.make($<statement>.made);
}

multi method statement($/ where $<condition>) {
    $/.make(AST::Condition.new(
        value => $/<condition><value>.made,
        statement => $/<statement>.made,
    ));
}

The whole AST for the test program is drawn below.

diagram

Take a look at the two calls of say. The second one (in the right side of the diagram) is located on the top level, as one of the items of the TOP’s @.statements array. The first call is a child of the AST::Condition node.

The tree is built, and we can evaluate it. The LinguaEvaluator class needs a way to react to the AST::Condition type of AST nodes. If should check the condition value and pass execution further if needed.

multi method eval-node(AST::Condition $node) {
    if $node.value.value {
        self.eval-node($node.statement);
    }
}

That’s all! Test the program with different values of the flag variable and see how the program reacts.

To complete the implementation, add a test in the t directory:

my flag = 1;
if flag say "Printed"; ## Printed

flag = 0;
if flag say "Ignored";

say "Done"; ## Done

Course navigation

Control Flow   |   Implementing else