# Repeat Syntax Using the Basic Storm AST

This page assumes that you have followed the setup for the syntax extension guide already, so that you have somewhere to work. In this first stage, we will implement the `repeat` syntax as a form of macro using the facilities already present in Basic Storm.

## Syntax

The first step is to create the grammar for the new syntax. To do this, create a file `syntax.bnf` inside the directory `repeat`. Inside the file we start by using the `lang.bs` namespace to easily access the productions in Basic Storm, and then we define the delimiters as in the previous tutorial:

    use lang.bs;

    optional delimiter = SDelimiter;
    required delimiter = SRequiredDelimiter;

After this, we can add a production that extends the `SStmt` rule in Basic Storm. We pick the `SStmt` rule since the `repeat` block will act as a statement (i.e. it is not necessary to put a semicolon after it). We start simple, by adding just the syntax and saving transforms for later:

    SStmt : "repeat" #keyword, "(", SExpr, ")", SStmt;

This rule matches the word `repeat` (colored as a keyword), followed by a start parenthesis, an expression that indicates the number of iterations, and end parenthesis, and a statement that constitutes the body of the `repeat` block.

We can now write a simple test in the `test.bs` file as follows:

    void main() {
        repeat(5) {
            print("Hello");
        }
    }

If you try to run the test now (with `storm .`), you will receive a parse error (complaining about `{`). This is because we have not yet included our package, so the new syntax is not yet visible. To include the grammar, we simply add the following to the top of the file:

    use expressions:repeat;

If we run the test yet again, we will receive the error: "No return value specified for a production that does not return 'void'." This means that we have not yet added a transform function to our production. However, due to Storm's lazy compilation, this means that the rule was successfully matched at least!

So, the next step is to add logic for the transform. We start by adding a call to a function that creates a syntax node, and passing it the repeat count and the body of the statement:

    SStmt => repeatStmt(times, body) : "repeat" #keyword, "(", SExpr times, ")", SStmt body;

If we run the code now, Storm will complain that it is unable to transform a `lang.bs.Expr` with parameters `()`. This is because we have not passed the necessary parameters to the `SExpr` and `SStmt` rules. If we look in the Basic Storm grammar for the definition of the rules, we see that they accept a parameter named `block` that corresponds to the block in which they are located. Since we are a statement as well, we can simply forward our parameter of the same name. We also forward the parameter to the `repeatStmt` function, since we will need it:

    SStmt => repeatStmt(block, times, body) :
      "repeat" #keyword, "(", SExpr(block) times, ")", SStmt(block) body;

We try to run the code again. This time, we will receive an error stating that Storm is unable to find `repeatStmt` with parameters `(lang.bs.Block&, lang.bs.Expr&, lang.bs.Expr&)`. This is because we have not yet implemented the `repeatStmt` function. So let's do that. Create a file `sematics.bs` next to the `syntax.bnf` where we created the syntax. Then we add the following:

    use lang:bs;

    Expr repeatStmt(Block parent, Expr times, Expr body) on Compiler {
        Expr(core:lang:SrcPos());
    }

That is, we define a function that does nothing but return an empty expression (which we need to give a `SrcPos`). At this point, our example will actually compile and run without errors. However, since we have not yet implemented any semantics, our program will simply ignore the body of the `repeat` statement altogether (the reason it works at this stage is since we don't expect our `repeat` statement to return anything, and the no-op behavior of `Expr` works for that case).

## Semantics

The next step is to actually implement the behavior of our block. We do this by observing that:

    repeat(<times>) {
        <body>;
    }

is equivalent to:

    for (Nat i = <times>; i > 0; i--) {
        <body>;
    }

This means that we can use the patterns functionality from the `lang.bs.macro` package to create the AST nodes for us. We have already matched the placeholders `<times>` and `<body>` in our grammar. So using a `pattern`, we can insert them into the new structure using the `${...}` syntax:

    use lang:bs;
    use lang:bs:macro;

    Expr repeatStmt(Block parent, Expr times, Expr body) on Compiler {
        pattern(parent) {
            for (Nat i = ${times}; i > 0; i--) {
                ${body};
            }
        };
    }

At this point, our language extension works as indented. If we run the test program now (`storm .`), we see that the program prints `Hello` five times as intended.

It is worth noting that even though it looks like we introduce a variable `i` that is visible inside the body of the loop, this is not the case. Name lookup in Basic Storm is performed using the `block` that is passed to statements and expressions. Since we passed the block that corresponds to the context outside of the generated `for`-loop to the body of the loop, it will not be able to find any variables we generate inside the `pattern`, even though it will be placed inside the `for` loop eventually.

It is of course possible (and sometimes even necessary) to create AST nodes manually. Inspecting the grammar for Basic Storm can give some insights into what nodes exist, and how they are used.