# 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).


---

# 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/testing-debugging-and-error-reporting.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.
