# Metaprogramming

The package `lang:bs:macro` contains a number of convenient utilities for interacting with the name tree, and generating abstract syntax trees for Basic Storm. These are presented below.

## Generating Names

When looking for names in the name tree it is necessary to create `core:lang:Name` instances that represent the desired name. This can be tedious to do by hand, so the `lang:bs:macro` package contains custom syntax for this purpose:

    lang:bs:SrcName name = name{a:b<c>};

The block `name` creates an instance of the `SrcName` class (which inherits from `Name`) that contains the name specified inside the curly brackets. An `SrcName` additionally keeps a reference to the location in the source code where the name was written, so that error messages can provide an accurate location.

The `name` syntax extends the allowed syntax for names slightly to allow accessing more "exotic" names more easily. It allows the name of each part to be enclosed in quotes like a string literal. String escapes are interpreted as usual. This makes it possible to access operators as follows:

    name{core:Int:"+"<core:Int, core:Int>};

## Accessing the Name Tree

Similarly to the `name` macro, it is often useful to reference entries in the name tree directly. The `named{}` syntax can be used to achieve this in a type-safe way. The `named` syntax looks up the name within the curly brackets at compile-time, and inserts a reference to the specified named entity in the generated code. This means that the `named{}` syntax incurs no overhead at runtime, since it compiles to a single load instruction. The `named{}` syntax supports the same extensions to names as `name{}` does.

Since Basic Storm knows the exact type of the named entity at compile time, `named{}` evaluates to the type of the referred named entity. This often eliminates the need for downcasts, that would be required when looking up names manually.

If no name is specified in the curly braces, the syntax evaluates to the current package.

For example:

    use lang:bs:macro;
    use core:lang;     // for Package
    use core:io;       // for Url

    Url findPackageDir() {
        Package current = named{}; // Get reference to current package
        unless (url = current.url)
            throw InternalError("Virtual package.");

        // If the package was not virtual, it has an Url:
        return url;
    }

Similarly, one can get a reference to other elements easily (full names are given for clarity, the normal name lookup rules apply, so it is possible to rely on use statements, etc.):

    // The integer type:
    Type intType = named{core:Int};

    // The array type for integers:
    Type arrayType = named{core:Array<core:Int>};

    // To string function for integers:
    Function toS = named{core:toS<core:Int>};

To disambiguate names, the names can be prefixed with a colon (`:`). This makes the name be resolved relative to the root of the name tree.

As an additional convenience, the special form `@parent` can be used as the first parameter of any name part. This special form matches the container of the matched entity. It makes it more convenient to match members of types. For example, the full name of the addition operator is `core.Int.+(core.Int, core.Int)`. It can be accessed usint `@parent` as follows:

    named{core:Int:"+"<@parent, core:Int>};

## Inspecting the Basic Storm AST

The `macro` package provides the syntax `dump{ <statement or expression> }` to inspect the abstract syntax tree in Basic Storm. The syntax simply captures the syntax tree and prints the string representation of it (by calling `toS`), and fowards it to the surrounding context. As such, the print happens whenever the code is compiled, and nothing is added to the generated code. In most cases, this is fairly uninteresting for constructs built into Basic Storm, as their string representations closely match the syntax. It is, however, very useful for debugging syntax extensions.

For example, it is possible to view how the `for` loop is transformed as follows:

    dump{ for (Int i = 0; i < 10; i++) {} }

## Inspecting the Generated IR

Similarly, the `macro` library contains the `dumpAsm` pseudo-function that dumps the generated intermediate code at the location. As with the `dump` syntax, this happens whenever the code is compiled, and does not affect the generated code.

Since Basic Storm stops generating code after a `return` statement, it is not possible to use `dumpAsm` to examine all IR of a function. There will always be a piece of the logic for returning the final value that will not be visible using this approach. It is still immensely useful for quickly debugging the output of custom syntax etc.

For example, one can inspect the IR generated for simple assignments as follows:

    Int x = 10;
    x++;
    dumpAsm;
    // ...

## Patterns

The `pattern` construct provided by the `lang:bs:macro` package allows easy generation of Basic Storm syntax trees from source code, without needing to manually creating each node. A pattern saves the parse tree generated by the parser in the source code, and transforms it when the pattern statement is evaluated. As such, evaluating a pattern statement, especially for a large piece of code, is associated with some cost. However, since the code is parsed ahead of time, the cost is not too large.

For example, we can generate a syntax tree that represents creating an array as follows:

    Expr x = pattern(block) {
        Array<Int> array;
        array.push(1);
        array.push(2);
    };
    print(x.toS());

The parameter `block` (expected to be a subclass of `lang.bs.Block`) to the `pattern` syntax dictates in which context identifiers inside the pattern should be resolved. This is the same mechanism that Basic Storm uses internally to keep track of the "current" block when instantiating AST nodes. When using patterns in the context of custom syntax extensions, the parent block is generally available as a parameter to the productions extended for the syntax extension (both `SStmt` and `SExpr` has a parameter `block` that contains the current block).

Patterns also allow inserting expressions generated by the surrounding code using the syntax `$name` or `${expression}`, similarly to the syntax used for string literals. The first version only allows a single identifier to be specified, while the second syntax allow arbitrary Basic Storm expressions to be evaluated and inserted at that location in the syntax tree. Regardless of which version is used, the identifier or expression is expected to evaluate to an instance of `lang.bs.Expr` or `core.lang.Type` depending on whether it appears in a location where an expression or a type is expected to appear.

For example, expressions can be inserted as follows:

    Expr e = Constant(SrcPos(), 20);
    Expr f = pattern(block) {
        10 * $e + ${Constant(SrcPos(), 10)};
    };
    print(f.toS());

Which produces the expression:

    {
        10 * 20 + 10;
    }

For example, types can be inserted as follows:

    Type t = named{core:Str};
    Expr e = pattern(block) {
         Object o = "hello";
         if (o as ${t})
             print(o);
    };
    print(e.toS());

Which produces the expression:

    {
        Object o = "hello";
        if (o as core:Str)
            print(o);
    }

It is also possible to insert a variable number of expressions into a parameter list, an array initializer, or a block using `@name` or `@{expression}`. In this case, the expression or identifier should evaluate to an array of `lang.bs.Expr` objects, which are inserted in sequence at the specified location. For example:

    Expr[] e = Expr:[Constant(SrcPos(), 1), Constant(SrcPos(), 2)];
    Expr f = pattern(block) {
        foo(@e, 8);
    };
    print(f.toS());

Which produces the expression:

    {
        foo(1, 2, 8);
    }

It is not necessary to use the `pattern` construct to create an entire block. It is also possible to create a pattern containing a single statement:

    Expr e = Constant(SrcPos(), 20);
    Expr f = pattern(block) 10 + $e;

As previously mentioned, patterns are useful when implementing syntax extensions. For example, we could implement a syntax for absolute values as follows:

BNF-file:

    SAtom => absExpr(block, expr) : "|", SExpr(block) expr, "|";

BS-file:

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

    Expr absExpr(Block block, Expr expr) {
        pattern(block) {
            Int tmp = $expr;
            if (tmp < 0) {
                0 - tmp;
            } else {
                tmp;
            }
        };
    }

From this example, we can also see that the patterns are hygienic, which means that if evaluating the expression `|tmp|` works as expected, even if `tmp` is used as a variable name inside the pattern.