# Syntax and semantics

The core metalanguage is fairly small. It has only these four types of expressions:

* `ML99_call(F, ...)` invokes `F` with provided arguments. `F` must be either a functional macro identifier or an expression that evaluates to a functional macro identifier; `...` must comprise a non-empty sequence of comma-separated expressions.
* `v(...)` merely evaluates to its arguments, e.g. `v(123)` evaluates to `123`.
* `ML99_abort(...)` evaluates a non-empty sequence of comma-separated expressions and immediately aborts interpretation.
* `ML99_fatal(F, ...)` aborts interpretation with an appropriate error message.

(Indeed, expressions do nothing unless interpreted -- i.e., they are lazy.)

All metaprograms in Metalang99 represent a sequence of these syntactic forms. The interpreter itself is called via `ML99_EVAL(...)`.

Let's move on to examples. Consider this:

```c
ML99_EVAL(v(123), v(~), v(***))
```

It simply evaluates to `123 ~ ***` as expected. Now consider the mechanics of a functional macro (aka "metafunction"):

```c
#define F_IMPL(x, y, z) v(x + y + z)

ML99_EVAL(ML99_call(F, v(1), v(2), v(3)))
```

It evaluates to `1 + 2 + 3`. Here, `v(1), v(2), v(3)` is a sequence of comma-separated expressions provided to `F`: Metalang99 evaluates each one and applies them to `F` like this: `F_IMPL(1, 2, 3)`. Notice that if we write `ML99_call(F, v(1, 2, 3))`, we achieve the same result because `v(1, 2, 3)` evaluates to `1, 2, 3` -- exactly the same arguments.

As you can see, the syntax `ML99_call(F, ...)` is a bit inconvenient. For the sake of proper code formatting and IDE support, the convention used by the Metalang99 standard library is to define a wrapper macro that expands to a Metalang99 call:

```c
/// The documentation string.
#define FOO(a, b, c) ML99_call(FOO, a, b, c)
#define FOO_IMPL(a, b, c) // The implementation.
```

This way `FOO` can be conveniently called as `FOO(v(1), v(2), v(3))`.

### Recursion

Why do we need custom syntax for invoking functional macros? Because it lets you express recursion with no hassle! Consider the following demonstrative example:

```c
#define X_IMPL(op)        ML99_call(op, v(123))
#define CALL_X_IMPL(_123) ML99_call(X, v(ID))
#define ID_IMPL(x)        v(x)

ML99_EVAL(ML99_call(X, v(CALL_X)))
```

It evaluates to `123`, as expected. However, without Metalang99, the expansion gets blocked:

```c
#define X(op)        op(123)
#define CALL_X(_123) X(ID)
#define ID(x)        x

// X(ID)
X(CALL_X)
```

It happens because `X(CALL_X)` expands to `CALL_X(123)`, which, in turn, expands to `X(ID)` -- the recursive macro call which is blocked by the preprocessor (see the [Cloak wiki](https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms#recursion)).

General macro recursion allows expressing things that were inexpressible using vanilla preprocessor macros. For example, you can leverage [Cons-lists](https://metalang99.readthedocs.io/en/latest/list.html) to do pretty much anything with unbounded sequences of arguments, as we shall see later. Internally, such metafunctions as [`ML99_listReplicate`](https://metalang99.readthedocs.io/en/latest/list.html#c.ML99_listReplicate), [`ML99_listReverse`](https://metalang99.readthedocs.io/en/latest/list.html#c.ML99_listReverse), or [`ML99_listFilter`](https://metalang99.readthedocs.io/en/latest/list.html#c.ML99_listFilter) are implemented by structural recursion, which would be impossible without Metalang99.

### Appendix: The use of \`v\`

Throughout the examples, you might have noticed the extensive use of the `v(...)` expression. Although it may be a bit confusing for newcomers, the purpose of `v(...)` is pretty simple: just say the Metalang99 interpreter to evaluate your stuff inside the parentheses as-is.

Take a look at this *erroneous* metafunction:

```c
#define POW2_IMPL(x) x * x
```

If we try to use it like this: `ML99_EVAL(ML99_call(POW2, v(3)))`, Metalang99 would complain at us:

```
test.c:5:1: error: static assertion failed: "invalid term `3 * 3`"
    5 | ML99_EVAL(ML99_call(POW2, v(3)))
      | ^~~~~~~~~
```

The reason for this is that every single metafunction called by `ML99_call` (`ML99_callUneval`, `ML99_appl`) must emit a proper Metalang99 term;  `3 * 3` is not a proper term according to the core language syntax. To fix the problem, just wrap `x * x` into `v`:

```c
#define POW2_IMPL(x) v(x * x)
```

You can think of `v` as of a literal expression, like `"abc"` or `42` in most programming languages. However, if you want Metalang99 to evaluate an expression according to its semantics, you need **not** use `v(...)` but instead provide a computable term:

```c
#define GEN_IMPL(n) ML99_repeat(v(n), ML99_appl(v(ML99_cat), v(_)))

// _0 _1 _2 _3 _4
ML99_EVAL(ML99_call(GEN, v(5)))
```

The same holds for metafunction arguments.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hirrolot.gitbook.io/metalang99/syntax-and-semantics.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
