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:

```bsstmt:use=lang.bs.macro
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:

```bsstmt:use=lang.bs.macro
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:

```bs
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.):

```bsstmt:use=lang.bs.macro
// 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>};
```


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:

```bsstmt:use=lang.bs.macro
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:

```bsstmt:use=lang.bs.macro
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:

```bsstmt:use=lang.bs.macro
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
[stormname:lang.bs.Expr] or [stormname: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:

```bsstmt:use=lang.bs.macro
Expr e = Constant(SrcPos(), 20);
Expr f = pattern(block) {
	10 * $e + ${Constant(SrcPos(), 10)};
};
print(f.toS());
```

Which produces the expression:

```bsstmt
{
	10 * 20 + 10;
}
```

For example, types can be inserted as follows:

```bsstmt:use=lang.bs.macro
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:

```bsstmt
{
    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 [stormname:lang.bs.Expr] objects, which are inserted in sequence at the
specified location. For example:

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

Which produces the expression:

```bsstmt
{
	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:

```bsstmt:use=lang.bs.macro
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:
```bnf
SAtom => absExpr(block, expr) : "|", SExpr(block) expr, "|";
```

BS-file:
```bs
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.
