Raku Books / Creating a Compiler in Raku / Building AST
Value nodes
Consider a bit bigger program:
my c = 2 + 3;Here, we are expecting that the compiler will generate the code to
add two numbers. We are not considering any optimisations at this point,
so we have to generate the AST nodes for every arithmetical operation.
Comparing with the last AST tree, we can see that the value attribute of
the AST::ScalarDeclaration node should not be a number but
some other kind of the node that represents addition. To keep the design
simple, it is wise to introduce AST nodes whose only work is to keep
values, either integers, or floating point, or strings.
class AST::NumberValue is ASTNode {
has $.value;
}If there is no value (as in a minimal variable declaration without initialiser), we can assign either 0 or an empty string, but the better solution is to define the null value and its wrapper AST node:
class AST::Null is ASTNode {
}The AST::ScalarDeclaration node must now point to an AST
node, so let us restrict the type of its value
attribute:
class AST::ScalarDeclaration is ASTNode {
has Str $.variable-name;
has ASTNode $.value;
}We are adding two more AST nodes to the tree, as shown in the diagram below.
The value node must be generated by the number action of
the grammar:
method number($/) {
$/.make(AST::NumberValue.new(value => +$/));
}This node is taken as is in the scalar-declaration
method, but if there is no value, then an AST::Null node is
created:
method scalar-declaration($/) {
$/.make(AST::ScalarDeclaration.new(
variable-name => ~$<variable-name>,
value => $<value> ??
$<value>.made !!
AST::Null.new(),
));
}Extend the program with another variable declaration:
my c = b;This time, we’ve got a variable instead of a value. But as soon as
the type of the $.value attribute in
AST::ScalarDeclaration is ASTNode, we can make
a new class, AST::Variable, and save an instance of it. The
AST::Variable object has a string attribute
$.variable-name.
class AST::Variable is ASTNode {
has Str $.variable-name;
}Integrating the new node type is easy, as most of our action methods have descriptive signatures:
multi method expr($/ where $<variable-name> && !$<index>) {
$/.make(AST::Variable.new(
variable-name => ~$<variable-name>));
}Here is the resulting AST tree:
This tree corresponds to the following program:
my a;
my b = 2;
my c = b;