# Testing, debugging, and error reporting

There is a handy macro for debugging a metaprogram. It is called `ML99_abort`:

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

// abc
ML99_EVAL(ML99_call(F, v(1), v(2), ML99_abort(v(abc))))
```

`ML99_abort` evaluates a provided sequence of expressions and immediately aborts the interpretation. Despite that we call `F`, the result of the interpretation is `abc`. Here is how Metalang99 evaluates the aforementioned expression:

* `v(1)` => `1`
* `v(2)` => `2`
* `ML99_abort(v(abc))` => `abc`, then halt.

`ML99_abort` is very handy when you need to figure out what is wrong with your metaprogram. I often use the bottom-up approach: first, I ensure that all lower-level macros work as expected, then move on to more general macros, and so on, till I find the problem. To test a specific macro, I call it inside `ML99_EVAL(...)` separately from the rest of a metaprogram. With `ML99_abort`, I usually trace macro parameters as well as any other interesting terms. You can see the result of interpretation with `-E` (GCC/Clang flag; preprocess only).

Secondly, errors need to be somehow emitted. For example, if we try to pop the head of the empty list, we obtain the following compilation error:

```
playground.c:3:1: error: static assertion failed: "ML99_listHead: expected a non-empty list"
    3 | ML99_EVAL(ML99_listHead(ML99_nil()))
      | ^~~~~~~~~
```

To emit such an error, call `ML99_fatal` like this:

\[`playground.c`]

```c
ML99_EVAL(ML99_fatal(F, the description of your error))
```

\[`/bin/sh`]

```
playground.c:3:1: error: static assertion failed: "F: the description of your error"
    3 | ML99_EVAL(ML99_fatal(F, the description of your error))
      | ^~~~~~~~~
```

Metalang99 also features the macros `ML99_todo` and `ML99_unimplemented` as well as their `*WithMsg` versions. Using them, you can indicate a not yet implemented and unimplemented functionality, respectively. The difference is that `ML99_todo`/`ML99_todoWithMsg` convey an intent that some piece of code is to be implemented later, while `ML99_unimplemented`/`ML99_unimplementedWithMsg` do not make such claims. Consider this code:

```c
#define FOO(...) \
    ML99_EVAL(ML99_IF( \
        ML99_VARIADICS_IS_SINGLE(__VA_ARGS__), \
        v(123), \
        ML99_todoWithMsg(v(FOO), v("Multiple arguments are not yet supported"))))

// 123
FOO(1)

// A not-yet-implemented error.
FOO(1, 2, 3)
```

Here, `FOO(1)` works just fine but we are not yet to handle multiple arguments. No problem, just insert `ML99_todoWithMsg` and implement it later.

And eventually, if you want to test your macro on certain input values, you can use assertions:

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

ML99_ASSERT(v(1 == 1));
ML99_ASSERT_EQ(ML99_call(F, v(1, 2, 3)), v(1 + 2 + 3));
ML99_ASSERT_EMPTY(ML99_call(CAT, v(), v()));
```

Learn more about assertions [here](https://metalang99.readthedocs.io/en/latest/assert.html).
