# `Expression.V2.Compile`

An compiler for AST returned by Expression.V2.Parser.

This reads the AST output returned by `Expression.V2.parse/1` and
compiles it to Elixir code.

It does this by emitting valid Elixir AST, mimicking what `quote/2` does.

The Elixir AST is then supplied to `Code.eval_quoted_with_env/3` without any
variable binding. What is returned is an anonymous function that accepts an
`Expression.V2.Context.t` struct and evaluates the code against that context.

Any function calls are applied to the callback module referenced in the context.
So if an expression uses a function called `foo(1, 2, 3)` then the callback's
`callback/3` function will be called as follows:

```elixir
apply(context.callback_module, :callback, ["foo", [1, 2, 3]])
```

There is some special handling of some functions that have specific Elixir AST
syntax requirements.

These are documented in the `to_quoted/2` function.

All variables referenced by the expression are scoped to `context.vars`.
However the full context is supplied to any function calls, giving
functions the privilege of doing more than the `context.vars` scope alone
would allow them to do.

# `compile`

```elixir
@spec compile([any()]) :: (Expression.V2.Context.t() -&gt; any())
```

Accepts AST as emitted by `Expression.V2.parse/1` and returns an anonymous function
that accepts a Context.t as an argument and returns the result  of the expression
against the given Context.

If the callback functions defined in the callback module are pure then this function
is also pure and is suitable for caching.

# `to_quoted`

```elixir
@spec to_quoted([term()] | term()) :: Macro.t()
```

Convert the AST returned from `Expression.V2.parse/1` into valid Elixir AST
that can be used by `Code.eval_quoted_with_env/3`.

There is some special handling here:

1. Lists are recursed to ensure that all list items are properly quoted.
2. ""Quoted strings"" are unquoted and returned as regular strings to the AST.
3. "Normal strings" are converted into Atoms and treated as such during eval.
4. Literals such as numbers & booleans are left as is.
5. Range.t items are converted to valid Elixir AST.
6. `&` and `&1` captures are generated into valid Elixir AST captures.
7. Any functions are generated as being function calls for the given callback module.

# `wrap_in_context`

```elixir
@spec wrap_in_context(Macro.t()) :: Macro.t()
```

Wrap an AST block into an anonymous function that accepts
a single argument called context.

This happens _after_ all the code generation completes. The code
generated expects a variable called `context` to exist, wrapping
it in this function ensures that it does.

This is the anonymous function that is returned to the caller.
The caller is then responsible to call it with the correct context
variables.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
