aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/external
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2026-02-23 20:36:05 +0100
committerlemon <lsof@mailbox.org>2026-02-23 20:36:05 +0100
commit052144cabb126efe925a96f8a0597a0f2005d206 (patch)
tree4fd87244b9eef018b30e90fdff24c5b1a145a85e /test/external
parent4e9020dfb847d80475415f9f5914efaa50238767 (diff)
add metalang99 testsuite (preprocessor stress testing)
Diffstat (limited to 'test/external')
-rw-r--r--test/external/metalang99/.clang-format17
-rw-r--r--test/external/metalang99/.github/workflows/c-cpp.yml88
-rw-r--r--test/external/metalang99/.gitignore61
-rw-r--r--test/external/metalang99/.gitmodules3
-rw-r--r--test/external/metalang99/.readthedocs.yaml17
-rw-r--r--test/external/metalang99/ARCHITECTURE.md25
-rw-r--r--test/external/metalang99/CHANGELOG.md464
-rw-r--r--test/external/metalang99/CMakeLists.txt10
-rw-r--r--test/external/metalang99/CONTRIBUTING.md32
-rw-r--r--test/external/metalang99/Doxyfile2859
-rw-r--r--test/external/metalang99/LICENSE21
-rw-r--r--test/external/metalang99/README.md391
-rw-r--r--test/external/metalang99/bench/100_call.c12
-rw-r--r--test/external/metalang99/bench/100_v.c8
-rw-r--r--test/external/metalang99/bench/README.md3
-rw-r--r--test/external/metalang99/bench/compare_25_items.c6
-rw-r--r--test/external/metalang99/bench/filter_map.c9
-rw-r--r--test/external/metalang99/bench/list_of_63_items.c8
-rw-r--r--test/external/metalang99/bench/many_call_in_arg_pos.c10
-rw-r--r--test/external/metalang99/docs/Makefile20
-rw-r--r--test/external/metalang99/docs/assert.rst5
-rw-r--r--test/external/metalang99/docs/bool.rst5
-rw-r--r--test/external/metalang99/docs/choice.rst5
-rw-r--r--test/external/metalang99/docs/conf.py57
-rw-r--r--test/external/metalang99/docs/either.rst5
-rw-r--r--test/external/metalang99/docs/gen.rst5
-rw-r--r--test/external/metalang99/docs/ident.rst5
-rw-r--r--test/external/metalang99/docs/index.rst120
-rw-r--r--test/external/metalang99/docs/lang.rst5
-rw-r--r--test/external/metalang99/docs/list.rst5
-rw-r--r--test/external/metalang99/docs/make.bat35
-rw-r--r--test/external/metalang99/docs/maybe.rst5
-rw-r--r--test/external/metalang99/docs/nat.rst5
-rw-r--r--test/external/metalang99/docs/requirements.txt2
-rw-r--r--test/external/metalang99/docs/seq.rst5
-rw-r--r--test/external/metalang99/docs/stmt.rst5
-rw-r--r--test/external/metalang99/docs/tuple.rst5
-rw-r--r--test/external/metalang99/docs/util.rst5
-rw-r--r--test/external/metalang99/docs/variadics.rst5
-rw-r--r--test/external/metalang99/examples/.gitignore1
-rw-r--r--test/external/metalang99/examples/CMakeLists.txt30
-rw-r--r--test/external/metalang99/examples/ackermann.c22
-rw-r--r--test/external/metalang99/examples/assert_for_each.c31
-rw-r--r--test/external/metalang99/examples/binary_tree.c25
-rw-r--r--test/external/metalang99/examples/demo.c48
-rw-r--r--test/external/metalang99/examples/duffs_device.c76
-rw-r--r--test/external/metalang99/examples/factorial.c16
-rw-r--r--test/external/metalang99/examples/lambda_calculus.c209
-rw-r--r--test/external/metalang99/examples/overload.c15
-rw-r--r--test/external/metalang99/examples/rectangle.c25
-rw-r--r--test/external/metalang99/idioms.md44
-rw-r--r--test/external/metalang99/include/metalang99.h33
-rw-r--r--test/external/metalang99/include/metalang99/assert.h134
-rw-r--r--test/external/metalang99/include/metalang99/bool.h246
-rw-r--r--test/external/metalang99/include/metalang99/choice.h129
-rw-r--r--test/external/metalang99/include/metalang99/control.h13
-rw-r--r--test/external/metalang99/include/metalang99/either.h170
-rw-r--r--test/external/metalang99/include/metalang99/eval/acc.h14
-rw-r--r--test/external/metalang99/include/metalang99/eval/eval.h130
-rw-r--r--test/external/metalang99/include/metalang99/eval/rec.h1098
-rw-r--r--test/external/metalang99/include/metalang99/eval/syntax_checker.h42
-rw-r--r--test/external/metalang99/include/metalang99/gen.h407
-rw-r--r--test/external/metalang99/include/metalang99/ident.h429
-rw-r--r--test/external/metalang99/include/metalang99/lang.h246
-rw-r--r--test/external/metalang99/include/metalang99/lang/closure.h51
-rw-r--r--test/external/metalang99/include/metalang99/list.h1129
-rw-r--r--test/external/metalang99/include/metalang99/logical.h11
-rw-r--r--test/external/metalang99/include/metalang99/maybe.h143
-rw-r--r--test/external/metalang99/include/metalang99/nat.h526
-rw-r--r--test/external/metalang99/include/metalang99/nat/dec.h264
-rw-r--r--test/external/metalang99/include/metalang99/nat/div.h1172
-rw-r--r--test/external/metalang99/include/metalang99/nat/eq.h266
-rw-r--r--test/external/metalang99/include/metalang99/nat/inc.h264
-rw-r--r--test/external/metalang99/include/metalang99/priv/bool.h46
-rw-r--r--test/external/metalang99/include/metalang99/priv/compiler_specific.h69
-rw-r--r--test/external/metalang99/include/metalang99/priv/tuple.h33
-rw-r--r--test/external/metalang99/include/metalang99/priv/util.h27
-rw-r--r--test/external/metalang99/include/metalang99/seq.h204
-rw-r--r--test/external/metalang99/include/metalang99/stmt.h167
-rw-r--r--test/external/metalang99/include/metalang99/tuple.h371
-rw-r--r--test/external/metalang99/include/metalang99/util.h444
-rw-r--r--test/external/metalang99/include/metalang99/variadics.h274
-rw-r--r--test/external/metalang99/optimization_tips.md24
-rwxr-xr-xtest/external/metalang99/scripts/bench.sh16
-rw-r--r--test/external/metalang99/scripts/check-arities.py61
-rwxr-xr-xtest/external/metalang99/scripts/check-fmt.sh6
-rwxr-xr-xtest/external/metalang99/scripts/docs.sh3
-rwxr-xr-xtest/external/metalang99/scripts/fmt.sh5
-rwxr-xr-xtest/external/metalang99/scripts/open-docs.sh3
-rwxr-xr-xtest/external/metalang99/scripts/open-spec.sh3
-rwxr-xr-xtest/external/metalang99/scripts/spec.sh12
-rwxr-xr-xtest/external/metalang99/scripts/test-all.sh6
-rwxr-xr-xtest/external/metalang99/scripts/test-examples.sh8
-rwxr-xr-xtest/external/metalang99/scripts/test.sh16
-rw-r--r--test/external/metalang99/spec/.gitignore276
-rw-r--r--test/external/metalang99/spec/references.bib17
-rw-r--r--test/external/metalang99/spec/spec.pdfbin0 -> 201160 bytes
-rw-r--r--test/external/metalang99/spec/spec.tex289
-rw-r--r--test/external/metalang99/tests/.gitignore1
-rw-r--r--test/external/metalang99/tests/CMakeLists.txt38
-rw-r--r--test/external/metalang99/tests/assert.c19
-rw-r--r--test/external/metalang99/tests/bool.c121
-rw-r--r--test/external/metalang99/tests/choice.c64
-rw-r--r--test/external/metalang99/tests/either.c66
-rw-r--r--test/external/metalang99/tests/eval/rec.c25
-rw-r--r--test/external/metalang99/tests/gen.c283
-rw-r--r--test/external/metalang99/tests/ident.c395
-rw-r--r--test/external/metalang99/tests/lang.c165
-rw-r--r--test/external/metalang99/tests/list.c528
-rw-r--r--test/external/metalang99/tests/maybe.c58
-rw-r--r--test/external/metalang99/tests/metalang99.c51
-rw-r--r--test/external/metalang99/tests/nat.c260
-rw-r--r--test/external/metalang99/tests/seq.c100
-rw-r--r--test/external/metalang99/tests/stmt.c114
-rw-r--r--test/external/metalang99/tests/tuple.c184
-rw-r--r--test/external/metalang99/tests/util.c137
-rw-r--r--test/external/metalang99/tests/variadics.c137
117 files changed, 16938 insertions, 0 deletions
diff --git a/test/external/metalang99/.clang-format b/test/external/metalang99/.clang-format
new file mode 100644
index 0000000..a195560
--- /dev/null
+++ b/test/external/metalang99/.clang-format
@@ -0,0 +1,17 @@
+Language: Cpp
+BasedOnStyle: LLVM
+
+IndentWidth: 4
+ContinuationIndentWidth: 4
+ColumnLimit: 100
+
+AllowShortFunctionsOnASingleLine: Empty
+AllowAllArgumentsOnNextLine: false
+BinPackArguments: false
+AllowAllParametersOfDeclarationOnNextLine: true
+BinPackParameters: true
+
+AlignConsecutiveMacros: true
+AlignAfterOpenBracket: AlwaysBreak
+
+StatementMacros: ["ML99_EVAL", "ML99_CLANG_PRAGMA", "ML99_GCC_PRAGMA"]
diff --git a/test/external/metalang99/.github/workflows/c-cpp.yml b/test/external/metalang99/.github/workflows/c-cpp.yml
new file mode 100644
index 0000000..0c0aef1
--- /dev/null
+++ b/test/external/metalang99/.github/workflows/c-cpp.yml
@@ -0,0 +1,88 @@
+name: C/C++ CI
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+ branches: [master]
+
+jobs:
+ test:
+ strategy:
+ matrix:
+ os: [ubuntu-latest, macos-latest, windows-latest]
+ include:
+ - os: ubuntu-latest
+ compiler: gcc
+ - os: macos-latest
+ compiler: clang
+ - os: windows-latest
+ compiler: msvc
+
+ runs-on: ${{ matrix.os }}
+ env:
+ CC: ${{ matrix.compiler }}
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Test
+ run: ./scripts/test-all.sh
+
+ test-tcc:
+ runs-on: ubuntu-latest
+ env:
+ CC: tcc
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Install TCC
+ run: sudo apt install tcc
+
+ - name: Test
+ run: ./scripts/test-all.sh
+
+ test-cxx-stmt:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Test C++ statement chaining
+ run: |
+ g++ tests/stmt.c -o stmt -Iinclude -Wall -Wextra -pedantic -std=c++11 -ftrack-macro-expansion=0
+ ./stmt
+
+ bench:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Bench
+ run: ./scripts/bench.sh
+
+ check-arities:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Install Doxygen
+ run: sudo apt install doxygen
+
+ - name: Check arity specifiers
+ run: python3 scripts/check-arities.py
+
+ check-fmt:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Download run-clang-format
+ run: git submodule update --init run-clang-format
+
+ - name: Check code formatting
+ run: ./scripts/check-fmt.sh
diff --git a/test/external/metalang99/.gitignore b/test/external/metalang99/.gitignore
new file mode 100644
index 0000000..8546167
--- /dev/null
+++ b/test/external/metalang99/.gitignore
@@ -0,0 +1,61 @@
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
+
+# Doxygen XML output
+xml
+
+# Sphinx output
+_build
+
+# CMake build files
+build/
diff --git a/test/external/metalang99/.gitmodules b/test/external/metalang99/.gitmodules
new file mode 100644
index 0000000..517f2a7
--- /dev/null
+++ b/test/external/metalang99/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "run-clang-format"]
+ path = run-clang-format
+ url = https://github.com/Sarcasm/run-clang-format
diff --git a/test/external/metalang99/.readthedocs.yaml b/test/external/metalang99/.readthedocs.yaml
new file mode 100644
index 0000000..92f2760
--- /dev/null
+++ b/test/external/metalang99/.readthedocs.yaml
@@ -0,0 +1,17 @@
+# See <https://docs.readthedocs.io/en/stable/config-file/index.html>.
+
+version: 2
+
+build:
+ os: ubuntu-22.04
+ tools:
+ python: "3.12"
+
+python:
+ install:
+ - requirements: docs/requirements.txt
+
+sphinx:
+ builder: html
+ configuration: docs/conf.py
+ fail_on_warning: true
diff --git a/test/external/metalang99/ARCHITECTURE.md b/test/external/metalang99/ARCHITECTURE.md
new file mode 100644
index 0000000..b1fe1cc
--- /dev/null
+++ b/test/external/metalang99/ARCHITECTURE.md
@@ -0,0 +1,25 @@
+# Architecture
+
+_This document describes the high-level architecture of Metalang99._
+
+## Interpreter
+
+The interpreter interprets the core metalanguage described in the [specification].
+
+[specification]: https://github.com/hirrolot/metalang99/blob/master/spec/spec.pdf
+
+### `eval/eval.h`
+
+`eval/eval.h` exposes a single macro `ML99_PRIV_EVAL` which evaluates a given metaprogram. It is implemented as a machine in [continuation-passing style] which is described in the specification too.
+
+[continuation-passing style]: https://en.wikipedia.org/wiki/Continuation-passing_style
+
+### `eval/rec.h`
+
+`eval/rec.h` contains a macro recursion engine upon which everything executes.
+
+## Standard library
+
+The Metalang99 standard library is a set of functions implemented using the core metalanguage. They are located inside corresponding files listed at the [documentation]'s front page.
+
+[documentation]: https://metalang99.readthedocs.io/en/latest/
diff --git a/test/external/metalang99/CHANGELOG.md b/test/external/metalang99/CHANGELOG.md
new file mode 100644
index 0000000..0a97127
--- /dev/null
+++ b/test/external/metalang99/CHANGELOG.md
@@ -0,0 +1,464 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## unreleased
+
+### Fixed
+
+ - Remove outdated Doxygen configuration options ([issue #34](https://github.com/hirrolot/metalang99/issues/34)).
+
+## 1.13.5 - 2025-03-17
+
+### Fixed
+
+ - Update the minimum required CMake version to 3.10.0 due to deprecation ([issue #33](https://github.com/hirrolot/metalang99/issues/33)).
+
+## 1.13.4 - 2025-03-17
+
+### Fixed
+
+ - Update the minimum required CMake version to 3.5.0 due to deprecation ([issue #32](https://github.com/hirrolot/metalang99/issues/32)).
+
+## 1.13.3 - 2023-03-11
+
+### Fixed
+
+ - Fix the `DOWNLOAD_EXTRACT_TIMESTAMP` CMake warning (see [datatype99/issues/15](https://github.com/hirrolot/datatype99/issues/15)).
+
+## 1.13.2 - 2022-05-15
+
+### Fixed
+
+ - Fix C++ compilation for `ML99_INTRODUCE_VAR_TO_STMT` and `ML99_INTRODUCE_NON_NULL_PTR_TO_STMT` ([issue #25](https://github.com/hirrolot/metalang99/issues/25)).
+
+## 1.13.1 - 2021-12-09
+
+### Fixed
+
+ - Specify `C` as the project language in `CMakeLists.txt`. Previously, CMake detected C++ and required a C++ compiler to compile the project.
+
+## 1.13.0 - 2021-12-01
+
+### Added
+
+ - Add the root `CMakeLists.txt` to be able to use CMake with [`FetchContent`] or [`add_subdirectory`] ([PR #20](https://github.com/hirrolot/metalang99/pull/20)).
+ - `list.h`:
+ - `ML99_listFilterMap` to filter a list with a maybe-returning function.
+
+[`FetchContent`]: https://cmake.org/cmake/help/latest/module/FetchContent.html
+[`add_subdirectory`]: https://cmake.org/cmake/help/latest/command/add_subdirectory.html
+
+## 1.12.1 - 2021-11-23
+
+### Deprecated
+
+ - Deprecate `ML99_catEval` because there were no use cases over time.
+
+## 1.12.0 - 2021-11-09
+
+### Added
+
+ - `choice.h`:
+ - `ML99_choiceData`, `ML99_CHOICE_DATA` to extract a choice value data.
+ - `gen.h`:
+ - Add `ML99_fnPtr(Stmt)` to generate a function pointer.
+ - New module `stmt.h`:
+ - Take `ML99_INTRODUCE_VAR_TO_STMT`, `ML99_INTRODUCE_NON_NULL_PTR_TO_STMT`, `ML99_CHAIN_EXPR_STMT`, `ML99_CHAIN_EXPR_STMT_AFTER`, and `ML99_SUPPRESS_UNUSED_BEFORE_STMT` from `gen.h`.
+
+### Changed
+
+ - `choice.h`:
+ - Define the representation of choice types as `(tag, ...)`.
+ - `tuple.h`:
+ - Emit a fatal error in `ML99_untuple` if an argument is not a tuple.
+ - `gen.h`:
+ - Move all statement chaining macros to `stmt.h` (see above).
+ - Move `ML99_GEN_SYM` and `ML99_TRAILING_SEMICOLON` to `util.h`.
+
+### Deprecated
+
+ - `tuple.h`:
+ - `ML99_untupleChecked` because it is the same as `ML99_untuple`.
+ - `ML99_tupleEval`, `ML99_untupleEval` because there were no use cases over time.
+ - `logical.h`:
+ - Move all functions to `bool.h`.
+ - `control.h`:
+ - Move `ML99_OVERLOAD` to `variadics.h`.
+ - Move `ML99_if`, `ML99_IF` to `bool.h`.
+ - Move `ML99_repeat`, `ML99_times` to `gen.h`.
+
+## 1.11.0 - 2021-10-02
+
+### Added
+
+ - New module `seq.h`:
+ - `ML99_seqIsEmpty`, `ML99_SEQ_IS_EMPTY` to check for the empty sequence.
+ - `ML99_seqGet`, `ML99_SEQ_GET` to get an `i`-indexed element.
+ - `ML99_seqTail`, `ML99_SEQ_TAIL` to get a tail.
+ - `ML99_seqForEach(I)` to iterate through each element.
+ - `logical.h`:
+ - `ML99_boolMatch(WithArgs)` to perform pattern matching on a boolean value.
+
+### Changed
+
+ - `list.h`, `variadics.h`:
+ - Remove the requirement that `ML99_listFromTuples` and `ML99_variadicsForEach(I)` can accept at most 63 arguments.
+
+## 1.10.0 - 2021-09-14
+
+### Added
+
+ - `util.h`:
+ - `ML99_COMMA` that expands to a single comma.
+
+### Deprecated
+
+ - `util.h`:
+ - `ML99_(L|R)PAREN` because they result in code that is difficult to reason about.
+
+## 1.9.0 - 2021-08-27
+
+### Added
+
+ - `metalang99.h`:
+ - `ML99_VERSION_COMPATIBLE` to check for a SemVer-compatible version.
+ - `ML99_VERSION_EQ` to check for an exact version.
+
+## 1.8.0 - 2021-08-26
+
+### Added
+
+ - `ident.h`:
+ - `ML99_charLit`, `ML99_CHAR_LIT` to convert a Metalang99 character to a C character literal.
+
+## 1.7.0 - 2021-08-13
+
+### Changed
+
+ - `assert.h`:
+ - Generate `_Static_assert` from the assertion macros if compiling on C11.
+
+## 1.6.0 - 2021-08-13
+
+### Added
+
+ - Tuple counterparts of variadics (`tuple.h`):
+ - `ML99_tupleCount`, `ML99_TUPLE_COUNT`.
+ - `ML99_tupleIsSingle`, `ML99_TUPLE_IS_SINGLE`.
+ - `ML99_tupleForEach(I)`.
+
+### Fixed
+
+ - `util.h`:
+ - `ML99_cat3` & `ML99_cat4` to desugar to themselves instead of `ML99_cat`.
+ - `variadics.h`:
+ - Make `variadics.h` work without including `nat.h` & `util.h`.
+
+## 1.5.0 - 2021-08-11
+
+### Added
+
+ - `ML99_assignInitializerList(Stmt)` as `ML99_assign(Stmt)` counterparts for initializer lists.
+
+## 1.4.1 - 2021-08-05
+
+### Fixed
+
+ - Invalid C11 standard detection for `_Static_assert` ([issue #15](https://github.com/hirrolot/metalang99/issues/15)).
+ - Invalid C11 standard detection for `_Static_assert` on MSVC ([issue #16](https://github.com/hirrolot/metalang99/issues/16)).
+
+## 1.4.0 - 2021-08-02
+
+### Added
+
+- `ML99_ALLOW_POOR_DIAGNOSTICS`: if your compiler does not support decent diagnostic messages, Metalang99 will emit an error that can be suppressed by defining this macro.
+
+### Fixed
+
+ - Emit `_Static_assert` for diagnostics where possible:
+ - C11.
+ - Clang if `__has_extension(c_static_assert)`.
+ - GCC if newer than [4.6](https://gcc.gnu.org/gcc-4.6/changes.html).
+
+## 1.3.0 - 2021-07-24
+
+### Added
+
+ - `util.h`:
+ - `ML99_todo(WithMsg)` and `ML99_unimplemented(WithMsg)` to indicate unimplemented functionality.
+
+### Fixed
+
+ - Handle the `(...) (...) ...` form in `ML99_isUntuple`:
+ - All the dependent public functions inherit this ability too: `ML99_isTuple`, `ML99_untupleChecked`, and `ML99_listFromTuples`.
+ - Now the interpreter is able to emit a syntax error for `v(123) v(456)`.
+
+### Changed
+
+ - Emit syntax errors and errors from `ML99_fatal` right to a console if compiling on GCC.
+
+## 1.2.0 - 2021-06-06
+
+### Added
+
+ - `list.h`:
+ - `ML99_listFromTuples` to transform comma-separated tuples into a list.
+ - `util.h`:
+ - `ML99_(L|R)PAREN` that expand to an opening/closing parenthesis.
+ - `tuple.h`:
+ - `ML99_untupleChecked` to emit a fatal error if a provided argument is not a tuple.
+ - New module `ident.h`:
+ - Migrate `ML99_detectIdent`, `ML99_identEq`, `ML99_DETECT_IDENT`, `ML99_IDENT_EQ`, `ML99_C_KEYWORD_DETECTOR`, `ML99_UNDERSCORE_DETECTOR` from `util.h`.
+ - `ML99_(LOWER|UPPER)CASE_DETECTOR` to detect lower/uppercase characters.
+ - `ML99_DIGIT_DETECTOR` to detect digits.
+ - `ML99_char_eq`, `ML99_CHAR_EQ` to compare two characters.
+ - `ML99_is(Lower|Upper)case`, `ML99_IS_(LOWER|UPPER)CASE` to check whether a letter is lower/uppercased.
+ - `ML99_isDigit`, `ML99_IS_DIGIT` to check whether a character is digit.
+ - `ML99_isChar`, `ML99_IS_CHAR` to check whether an identifier is a character.
+ - `ML99_(LOWER|UPPER)CASE_CHARS` that expands to all comma-separated lower/uppercase characters.
+ - `ML99_DIGITS` that expands to all comma-separated digits.
+
+### Changed
+
+ - `util.h`:
+ - Automatically include `ident.h` for backwards compatibility.
+
+### Fixed
+
+ - Make Metalang99 work on TCC (see [datatype99/issues/10](https://github.com/hirrolot/datatype99/issues/10)).
+
+## 1.1.0 - 2021-04-24
+
+### Added
+
+ - `gen.h`:
+ - Statement chaining macros:
+ - `ML99_CHAIN_EXPR_STMT` to execute a statement before the next statement.
+ - `ML99_CHAIN_EXPR_STMT_AFTER` to execute a statement afterwards.
+ - `ML99_INTRODUCE_NON_NULL_PTR_TO_STMT` to introduce a non-null pointer to a statement.
+ - Other:
+ - `ML99_GEN_SYM` to generate unique identifiers.
+ - `ML99_TRAILING_SEMICOLON` to force a trailing semicolon.
+ - `ML99_semicoloned` that puts a semicolon after its argument.
+ - `ML99_assign` to assign something to something.
+ - `ML99_assignStmt` to generate an assignment statement.
+ - `ML99_invoke` to invoke a macro/function.
+ - `ML99_invokeStmt` to generate a macro/function invocation statement.
+ - `ML99_prefixedBlock` to generate `prefix { code }`.
+ - `util.h`:
+ - Dealing with identifiers:
+ - `ML99_detectIdent`.
+ - `ML99_identEq`, `ML99_IDENT_EQ` to compare two identifiers.
+ - `ML99_C_KEYWORD_DETECTOR` to detect the C11 keywords.
+ - `ML99_UNDERSCORE_DETECTOR` to detect the underscore character (`_`).
+ - Other:
+ - `ML99_uncomma` to evaluate terms with the space-separator.
+ - `ML99_reify` to reify a macro/function to a Metalang99-compliant metafunction.
+ - `ML99_cat3`, `ML99_CAT3`, `ML99_CAT3_PRIMITIVE`.
+ - `ML99_cat4`, `ML99_CAT4`, `ML99_CAT4_PRIMITIVE`.
+ - `assert.h`:
+ - `ML99_assert`, `ML99_assertEq`.
+ - `variadics.h`:
+ - `ML99_variadicsIsSingle`, `ML99_VARIADICS_IS_SINGLE`.
+ - Built-in data type assertion macros:
+ - `tuple.h`: `ML99_assertIsTuple`.
+ - `nat.h`: `ML99_assertIsNat`.
+
+### Fixed
+
+ - `assert.h`:
+ - Parenthesize expressions passed to `ML99_ASSERT`, `ML99_ASSERT_EQ`.
+
+### Changed
+
+ - `gen.h`:
+ - `ML99_INTRODUCE_VAR_TO_STMT` can deal with several variables.
+
+### Deprecated
+
+ - `gen.h`:
+ - `ML99_SUPPRESS_UNUSED_BEFORE_STMT` (use `ML99_CHAIN_EXPR_STMT((void)expr)` instead).
+
+## 1.0.0 - 2021-03-27
+
+### Added
+
+ - `ML99_QUOTE`.
+
+### Removed
+
+ - `ML99_consume`, `ML99_CONSUME`.
+
+### Changed
+
+ - Move `ML99_TERMS` from `util.h` to `lang.h`.
+ - Return a list of tuples from `ML99_listZip`, accept a list of tuples in `ML99_listUnzip`, return a tuple of lists from `ML99_listPartition`.
+ - `ML99_listEval` => `ML99_LIST_EVAL`, `ML99_listEvalCommaSep` => `ML99_LIST_EVAL_COMMA_SEP`.
+ - Accept ignored variadics in `ML99_nil`, `ML99_empty`, `ML99_true`, `ML99_false`, `ML99_nothing` (and their plain versions).
+
+### Fixed
+
+ - Emit the correct metafunction name in case of an error in `ML99_listGet`.
+ - Remove a precondition that metafunctions passed to `ML99_listFoldl`, `ML99_listFolr`, `ML99_listFoldl1`, `ML99_listMap`, `ML99_listMapI`, `ML99_listFor`, `ML99_listMapInitLast`, and `ML99_listForInitLast` must evaluate to a single term.
+
+## 0.5.0 - 2021-03-22
+
+### Added
+
+ - `ML99_SUPPRESS_UNUSED_BEFORE_STMT`.
+ - `ML99_tupleGet`, `ML99_variadicsGet`, `ML99_TUPLE_GET`, `ML99_VARIADICS_GET`.
+ - `ML99_tupleAppend`, `ML99_tuplePrepend`.
+ - `ML99_indexedArgs`.
+ - `ML99_appl4`.
+ - `ML99_times`.
+ - `ML99_TRUE`, `ML99_FALSE`.
+ - `ML99_LEFT`, `ML99_RIGHT`, `ML99_IS_LEFT`, `ML99_IS_RIGHT`.
+ - `ML99_JUST`, `ML99_NOTHING`, `ML99_IS_JUST`, `ML99_IS_NOTHING`.
+ - `ML99_NAT_MAX`, `ML99_DIV_CHECKED`.
+ - `gen.h`.
+
+### Removed
+
+ - `M_choiceEmpty(Plain)` (this allows a more optimal choice representation).
+ - `M_semicolon` (this macro turned out to be [dangerous](https://github.com/hirrolot/metalang99/commit/f12ba642b1fcf313e291fc0e353b01f666a980f8)).
+ - `M_tupleHead`, `M_variadicsHead`.
+ - `M_overload`.
+ - `M_when(Plain)`, `M_whenLazy(Plain)`.
+ - `M_putBefore`, `M_putAfter`, `M_putBetween`.
+ - `M_leftUnderscored`, `M_rightUnderscored`.
+ - `misc.h`, `eval.h`.
+
+### Changed
+
+ - Do not guarantee the exact number of available reduction steps, instead keep it "reasonable" for the practical needs.
+ - Amalgamate `lang.h` with `eval.h`.
+ - Employ the `SCREAMING_CASE` naming convention for plain macros.
+ - All macros are prefixed with `ML99_`, unconditionally.
+ - Accept a number as a first argument and a function as the second in `ML99_repeat`.
+ - `M_get` => `ML99_listGet`.
+ - `M_overloadPlain` => `ML99_OVERLOAD`.
+ - `M_eval` => `ML99_EVAL`.
+ - `M_callTrivial` => `ML99_callUneval`.
+ - Move `ML99_repeat` from `misc.h` to `control.h`.
+ - Move `ML99_indexed(Params, Fields, InitializerList, Args)` from `misc.h` to `gen.h`.
+ - Move `ML99_braced`, `ML99_typedef`, `ML99_struct`, `ML99_anonStruct`, `ML99_union`, `ML99_anonUnion`, `ML99_enum`, `ML99_anonEnum` from `util.h` to `gen.h`.
+ - `M_assertPlain` => `ML99_ASSERT_UNEVAL`, `M_assertEmptyPlain` => `ML99_ASSERT_EMPTY_UNEVAL`.
+ - Rename "unsigned integers" to "natural numbers":
+ - `uint.h` => `nat.h`.
+ - `M_uintMatch(WithArgs)` => `ML99_natMatch(WithArgs)`.
+ - `M_uintEq` => `ML99_natEq`.
+ - `M_uintNeq` => `ML99_natNeq`.
+
+### Fixed
+
+ - Emit a compile-time error if [`/Zc:preprocessor`] (MSVC) was not specified.
+ - Allow branches in `ML99_IF` expand to commas.
+
+[`/Zc:preprocessor`]: https://docs.microsoft.com/en-us/cpp/build/reference/zc-preprocessor?view=msvc-160
+
+## 0.4.2 - 2021-02-28
+
+### Added
+
+ - `METALANG99_MAJOR`, `METALANG99_MINOR`, `METALANG99_PATCH`.
+ - `M_union`, `M_anonUnion`, `M_enum`, `M_anonEnum`.
+ - `METALANG99_GCC_PRAGMA`, `METALANG99_CLANG_PRAGMA`.
+
+### Fixed
+
+ - Suppress Clang's `-Wshadow` for a variable produced by `M_INTRODUCE_VAR_TO_STMT`.
+
+## 0.4.1 - 2021-02-28
+
+### Added
+
+ - `M_DETECT_IDENT`
+ - `M_choicePlain`, `M_choiceEmptyPlain`, `M_consPlain`, `M_nilPlain`.
+ - `M_listMapInPlace`, `M_listMapInPlaceI`.
+
+### Changed
+
+ - Increase the maximum arity from 16 to 255.
+ - Specify the exact number of commas produced by `M_indexedInitializerList`.
+
+### Fixed
+
+ - Initialize variables produced by `M_semicolon` and `M_assertPlain` to suppress warnings.
+
+## 0.4.0 - 2021-02-26
+
+### Added
+
+ - `tuple.h`: `M_tuple(Plain)`, `M_tupleEval`, `M_untuple(Plain)`, `M_untupleEval`, `M_isTuple(Plain)`, `M_isUntuple(Plain)`, `M_tupleHead(Plain)`, `M_tupleTail(Plain)`.
+
+### Changed
+
+ - Move the corresponding functions from `util.h` and `variadics.h` to `tuple.h`.
+
+## 0.3.0 - 2021-02-26
+
+### Added
+
+ - `M_when`, `M_whenPlain`, `M_whenLazy`, `M_whenLazyPlain`.
+ - `M_leftUnderscored`, `M_rightUnderscored`.
+ - `M_INTRODUCE_VAR_TO_STMT`.
+ - `M_terms`.
+ - `M_tupleHead`, `M_tupleHeadPlain`, `M_tupleTail`, `M_tupleTailPlain`.
+ - `M_indexedParams`, `M_indexedFields`, `M_indexedInitializerList`.
+ - `M_typedef`, `M_struct`, `M_anonStruct`.
+ - `M_choiceTag`, `M_choiceTagPlain`, `M_isNilPlain`, `M_isCons`, `M_isConsPlain`.
+
+### Changed
+
+ - Make `M_variadicsHead` accept a single argument too.
+ - Now at most 63 variadic arguments are acceptable by `M_list`, `M_variadicsCount`, and `M_variadicsCountPlain`.
+ - Terms now need to be separated by commas, e.g. instead of `v(1) M_call(F, v(2)) v(3)`, write `v(1), M_call(F, v(2)), v(3)` or `M_terms(v(1), M_call(F, v(2)), v(3)`.
+ - The empty sequence is prohibited by `M_eval`, `M_call` and `M_abort`.
+ - Use American style endings (because it is prevalent):
+ - `M_(un)parenthesise(Eval)` => `M_(un)tuple(Eval)`.
+ - `M_isParenthesised` => `M_isTuple`.
+ - `M_isUnparenthesised` => `M_isUntuple`.
+ - `M_parenthesisedVariadics(Head|Tail)` => `M_tuple(Head|Tail)`.
+ - Shorten functions on unsigned integers:
+ - `M_uintInc(Plain)` => `M_inc(Plain)`.
+ - `M_uintDec(Plain)` => `M_dec(Plain)`.
+ - `M_uintAdd(3)` => `M_add(3)`.
+ - `M_uintSub(3)` => `M_sub(3)`.
+ - `M_uintMul(3)` => `M_mul(3)`.
+ - `M_uintDiv(3)` => `M_div(3)`.
+ - `M_uintDivChecked` => `M_divChecked`.
+ - `M_uintLesser(Eq)` => `M_lesser(Eq)`.
+ - `M_uintGreater(Eq)` => `M_greater(Eq)`.
+ - `M_uintMod` => `M_mod`.
+ - `M_uintMin` => `M_min`.
+ - `M_uintMax` => `M_max`.
+ - `M_variadicsMap` => `M_variadicsForEach`, `M_variadicsMapI` => `M_variadicsForEachI`.
+
+### Fixed
+
+ - `aux.*` => `util.*` for compatibility with Windows.
+
+### Removed
+
+ - `M_variadicsMapCommaSep`, `M_variadicsMapICommaSep` (better use lists).
+ - `M_const2`, `M_const3`.
+
+## 0.2.0 - 2021-02-05
+
+### Changed
+
+ - The project name `Epilepsy` => `Metalang99` (more neutral).
+
+### Fixed
+
+ - Reporting about syntactic mismatches.
+
+## 0.1.0 - 2021-02-04
+
+### Added
+
+ - This excellent project.
diff --git a/test/external/metalang99/CMakeLists.txt b/test/external/metalang99/CMakeLists.txt
new file mode 100644
index 0000000..96733b4
--- /dev/null
+++ b/test/external/metalang99/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.10.0)
+project(metalang99 LANGUAGES C)
+
+# Fix the warnings about `DOWNLOAD_EXTRACT_TIMESTAMP` in newer CMake versions.
+if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
+ cmake_policy(SET CMP0135 NEW)
+endif()
+
+add_library(${PROJECT_NAME} INTERFACE)
+target_include_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
diff --git a/test/external/metalang99/CONTRIBUTING.md b/test/external/metalang99/CONTRIBUTING.md
new file mode 100644
index 0000000..2e9e0d1
--- /dev/null
+++ b/test/external/metalang99/CONTRIBUTING.md
@@ -0,0 +1,32 @@
+# Contributing
+
+To introduce changes:
+
+ 1. Fork this repository.
+ 2. Create your own branch `xxx` from `master`.
+ 3. Make required changes.
+ 4. Open a PR to `master` from your `xxx`.
+ 5. Wait until it gets reviewed.
+
+To be able to work with low-level stuff such as the interpreter, I highly recommend to first observe the [Cloak Wiki].
+
+To be able to work with the metalanguage itself, some basic familiarity with programming language theory is expected. For learning materials, see https://github.com/steshaw/plt.
+
+[Cloak Wiki]: https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
+
+Some useful scripts are:
+
+| Description | Command |
+|----------|----------|
+| Format all the code base | `./scripts/fmt.sh` |
+| Check code formatting | `./scripts/check-fmt.sh` |
+| Test only `tests/` | `./scripts/test.sh` |
+| Test only `examples/` | `./scripts/test-examples.sh` |
+| Test both `tests/` and `examples/` | `./scripts/test-all.sh` |
+| Generate the documentation | `./scripts/docs.sh` |
+| Open the documentation | `./scripts/open-docs.sh` |
+| Generate the specification | `./scripts/spec.sh` |
+| Open the specification | `./scripts/open-spec.sh` |
+| Run the benchmarks | `./scripts/bench.sh` |
+
+Happy hacking!
diff --git a/test/external/metalang99/Doxyfile b/test/external/metalang99/Doxyfile
new file mode 100644
index 0000000..8144215
--- /dev/null
+++ b/test/external/metalang99/Doxyfile
@@ -0,0 +1,2859 @@
+# Doxyfile 1.9.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+#
+# Note:
+#
+# Use doxygen to compare the used configuration file with the template
+# configuration file:
+# doxygen -x [configFile]
+# Use doxygen to compare the used configuration file with the template
+# configuration file without replacing the environment variables or CMake type
+# replacement variables:
+# doxygen -x_noenv [configFile]
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = Metalang99
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = 1.13.5
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "Full-blown preprocessor metaprogramming"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
+# sub-directories (in 2 levels) under the output directory of each output format
+# and will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
+# control the number of sub-directories.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# Controls the number of sub-directories that will be created when
+# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
+# level increment doubles the number of directories, resulting in 4096
+# directories at level 8 which is the default and also the maximum value. The
+# sub-directories are organized in 2 levels, the first level always has a fixed
+# number of 16 directories.
+# Minimum value: 0, maximum value: 8, default value: 8.
+# This tag requires that the tag CREATE_SUBDIRS is set to YES.
+
+CREATE_SUBDIRS_LEVEL = 8
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
+# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
+# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
+# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
+# English messages), Korean, Korean-en (Korean with English messages), Latvian,
+# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
+# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
+# Swedish, Turkish, Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:^^"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". Note that you cannot put \n's in the value part of an alias
+# to insert newlines (in the resulting output). You can put ^^ in the value part
+# of an alias to insert a newline as if a physical newline was in the original
+# file. When you need a literal { or } or , in the value part of an alias you
+# have to escape them by means of a backslash (\), this can lead to conflicts
+# with the commands \{ and \} for these it is advised to use the version @{ and
+# @} or use a double escape (\\{ and \\})
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 0
+
+# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
+# generate identifiers for the Markdown headings. Note: Every identifier is
+# unique.
+# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a
+# sequence number starting at 0 and GITHUB use the lower case version of title
+# with any whitespace replaced by '-' and punctuation characters removed.
+# The default value is: DOXYGEN.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+MARKDOWN_ID_STYLE = DOXYGEN
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which effectively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS = 1
+
+# If the TIMESTAMP tag is set different from NO then each generated page will
+# contain the date or date and time when the page was generated. Setting this to
+# NO can help when comparing the output of multiple runs.
+# Possible values are: YES, NO, DATETIME and DATE.
+# The default value is: NO.
+
+TIMESTAMP = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# will also hide undocumented C++ concepts if enabled. This option has no effect
+# if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# Possible values are: SYSTEM, NO and YES.
+# The default value is: SYSTEM.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
+# will show which file needs to be included to use the class.
+# The default value is: YES.
+
+SHOW_HEADERFILE = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = NO
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file. See also section "Changing the
+# layout of pages" for information.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as documenting some parameters in
+# a documented function twice, or documenting parameters that don't exist or
+# using markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
+# function parameter documentation. If set to NO, doxygen will accept that some
+# parameters have no documentation without warning.
+# The default value is: YES.
+
+WARN_IF_INCOMPLETE_DOC = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong parameter
+# documentation, but not about the absence of documentation. If EXTRACT_ALL is
+# set to YES then this flag will automatically be disabled. See also
+# WARN_IF_INCOMPLETE_DOC
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
+# undocumented enumeration values. If set to NO, doxygen will accept
+# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: NO.
+
+WARN_IF_UNDOC_ENUM_VAL = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves
+# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not
+# write the warning messages in between other messages but write them at the end
+# of a run, in case a WARN_LOGFILE is defined the warning messages will be
+# besides being in the defined file also be shown at the end of a run, unless
+# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
+# the behavior will remain as with the setting FAIL_ON_WARNINGS.
+# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# See also: WARN_LINE_FORMAT
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# In the $text part of the WARN_FORMAT command it is possible that a reference
+# to a more specific place is given. To make it easier to jump to this place
+# (outside of doxygen) the user can define a custom "cut" / "paste" string.
+# Example:
+# WARN_LINE_FORMAT = "'vi $file +$line'"
+# See also: WARN_FORMAT
+# The default value is: at line $line of file $file.
+
+WARN_LINE_FORMAT = "at line $line of file $file"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr). In case the file specified cannot be opened for writing the
+# warning and error messages are written to standard error. When as file - is
+# specified the warning and error messages are written to standard output
+# (stdout).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = include \
+ include/metalang99
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# See also: INPUT_FILE_ENCODING
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
+# character encoding on a per file pattern basis. Doxygen will compare the file
+# name with each pattern and apply the encoding instead of the default
+# INPUT_ENCODING) if there is a match. The character encodings are a list of the
+# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
+# "INPUT_ENCODING" for further information on supported encodings.
+
+INPUT_FILE_ENCODING =
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,
+# *.cpp, *.cppm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl,
+# *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, *.php,
+# *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be
+# provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.pyw \
+ *.f90 \
+ *.f95 \
+ *.f03 \
+ *.f08 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# ANamespace::AClass, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH = examples
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that doxygen will use the data processed and written to standard output
+# for further processing, therefore nothing else, like debug statements or used
+# commands (so in case of a Windows batch file always use @echo OFF), should be
+# written to standard output.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+# The Fortran standard specifies that for fixed formatted Fortran code all
+# characters from position 72 are to be considered as comment. A common
+# extension is to allow longer lines before the automatic comment starts. The
+# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
+# be processed before the automatic comment starts.
+# Minimum value: 7, maximum value: 10000, default value: 72.
+
+FORTRAN_COMMENT_AFTER = 72
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see:
+# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
+# performance. This can be particularly helpful with template rich C++ code for
+# which doxygen's built-in parser lacks the necessary type information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
+# tag is set to YES then doxygen will add the directory of each input to the
+# include path.
+# The default value is: YES.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_ADD_INC_PATHS = YES
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the directory containing a file called compile_commands.json. This
+# file is the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
+# options used when the source files were built. This is equivalent to
+# specifying the -p option to a clang tool, such as clang-check. These options
+# will then be passed to the parser. Any options specified with CLANG_OPTIONS
+# will be added as well.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
+# that should be ignored while generating the index headers. The IGNORE_PREFIX
+# tag works for classes, function and member names. The entity will be placed in
+# the alphabetical list under the first letter of the entity name that remains
+# after removing the prefix.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT =
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# Note: Since the styling of scrollbars can currently not be overruled in
+# Webkit/Chromium, the styling will be left out of the default doxygen.css if
+# one or more extra stylesheets have been specified. So if scrollbar
+# customization is desired it has to be added explicitly. For an example see the
+# documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
+# should be rendered with a dark or light theme.
+# Possible values are: LIGHT always generate light mode output, DARK always
+# generate dark mode output, AUTO_LIGHT automatically set the mode according to
+# the user preference, use light mode if no preference is set (the default),
+# AUTO_DARK automatically set the mode according to the user preference, use
+# dark mode if no preference is set and TOGGLE allow to user to switch between
+# light and dark mode via a button.
+# The default value is: AUTO_LIGHT.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE = AUTO_LIGHT
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a color-wheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use gray-scales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be
+# dynamically folded and expanded in the generated HTML source code.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_CODE_FOLDING = YES
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag determines the URL of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDURL =
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# on Windows. In the beginning of 2021 Microsoft took the original page, with
+# a.o. the download links, offline the HTML help workshop was already many years
+# in maintenance mode). You can download the HTML help workshop from the web
+# archives at Installation executable (see:
+# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
+# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# The SITEMAP_URL tag is used to specify the full URL of the place where the
+# generated documentation will be placed on the server by the user during the
+# deployment of the documentation. The generated sitemap is called sitemap.xml
+# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
+# is specified no sitemap is generated. For information about the sitemap
+# protocol see https://www.sitemaps.org
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SITEMAP_URL =
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine tune the look of the index (see "Fine-tuning the output"). As an
+# example, the default style sheet generated by doxygen has an example that
+# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
+# Since the tree basically has the same information as the tab index, you could
+# consider setting DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
+# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
+# area (value NO) or if it should extend to the full height of the window (value
+# YES). Setting this to YES gives a layout similar to
+# https://docs.readthedocs.io with more room for contents, but less room for the
+# project logo, title, and description. If either GENERATE_TREEVIEW or
+# DISABLE_INDEX is set to NO, this option has no effect.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FULL_SIDEBAR = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
+# addresses.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+OBFUSCATE_EMAILS = YES
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE =
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = YES
+
+# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
+# Note that the different versions of MathJax have different requirements with
+# regards to the different settings, so it is possible that also other MathJax
+# settings have to be changed when switching between the different MathJax
+# versions.
+# Possible values are: MathJax_2 and MathJax_3.
+# The default value is: MathJax_2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_VERSION = MathJax_2
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. For more details about the output format see MathJax
+# version 2 (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
+# (see:
+# http://docs.mathjax.org/en/latest/web/components/output.html).
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility. This is the name for Mathjax version 2, for MathJax version 3
+# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
+# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
+# is the name for Mathjax version 3, for MathJax version 2 this will be
+# translated into HTML-CSS) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment. The default value is:
+# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
+# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# for MathJax version 2 (see
+# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# For example for MathJax version 3 (see
+# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
+# MATHJAX_EXTENSIONS = ams
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
+# the generated LaTeX document. The header should contain everything until the
+# first chapter. If it is left blank doxygen will generate a standard header. It
+# is highly recommended to start with a default header using
+# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
+# and then modify the file new_header.tex. See also section "Doxygen usage" for
+# information on how to generate the default header that doxygen normally uses.
+#
+# Note: Only use a user-defined header if you know what you are doing!
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. The following
+# commands have a special meaning inside the header (and footer): For a
+# description of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
+# the generated LaTeX document. The footer should contain everything after the
+# last chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer. See also section "Doxygen
+# usage" for information on how to generate the default footer that doxygen
+# normally uses. Note: Only use a user-defined footer if you know what you are
+# doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.
+# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
+# mode nothing is printed on the terminal, errors are scrolled as if <return> is
+# hit at every error; missing files that TeX tries to input or request from
+# keyboard input (\read on a not open input stream) cause the job to abort,
+# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
+# but there is no possibility of user interaction just like in batch mode,
+# SCROLL In scroll mode, TeX will stop only for missing files to input or if
+# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
+# each error, asking for user intervention.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to Sqlite3 output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3
+# database with symbols found by doxygen stored in tables.
+# The default value is: NO.
+
+GENERATE_SQLITE3 = NO
+
+# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be
+# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put
+# in front of it.
+# The default directory is: sqlite3.
+# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
+
+SQLITE3_OUTPUT = sqlite3
+
+# The SQLITE3_OVERWRITE_DB tag is set to YES, the existing doxygen_sqlite3.db
+# database file will be recreated with each doxygen run. If set to NO, doxygen
+# will warn if an a database file is already found and not modify it.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
+
+SQLITE3_RECREATE_DB = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
+# RECURSIVE has no effect here.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = DOXYGEN_IGNORE \
+ __COUNTER__
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces
+# will be listed in the class and namespace index. If set to NO, only the
+# inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the topic index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to diagram generator tools
+#---------------------------------------------------------------------------
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
+# subgraphs. When you want a differently looking font in the dot files that
+# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
+# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
+# Edge and Graph Attributes specification</a> You need to make sure dot is able
+# to find the font, which can be done by putting it in a standard location or by
+# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font. Default graphviz fontsize is 14.
+# The default value is: fontname=Helvetica,fontsize=10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
+
+# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
+# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
+# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
+# arrows shapes.</a>
+# The default value is: labelfontname=Helvetica,labelfontsize=10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
+
+# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
+# around nodes set 'shape=plain' or 'shape=plaintext' <a
+# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
+# The default value is: shape=box,height=0.2,width=0.4.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
+
+# You can set the path where dot can find font specified with fontname in
+# DOT_COMMON_ATTR and others dot attributes.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
+# generate a graph for each documented class showing the direct and indirect
+# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
+# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
+# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
+# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.
+# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance
+# relations will be shown as texts / links.
+# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
+# The default value is: YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes. Explicit enabling a collaboration graph,
+# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the
+# command \collaborationgraph. Disabling a collaboration graph can be
+# accomplished by means of the command \hidecollaborationgraph.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies. Explicit enabling a group
+# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means
+# of the command \groupgraph. Disabling a directory graph can be accomplished by
+# means of the command \hidegroupgraph. See also the chapter Grouping in the
+# manual.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO,
+# can be accomplished by means of the command \includegraph. Disabling an
+# include graph can be accomplished by means of the command \hideincludegraph.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = NO
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set
+# to NO, can be accomplished by means of the command \includedbygraph. Disabling
+# an included by graph can be accomplished by means of the command
+# \hideincludedbygraph.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = NO
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories. Explicit enabling a directory graph, when
+# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command
+# \directorygraph. Disabling a directory graph can be accomplished by means of
+# the command \hidedirectorygraph.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = NO
+
+# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
+# of child directories generated in directory dependency graphs by dot.
+# Minimum value: 1, maximum value: 25, default value: 1.
+# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
+
+DIR_GRAPH_MAX_DEPTH = 1
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# https://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd,
+# gif, gif:cairo, gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd,
+# png:cairo, png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file or to the filename of jar file
+# to be used. If left blank, it is assumed PlantUML is not used or called during
+# a preprocessing step. Doxygen will generate a warning when it encounters a
+# \startuml command in this case and will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
+# graphical representation for inheritance and collaboration diagrams is used.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc temporary
+# files.
+# The default value is: YES.
+
+DOT_CLEANUP = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will
+# use a built-in version of mscgen tool to produce the charts. Alternatively,
+# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
+# specifying prog as the value, doxygen will call the tool as prog -T
+# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
+# output file formats "png", "eps", "svg", and "ismap".
+
+MSCGEN_TOOL =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
diff --git a/test/external/metalang99/LICENSE b/test/external/metalang99/LICENSE
new file mode 100644
index 0000000..dd7fd5b
--- /dev/null
+++ b/test/external/metalang99/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020-2025 hirrolot
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/test/external/metalang99/README.md b/test/external/metalang99/README.md
new file mode 100644
index 0000000..6985549
--- /dev/null
+++ b/test/external/metalang99/README.md
@@ -0,0 +1,391 @@
+# Metalang99
+
+[![CI](https://github.com/hirrolot/metalang99/workflows/C/C++%20CI/badge.svg)](https://github.com/hirrolot/metalang99/actions)
+[![docs](https://img.shields.io/badge/docs-readthedocs.io-blue)](https://metalang99.readthedocs.io/en/latest/)
+[![book](https://img.shields.io/badge/book-gitbook.io-pink)](https://hirrolot.gitbook.io/metalang99/)
+[![specification](https://img.shields.io/badge/specification-PDF-aa44d6)](https://github.com/hirrolot/metalang99/blob/master/spec/spec.pdf)
+
+> The dark side of the force is a pathway to many abilities, some considered to be unnatural.<br>&emsp; &emsp; <b>-- Darth Sidious</b>
+
+Based on [`examples/demo.c`](examples/demo.c):
+
+<table>
+<tr><td><b>Compile-time list manipulation</b></td></tr>
+
+<tr>
+<td>
+
+```c
+// 3, 3, 3, 3, 3
+static int five_threes[] = {
+ ML99_LIST_EVAL_COMMA_SEP(ML99_listReplicate(v(5), v(3))),
+};
+
+// 5, 4, 3, 2, 1
+static int from_5_to_1[] = {
+ ML99_LIST_EVAL_COMMA_SEP(ML99_listReverse(ML99_list(v(1, 2, 3, 4, 5)))),
+};
+
+// 9, 2, 5
+static int lesser_than_10[] = {
+ ML99_LIST_EVAL_COMMA_SEP(
+ ML99_listFilter(ML99_appl(v(ML99_greater), v(10)), ML99_list(v(9, 2, 11, 13, 5)))),
+};
+```
+
+</td>
+</tr>
+</table>
+
+<table>
+<tr><td><b>Macro recursion</b></td></tr>
+
+<tr>
+<td>
+
+```c
+#define factorial(n) ML99_natMatch(n, v(factorial_))
+#define factorial_Z_IMPL(...) v(1)
+#define factorial_S_IMPL(n) ML99_mul(ML99_inc(v(n)), factorial(v(n)))
+
+ML99_ASSERT_EQ(factorial(v(4)), v(24));
+```
+
+</td>
+</tr>
+</table>
+
+<table>
+<tr><td><b>Overloading on a number of arguments</b></td></tr>
+
+<tr>
+<td>
+
+```c
+typedef struct {
+ double width, height;
+} Rect;
+
+#define Rect_new(...) ML99_OVERLOAD(Rect_new_, __VA_ARGS__)
+#define Rect_new_1(x) \
+ { x, x }
+#define Rect_new_2(x, y) \
+ { x, y }
+
+static Rect _7x8 = Rect_new(7, 8), _10x10 = Rect_new(10);
+
+// ... and more!
+
+int main(void) {
+ // Yeah. All is done at compile time.
+}
+```
+
+</td>
+</tr>
+</table>
+
+(Hint: `v(something)` evaluates to `something`.)
+
+Metalang99 is a firm foundation for writing reliable and maintainable metaprograms in pure C99. It is implemented as an interpreted FP language atop of preprocessor macros: just `#include <metalang99.h>` and you are ready to go. Metalang99 features algebraic data types, pattern matching, recursion, currying, and collections; in addition, it provides means for compile-time error reporting and debugging. With our [built-in syntax checker], macro errors should be perfectly comprehensible, enabling you for convenient development.
+
+[built-in syntax checker]: #q-what-about-compile-time-errors
+
+Currently, Metalang99 is used at [OpenIPC] as an indirect dependency of [Datatype99] and [Interface99]; this includes an [RTSP 1.0 implementation] along with ~50k lines of private code.
+
+[OpenIPC]: https://openipc.org/
+[RTSP 1.0 implementation]: https://github.com/OpenIPC/smolrtsp/
+
+[Datatype99]: https://github.com/hirrolot/Datatype99
+[Interface99]: https://github.com/hirrolot/Interface99
+
+## Motivation
+
+Macros facilitate code re-use, macros are the building material that lets you shape the language to suit the problem being solved, leading to more clean and concise code. However, metaprogramming in C is utterly castrated: we cannot even operate with control flow, integers, unbounded sequences, and compound data structures, thereby throwing a lot of hypothetically useful metaprograms out of scope.
+
+To solve the problem, I have implemented Metalang99. Having its functionality at our disposal, it becomes possible to develop even fairly non-trivial metaprograms, such as [Datatype99]:
+
+```c
+#include <datatype99.h>
+
+datatype(
+ BinaryTree,
+ (Leaf, int),
+ (Node, BinaryTree *, int, BinaryTree *)
+);
+
+int sum(const BinaryTree *tree) {
+ match(*tree) {
+ of(Leaf, x) return *x;
+ of(Node, lhs, x, rhs) return sum(*lhs) + *x + sum(*rhs);
+ }
+
+ return -1;
+}
+```
+
+Or [Interface99]:
+
+```c
+#include <interface99.h>
+
+#include <stdio.h>
+
+#define Shape_IFACE \
+ vfunc( int, perim, const VSelf) \
+ vfunc(void, scale, VSelf, int factor)
+
+interface(Shape);
+
+typedef struct {
+ int a, b;
+} Rectangle;
+
+int Rectangle_perim(const VSelf) { /* ... */ }
+void Rectangle_scale(VSelf, int factor) { /* ... */ }
+
+impl(Shape, Rectangle);
+
+typedef struct {
+ int a, b, c;
+} Triangle;
+
+int Triangle_perim(const VSelf) { /* ... */ }
+void Triangle_scale(VSelf, int factor) { /* ... */ }
+
+impl(Shape, Triangle);
+
+void test(Shape shape) {
+ printf("perim = %d\n", VCALL(shape, perim));
+ VCALL(shape, scale, 5);
+ printf("perim = %d\n", VCALL(shape, perim));
+}
+```
+
+Unlike the vague techniques, such as [tagged unions] or [virtual method tables], the above metaprograms leverage type safety, syntax conciseness, and maintain the exact memory layout of generated code.
+
+Looks interesting? Check out the [motivational post] for more information.
+
+[tagged unions]: https://en.wikipedia.org/wiki/Tagged_union
+[virtual method tables]: https://en.wikipedia.org/wiki/Virtual_method_table
+[motivational post]: https://hirrolot.github.io/posts/macros-on-steroids-or-how-can-pure-c-benefit-from-metaprogramming.html
+
+## Getting started
+
+Metalang99 is just a set of header files and nothing else. To use it as a dependency, you need to:
+
+ 1. Add `metalang99/include` to include directories.
+ 2. Specify [`-ftrack-macro-expansion=0`] (GCC) or [`-fmacro-backtrace-limit=1`] (Clang) to avoid useless macro expansion errors.
+
+[`-ftrack-macro-expansion=0`]: https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html
+[`-fmacro-backtrace-limit=1`]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fmacro-backtrace-limit
+
+If you use CMake, the recommended way is [`FetchContent`]:
+
+[`FetchContent`]: https://cmake.org/cmake/help/latest/module/FetchContent.html
+
+```cmake
+include(FetchContent)
+
+FetchContent_Declare(
+ metalang99
+ URL https://github.com/hirrolot/metalang99/archive/refs/tags/vx.y.z.tar.gz # vx.y.z
+)
+
+FetchContent_MakeAvailable(metalang99)
+
+target_link_libraries(MyProject metalang99)
+
+# Disable full macro expansion backtraces for Metalang99.
+if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ target_compile_options(MyProject PRIVATE -fmacro-backtrace-limit=1)
+elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(MyProject PRIVATE -ftrack-macro-expansion=0)
+endif()
+```
+
+Optionally, you can [precompile headers] in your project that rely on Metalang99. This will decrease compilation time because the headers will not be compiled each time they are included.
+
+[precompile headers]: https://en.wikipedia.org/wiki/Precompiled_header
+
+[Tutorial](https://hirrolot.gitbook.io/metalang99/) | [Examples](examples/) | [User documentation](https://metalang99.readthedocs.io/en/latest/)
+
+Happy hacking!
+
+## Highlights
+
+ - **Macro recursion.** Recursive calls behave as expected. In particular, to implement recursion, [Boost/Preprocessor] just copy-pastes all recursive functions up to a certain limit and forces to either keep track of recursion depth or rely on their built-in deduction. Being an interpreter, Metalang99 is free from such drawbacks.
+
+ - **Almost the same syntax.** Metalang99 does not look too alien in comparison with [Order PP] because the syntax differs insignificantly from usual preprocessor code.
+
+ - **Partial application.** Instead of tracking auxiliary arguments here and there (as it is done in Boost/Preprocessor), Metalang99's partial application allows to capture an environment by applying constant values first. Besides that, partial application facilitates better reuse of metafunctions; see `ML99_const`, `ML99_compose`, etc.
+
+ - **Debugging and error reporting.** You can conveniently debug your macros with `ML99_abort` and report unrecoverable errors with `ML99_fatal`. The interpreter will immediately halt and do the trick. To the best of our knowledge, no other macro framework provides such a mechanism for debugging and error reporting.
+
+[Boost/Preprocessor]: http://boost.org/libs/preprocessor
+[Order PP]: https://github.com/rofl0r/order-pp
+
+## Philosophy and origins
+
+My work on [Poica], a research programming language implemented upon [Boost/Preprocessor], has left me unsatisfied with the result. The fundamental limitations of Boost/Preprocessor have made the codebase simply unmaintainable; these include recursive macro calls (blocked by the preprocessor), which have made debugging a complete nightmare, the absence of partial application that has made context passing utterly awkward, and every single mistake that resulted in megabytes of compiler error messages.
+
+Only then I have understood that instead of enriching the preprocessor with various ad-hoc mechanisms, we should really establish a clear paradigm in which to structure metaprograms. With these thoughts in mind, I started to implement Metalang99...
+
+Long story short, it took half of a year of hard work to release v0.1.0 and almost a year to make it stable. As a real-world application of Metalang99, I created [Datatype99] exactly of the same form I wanted it to be: the implementation is highly declarative, the syntax is nifty, and the semantics is well-defined.
+
+Finally, I want to say that Metalang99 is only about syntax transformations and not about CPU-bound tasks; the preprocessor is just too slow and limited for such kind of abuse.
+
+[Poica]: https://github.com/hirrolot/poica
+
+## Guidelines
+
+ - If possible, assert macro parameters for well-formedness using `ML99_assertIsTuple`, `ML99_assertIsNat`, etc. for better diagnostic messages.
+ - Prefer the `##` token-pasting operator inside [Metalang99-compliant macros] instead of `ML99_cat` or its friends, because arguments will nevertheless be fully expanded.
+ - Use [`ML99_todo` and its friends] to indicate unimplemented functionality.
+
+[Metalang99-compliant macros]: https://metalang99.readthedocs.io/en/latest/#definitions
+[`ML99_todo` and its friends]: https://metalang99.readthedocs.io/en/latest/util.html#c.ML99_todo
+
+## Blog posts
+
+ - [_Pretty-Printable Enumerations in Pure C_](https://hirrolot.github.io/posts/pretty-printable-enumerations-in-pure-c.html)
+ - [_What’s the Point of the C Preprocessor, Actually?_]
+ - [_Macros on Steroids, Or: How Can Pure C Benefit From Metaprogramming_](https://hirrolot.github.io/posts/macros-on-steroids-or-how-can-pure-c-benefit-from-metaprogramming.html)
+ - [_Extend Your Language, Don’t Alter It_](https://hirrolot.github.io/posts/extend-your-language-dont-alter-it.html)
+
+[_What’s the Point of the C Preprocessor, Actually?_]: https://hirrolot.github.io/posts/whats-the-point-of-the-c-preprocessor-actually.html
+
+## Contributing
+
+See [`CONTRIBUTING.md`](CONTRIBUTING.md).
+
+## Architecture
+
+See [`ARCHITECTURE.md`](ARCHITECTURE.md).
+
+## Idioms
+
+See [`idioms.md`](idioms.md).
+
+## Optimization tips
+
+See [`optimization_tips.md`](optimization_tips.md).
+
+## Release procedure
+
+ 1. Update the `PROJECT_NUMBER` field in `Doxyfile`.
+ 2. Update the `release` field in `docs/conf.py`.
+ 3. Update `ML99_MAJOR`, `ML99_MINOR`, and `ML99_PATCH` in `include/metalang99.h`.
+ 4. Update the version number in `spec/spec.tex` & `spec/spec.pdf`.
+ 5. Update `CHANGELOG.md`.
+ 6. Release the project in [GitHub Releases].
+
+[GitHub Releases]: https://github.com/hirrolot/metalang99/releases
+
+## FAQ
+
+### Q: What about compile-time errors?
+
+A: Metalang99 is a big step towards understandable compiler diagnostics. It has a built-in syntax checker that tests all incoming terms for validity:
+
+[`playground.c`]
+```c
+ML99_EVAL(123)
+ML99_EVAL(x, y, z)
+ML99_EVAL(v(Billie) v(Jean))
+```
+
+[`/bin/sh`]
+```
+$ gcc playground.c -Imetalang99/include -ftrack-macro-expansion=0
+playground.c:3:1: error: static assertion failed: "invalid term `123`"
+ 3 | ML99_EVAL(123)
+ | ^~~~~~~~~
+playground.c:4:1: error: static assertion failed: "invalid term `x`"
+ 4 | ML99_EVAL(x, y, z)
+ | ^~~~~~~~~
+playground.c:5:1: error: static assertion failed: "invalid term `(0v, Billie) (0v, Jean)`, did you miss a comma?"
+ 5 | ML99_EVAL(v(Billie) v(Jean))
+ | ^~~~~~~~~
+```
+
+Metalang99 can even check for macro preconditions and report an error:
+
+[`playground.c`]
+```c
+ML99_EVAL(ML99_listHead(ML99_nil()))
+ML99_EVAL(ML99_unwrapLeft(ML99_right(v(123))))
+ML99_EVAL(ML99_div(v(18), v(4)))
+```
+
+[`/bin/sh`]
+```
+$ gcc playground.c -Imetalang99/include -ftrack-macro-expansion=0
+playground.c:3:1: error: static assertion failed: "ML99_listHead: expected a non-empty list"
+ 3 | ML99_EVAL(ML99_listHead(ML99_nil()))
+ | ^~~~~~~~~
+playground.c:4:1: error: static assertion failed: "ML99_unwrapLeft: expected ML99_left but found ML99_right"
+ 4 | ML99_EVAL(ML99_unwrapLeft(ML99_right(v(123))))
+ | ^~~~~~~~~
+playground.c:5:1: error: static assertion failed: "ML99_div: 18 is not divisible by 4"
+ 5 | ML99_EVAL(ML99_div(v(18), v(4)))
+ | ^~~~~~~~~
+```
+
+However, if you do something awkward, compile-time errors can become quite obscured:
+
+```c
+// ML99_PRIV_REC_NEXT_ML99_PRIV_IF_0 blah(ML99_PRIV_SYNTAX_CHECKER_EMIT_ERROR, ML99_PRIV_TERM_MATCH) ((~, ~, ~) blah, ML99_PRIV_EVAL_)(ML99_PRIV_REC_STOP, (~), 0fspace, (, ), ((0end, ~), ~), ~, ~ blah)(0)()
+ML99_EVAL((~, ~, ~) blah)
+```
+
+In either case, you can try to [iteratively debug your metaprogram](https://hirrolot.gitbook.io/metalang99/testing-debugging-and-error-reporting). From my experience, 95% of errors are comprehensible -- Metalang99 is built for humans, not for macro monsters.
+
+### Q: What about debugging?
+
+A: See the chapter [_"Testing, debugging, and error reporting"_](https://hirrolot.gitbook.io/metalang99/testing-debugging-and-error-reporting).
+
+### Q: What about IDE support?
+
+A: I use VS Code for development. It enables pop-up suggestments of macro-generated constructions but, of course, it does not support macro syntax highlighting.
+
+### Q: Compilation times?
+
+A: To run the benchmarks, execute `./scripts/bench.sh` from the root directory.
+
+### Q: How does it work?
+
+A:
+
+ 1. Because macro recursion is prohibited, there is an ad-hoc [recursion engine] which works by deferring macro expansions and passing continuations here and there.
+ 2. Upon it, the [continuation-passing style] [interpreter] reduces language expressions into final results.
+ 3. The standard library is nothing but a set of metafunctions implemented using the core metalanguage, i.e. they are to be evaluated by the interpreter.
+
+[recursion engine]: include/metalang99/eval/rec.h
+[interpreter]: include/metalang99/eval/eval.h
+[continuation-passing style]: https://en.wikipedia.org/wiki/Continuation-passing_style
+
+### Q: Why not third-party code generators?
+
+A: See the blog post [_"What’s the Point of the C Preprocessor, Actually?"_](https://hirrolot.github.io/posts/whats-the-point-of-the-c-preprocessor-actually.html)
+
+### Q: Is it Turing-complete?
+
+A: The C/C++ preprocessor is capable to iterate only [up to a certain limit](https://stackoverflow.com/questions/3136686/is-the-c99-preprocessor-turing-complete). For Metalang99, this limit is defined in terms of reductions steps: once a fixed amount of reduction steps is exhausted, your metaprogram will not be able to execute anymore.
+
+### Q: Why macros if we have templates?
+
+A: Metalang99 is primarily targeted at pure C, and C lacks templates. But anyway, you can find the argumentation for C++ at the website of [Boost/Preprocessor].
+
+### Q: Which standards are supported?
+
+A: C99/C++11 and onwards.
+
+### Q: Which compilers are tested?
+
+A: Metalang99 is known to work on these compilers:
+
+ - GCC
+ - Clang
+ - MSVC
+ - TCC
diff --git a/test/external/metalang99/bench/100_call.c b/test/external/metalang99/bench/100_call.c
new file mode 100644
index 0000000..e4b1981
--- /dev/null
+++ b/test/external/metalang99/bench/100_call.c
@@ -0,0 +1,12 @@
+#include <metalang99.h>
+
+#define F_IMPL(x, y, z) v(x + y + z)
+
+#define _5 \
+ ML99_call(F, v(1), v(2), v(3)), ML99_call(F, v(1), v(2), v(3)), \
+ ML99_call(F, v(1), v(2), v(3)), ML99_call(F, v(1), v(2), v(3)), \
+ ML99_call(F, v(1), v(2), v(3))
+#define _10 _5, _5
+#define _100 _10, _10, _10, _10, _10, _10, _10, _10, _10, _10
+
+ML99_EVAL(_100)
diff --git a/test/external/metalang99/bench/100_v.c b/test/external/metalang99/bench/100_v.c
new file mode 100644
index 0000000..d97c3ed
--- /dev/null
+++ b/test/external/metalang99/bench/100_v.c
@@ -0,0 +1,8 @@
+#include <metalang99.h>
+
+#define _10 \
+ v(~~~~~~~~~~), v(~~~~~~~~~~), v(~~~~~~~~~~), v(~~~~~~~~~~), v(~~~~~~~~~~), v(~~~~~~~~~~), \
+ v(~~~~~~~~~~), v(~~~~~~~~~~), v(~~~~~~~~~~), v(~~~~~~~~~~)
+#define _100 _10, _10, _10, _10, _10, _10, _10, _10, _10, _10
+
+ML99_EVAL(_100)
diff --git a/test/external/metalang99/bench/README.md b/test/external/metalang99/bench/README.md
new file mode 100644
index 0000000..f8cb95e
--- /dev/null
+++ b/test/external/metalang99/bench/README.md
@@ -0,0 +1,3 @@
+# Benchmarking
+
+Execute `./scripts/bench.sh` from the root directory to run the benchmarks.
diff --git a/test/external/metalang99/bench/compare_25_items.c b/test/external/metalang99/bench/compare_25_items.c
new file mode 100644
index 0000000..5a166f9
--- /dev/null
+++ b/test/external/metalang99/bench/compare_25_items.c
@@ -0,0 +1,6 @@
+#include <metalang99.h>
+
+#define NUMBERS \
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
+
+ML99_ASSERT(ML99_listEq(v(ML99_natEq), ML99_list(v(NUMBERS)), ML99_list(v(NUMBERS))));
diff --git a/test/external/metalang99/bench/filter_map.c b/test/external/metalang99/bench/filter_map.c
new file mode 100644
index 0000000..8aeb211
--- /dev/null
+++ b/test/external/metalang99/bench/filter_map.c
@@ -0,0 +1,9 @@
+#include <metalang99.h>
+
+#define _10 5, 5, 5, 5, 5, 3, 3, 3, 3, 3
+#define _50 _10, _10, _10, _10, _10
+
+#define F_IMPL(x) ML99_if(ML99_natEq(v(x), v(5)), ML99_just(v(x)), ML99_nothing())
+#define F_ARITY 1
+
+ML99_LIST_EVAL(ML99_listFilterMap(v(F), ML99_list(v(_50, _10, 3, 3, 3))))
diff --git a/test/external/metalang99/bench/list_of_63_items.c b/test/external/metalang99/bench/list_of_63_items.c
new file mode 100644
index 0000000..8ee1f5c
--- /dev/null
+++ b/test/external/metalang99/bench/list_of_63_items.c
@@ -0,0 +1,8 @@
+#include <metalang99.h>
+
+#define NUMBERS \
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, \
+ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
+
+ML99_EVAL(ML99_list(v(NUMBERS)))
diff --git a/test/external/metalang99/bench/many_call_in_arg_pos.c b/test/external/metalang99/bench/many_call_in_arg_pos.c
new file mode 100644
index 0000000..712738f
--- /dev/null
+++ b/test/external/metalang99/bench/many_call_in_arg_pos.c
@@ -0,0 +1,10 @@
+#include <metalang99.h>
+
+#define F_IMPL(x) v(x)
+
+#define CALL ML99_call(F, ML99_call(F, ML99_call(F, v(~~~~~))))
+#define _5 CALL, CALL, CALL, CALL, CALL
+#define _10 _5, _5
+#define _100 _10, _10, _10, _10, _10, _10, _10, _10, _10, _10
+
+ML99_EVAL(_100)
diff --git a/test/external/metalang99/docs/Makefile b/test/external/metalang99/docs/Makefile
new file mode 100644
index 0000000..d4bb2cb
--- /dev/null
+++ b/test/external/metalang99/docs/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = .
+BUILDDIR = _build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/test/external/metalang99/docs/assert.rst b/test/external/metalang99/docs/assert.rst
new file mode 100644
index 0000000..18d1ac0
--- /dev/null
+++ b/test/external/metalang99/docs/assert.rst
@@ -0,0 +1,5 @@
+assert.h
+========
+
+.. doxygenfile:: assert.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/bool.rst b/test/external/metalang99/docs/bool.rst
new file mode 100644
index 0000000..8ef73f1
--- /dev/null
+++ b/test/external/metalang99/docs/bool.rst
@@ -0,0 +1,5 @@
+bool.h
+======
+
+.. doxygenfile:: bool.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/choice.rst b/test/external/metalang99/docs/choice.rst
new file mode 100644
index 0000000..3ee0ab6
--- /dev/null
+++ b/test/external/metalang99/docs/choice.rst
@@ -0,0 +1,5 @@
+choice.h
+========
+
+.. doxygenfile:: choice.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/conf.py b/test/external/metalang99/docs/conf.py
new file mode 100644
index 0000000..daebca3
--- /dev/null
+++ b/test/external/metalang99/docs/conf.py
@@ -0,0 +1,57 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+# -- Project information -----------------------------------------------------
+
+import subprocess
+
+subprocess.call("cd .. ; doxygen", shell=True)
+
+project = 'Metalang99'
+copyright = '2021, hirrolot'
+author = 'hirrolot'
+
+# The full version, including alpha/beta/rc tags
+release = '1.13.5'
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ["breathe"]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = "insipid"
+
+breathe_projects = {"Metalang99": "../xml"}
+breathe_default_project = "Metalang99"
+primary_domain = 'c'
+highlight_language = 'c'
diff --git a/test/external/metalang99/docs/either.rst b/test/external/metalang99/docs/either.rst
new file mode 100644
index 0000000..5da16a2
--- /dev/null
+++ b/test/external/metalang99/docs/either.rst
@@ -0,0 +1,5 @@
+either.h
+========
+
+.. doxygenfile:: either.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/gen.rst b/test/external/metalang99/docs/gen.rst
new file mode 100644
index 0000000..09a20b2
--- /dev/null
+++ b/test/external/metalang99/docs/gen.rst
@@ -0,0 +1,5 @@
+gen.h
+=====
+
+.. doxygenfile:: gen.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/ident.rst b/test/external/metalang99/docs/ident.rst
new file mode 100644
index 0000000..51823cf
--- /dev/null
+++ b/test/external/metalang99/docs/ident.rst
@@ -0,0 +1,5 @@
+ident.h
+=======
+
+.. doxygenfile:: ident.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/index.rst b/test/external/metalang99/docs/index.rst
new file mode 100644
index 0000000..4666879
--- /dev/null
+++ b/test/external/metalang99/docs/index.rst
@@ -0,0 +1,120 @@
+.. Metalang99 documentation master file, created by
+ sphinx-quickstart on Mon Jan 4 08:10:23 2021.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+The Metalang99 Standard Library
+===============================
+
+The Metalang99 standard library exports a set of macros implemented using the `Metalang99 metalanguage`_.
+
+Definitions
+-----------
+
+ - A plain macro is a macro whose result can be computed only by preprocessor expansion.
+
+ - A Metalang99-compliant macro is a macro called through `ML99_call`/`ML99_callUneval`, directly or indirectly. To compute its result, the Metalang99 interpreter is needed.
+
+ - A desugaring macro is a convenience macro `X(params...)` which expands to `ML99_call(X, params...)` so that you can invoke `X` as `X(v(1), v(2), v(3))`. Desugaring macros are provided for all public Metalang99-compliant macros.
+
+Naming conventions
+------------------
+
+ - Plain macros follow the `SCREAMING_CASE` convention.
+ - Metalang99-compliant macros follow the `camelCase` convention.
+ - Macros denoting language terms (defined by `lang.h`) follow the `camelCase` convention.
+
+Sometimes, there exist two versions of the same macro: one is plain, and the other is Metalang99-compliant. For example, here are two complete metaprograms, one using `ML99_untuple` and the second one using `ML99_UNTUPLE`:
+
+.. code:: c
+
+ ML99_EVAL(ML99_untuple(v((1, 2, 3))))
+
+.. code:: c
+
+ ML99_UNTUPLE((1, 2, 3))
+
+Both metaprograms result in `1, 2, 3`.
+
+Version manipulation macros
+---------------------------
+
+*The following macros are defined in metalang99.h*.
+
+`ML99_MAJOR`, `ML99_MINOR`, and `ML99_PATCH` denote the major, the minor, and the patch version numbers, respectively.
+
+`ML99_VERSION_COMPATIBLE(x, y, z)` and `ML99_VERSION_EQ(x, y, z)` are function-like macros that expand to a constant boolean expression:
+
+ - The former holds iff the current Metalang99 version is at least vx.y.z in a `SemVer`_-compatible way. Thus, if the current version is v1.2.3, then `ML99_VERSION_COMPATIBLE` will hold for v1.2.3, v1.2.6, v1.6.0, but not for v2.5.0 or v3.0.0.
+ - The latter one holds iff the version is exactly vx.y.z.
+
+These macros can be used as follows:
+
+.. code:: c
+
+ #if !ML99_VERSION_COMPATIBLE(1, 2, 3)
+ #error Please, update your Metalang99 to v1.2.3 or higher!
+ #endif
+
+.. toctree::
+ :hidden:
+
+ lang
+ choice
+ tuple
+ variadics
+ list
+ seq
+ either
+ maybe
+ nat
+ ident
+ bool
+ util
+ assert
+ gen
+ stmt
+
+Contents
+====================================
+
+ - `lang.h`_ - The core metalanguage.
+ - `choice.h`_ - Choice types: `(tag, ...)`.
+ - `tuple.h`_ - Tuples: `(x, y, z)`.
+ - `variadics.h`_ - Variadic arguments: `x, y, z`.
+ - `list.h`_ - Cons-lists.
+ - `seq.h`_ - Sequences: `(x)(y)(z)`.
+ - `either.h`_ - A choice type with two cases.
+ - `maybe.h`_ - An optional value.
+ - `nat.h`_ - Natural numbers: [0; 255].
+ - `ident.h`_ - Identifiers: `[a-zA-Z0-9_]+`.
+ - `bool.h`_ - Boolean algebra.
+ - `util.h`_ - Utilitary stuff.
+ - `assert.h`_ - Static assertions.
+ - `gen.h`_ - Support for C language constructions.
+ - `stmt.h`_ - Statement chaining.
+
+Indices and tables
+====================================
+
+* :ref:`genindex`
+* :ref:`search`
+
+.. _Metalang99 metalanguage: https://github.com/hirrolot/metalang99
+.. _SemVer: https://semver.org/
+
+.. _lang.h: lang.html
+.. _choice.h: choice.html
+.. _tuple.h: tuple.html
+.. _variadics.h: variadics.html
+.. _list.h: list.html
+.. _seq.h: seq.html
+.. _either.h: either.html
+.. _maybe.h: maybe.html
+.. _nat.h: nat.html
+.. _ident.h: ident.html
+.. _bool.h: bool.html
+.. _util.h: util.html
+.. _assert.h: assert.html
+.. _gen.h: gen.html
+.. _stmt.h: stmt.html
diff --git a/test/external/metalang99/docs/lang.rst b/test/external/metalang99/docs/lang.rst
new file mode 100644
index 0000000..1e413c1
--- /dev/null
+++ b/test/external/metalang99/docs/lang.rst
@@ -0,0 +1,5 @@
+lang.h
+======
+
+.. doxygenfile:: lang.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/list.rst b/test/external/metalang99/docs/list.rst
new file mode 100644
index 0000000..7da444c
--- /dev/null
+++ b/test/external/metalang99/docs/list.rst
@@ -0,0 +1,5 @@
+list.h
+======
+
+.. doxygenfile:: list.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/make.bat b/test/external/metalang99/docs/make.bat
new file mode 100644
index 0000000..2119f51
--- /dev/null
+++ b/test/external/metalang99/docs/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=.
+set BUILDDIR=_build
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/test/external/metalang99/docs/maybe.rst b/test/external/metalang99/docs/maybe.rst
new file mode 100644
index 0000000..7b23c60
--- /dev/null
+++ b/test/external/metalang99/docs/maybe.rst
@@ -0,0 +1,5 @@
+maybe.h
+=======
+
+.. doxygenfile:: maybe.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/nat.rst b/test/external/metalang99/docs/nat.rst
new file mode 100644
index 0000000..e1410c2
--- /dev/null
+++ b/test/external/metalang99/docs/nat.rst
@@ -0,0 +1,5 @@
+nat.h
+=====
+
+.. doxygenfile:: nat.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/requirements.txt b/test/external/metalang99/docs/requirements.txt
new file mode 100644
index 0000000..2b0e822
--- /dev/null
+++ b/test/external/metalang99/docs/requirements.txt
@@ -0,0 +1,2 @@
+breathe >= 4.25.1
+insipid-sphinx-theme >= 0.2.8
diff --git a/test/external/metalang99/docs/seq.rst b/test/external/metalang99/docs/seq.rst
new file mode 100644
index 0000000..dc8ea0d
--- /dev/null
+++ b/test/external/metalang99/docs/seq.rst
@@ -0,0 +1,5 @@
+seq.h
+=====
+
+.. doxygenfile:: seq.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/stmt.rst b/test/external/metalang99/docs/stmt.rst
new file mode 100644
index 0000000..c0548c6
--- /dev/null
+++ b/test/external/metalang99/docs/stmt.rst
@@ -0,0 +1,5 @@
+stmt.h
+======
+
+.. doxygenfile:: stmt.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/tuple.rst b/test/external/metalang99/docs/tuple.rst
new file mode 100644
index 0000000..c81bcf2
--- /dev/null
+++ b/test/external/metalang99/docs/tuple.rst
@@ -0,0 +1,5 @@
+tuple.h
+=======
+
+.. doxygenfile:: tuple.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/util.rst b/test/external/metalang99/docs/util.rst
new file mode 100644
index 0000000..f0637e8
--- /dev/null
+++ b/test/external/metalang99/docs/util.rst
@@ -0,0 +1,5 @@
+util.h
+======
+
+.. doxygenfile:: util.h
+ :project: Metalang99
diff --git a/test/external/metalang99/docs/variadics.rst b/test/external/metalang99/docs/variadics.rst
new file mode 100644
index 0000000..126c2a8
--- /dev/null
+++ b/test/external/metalang99/docs/variadics.rst
@@ -0,0 +1,5 @@
+variadics.h
+===========
+
+.. doxygenfile:: variadics.h
+ :project: Metalang99
diff --git a/test/external/metalang99/examples/.gitignore b/test/external/metalang99/examples/.gitignore
new file mode 100644
index 0000000..567609b
--- /dev/null
+++ b/test/external/metalang99/examples/.gitignore
@@ -0,0 +1 @@
+build/
diff --git a/test/external/metalang99/examples/CMakeLists.txt b/test/external/metalang99/examples/CMakeLists.txt
new file mode 100644
index 0000000..ed8e963
--- /dev/null
+++ b/test/external/metalang99/examples/CMakeLists.txt
@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 3.16)
+project(examples LANGUAGES C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ add_compile_options(-Wall -Wextra -pedantic -std=c99
+ -ftrack-macro-expansion=0)
+elseif(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ add_compile_options("-fmacro-backtrace-limit=1")
+elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
+ # Enable a standard-conforming C99/C11 preprocessor.
+ add_compile_options("/std:c11")
+elseif(CMAKE_C_COMPILER_ID STREQUAL "TinyCC")
+ add_compile_definitions(ML99_ALLOW_POOR_DIAGNOSTICS)
+endif()
+
+include_directories(../include)
+
+add_executable(ackermann ackermann.c)
+add_executable(assert_for_each assert_for_each.c)
+add_executable(binary_tree binary_tree.c)
+add_executable(demo demo.c)
+add_executable(duffs_device duffs_device.c)
+add_executable(factorial factorial.c)
+add_executable(overload overload.c)
+add_executable(rectangle rectangle.c)
+add_executable(lambda_calculus lambda_calculus.c)
+
+foreach(TARGET ${BUILDSYSTEM_TARGETS})
+ set_target_properties(TARGET PROPERTIES C_STANDARD 99 C_STANDARD_REQUIRED ON)
+endforeach()
diff --git a/test/external/metalang99/examples/ackermann.c b/test/external/metalang99/examples/ackermann.c
new file mode 100644
index 0000000..a3ea623
--- /dev/null
+++ b/test/external/metalang99/examples/ackermann.c
@@ -0,0 +1,22 @@
+#include <metalang99.h>
+
+#define ack(m, n) ML99_natMatchWithArgs(m, v(ack_), n)
+
+#define ack_Z_IMPL(n) ML99_inc(v(n))
+#define ack_S_IMPL(m, n) ML99_natMatchWithArgs(v(n), v(ack_S_), v(m))
+#define ack_S_Z_IMPL(m) ack(v(m), v(1))
+#define ack_S_S_IMPL(n, m) ack(v(m), ack(ML99_inc(v(m)), v(n)))
+
+ML99_ASSERT_EQ(ack(v(0), v(0)), v(1));
+ML99_ASSERT_EQ(ack(v(0), v(1)), v(2));
+ML99_ASSERT_EQ(ack(v(0), v(2)), v(3));
+
+ML99_ASSERT_EQ(ack(v(1), v(0)), v(2));
+ML99_ASSERT_EQ(ack(v(1), v(1)), v(3));
+ML99_ASSERT_EQ(ack(v(1), v(2)), v(4));
+
+ML99_ASSERT_EQ(ack(v(2), v(0)), v(3));
+ML99_ASSERT_EQ(ack(v(2), v(1)), v(5));
+ML99_ASSERT_EQ(ack(v(2), v(2)), v(7));
+
+int main(void) {}
diff --git a/test/external/metalang99/examples/assert_for_each.c b/test/external/metalang99/examples/assert_for_each.c
new file mode 100644
index 0000000..3ba9127
--- /dev/null
+++ b/test/external/metalang99/examples/assert_for_each.c
@@ -0,0 +1,31 @@
+// Asserts multiple expressions at once.
+
+#include <metalang99.h>
+
+#include <assert.h>
+
+#define ASSERT_FOR_EACH(...) \
+ do { \
+ ML99_EVAL(ML99_variadicsForEach( \
+ ML99_compose(v(ML99_semicoloned), ML99_reify(v(assert))), \
+ v(__VA_ARGS__))) \
+ } while (0)
+
+int main(void) {
+ ASSERT_FOR_EACH(123 == 123, 2 + 2 == 4, "foo"[1] == 'o');
+
+ /*
+ * If we combine multiple assertions with the && operator, we will not be able to distinguish
+ * them if one of them fails apparently:
+ *
+ * main: Assertion `123 == 321 && 2 + 2 == 4 && "foo"[1] == 'o' failed.
+ * assert(123 == 321 && 2 + 2 == 4 && "foo"[1] == 'o');
+ */
+
+ /*
+ * ... unlike `ASSERT_FOR_EACH` telling us which one has failed:
+ *
+ * main: Assertion `123 == 321' failed.
+ * ASSERT_FOR_EACH(123 == 321, 2 + 2 == 4, "foo"[1] == 'o');
+ */
+}
diff --git a/test/external/metalang99/examples/binary_tree.c b/test/external/metalang99/examples/binary_tree.c
new file mode 100644
index 0000000..8cd9177
--- /dev/null
+++ b/test/external/metalang99/examples/binary_tree.c
@@ -0,0 +1,25 @@
+// Sums all nodes of a binary tree, recursively.
+
+#include <metalang99.h>
+
+#define leaf(x) ML99_choice(v(leaf), x)
+#define node(lhs, data, rhs) ML99_choice(v(node), lhs, data, rhs)
+
+#define sumTree(tree) ML99_match(tree, v(sumTree_))
+#define sumTree_leaf_IMPL(x) v(x)
+#define sumTree_node_IMPL(lhs, data, rhs) ML99_add3(sumTree(v(lhs)), v(data), sumTree(v(rhs)))
+
+/*
+ * 4
+ * / \
+ * / \
+ * / \
+ * 2 6
+ * / \ / \
+ * 1 3 5 7
+ */
+#define TREE node(node(leaf(v(1)), v(2), leaf(v(3))), v(4), node(leaf(v(5)), v(6), leaf(v(7))))
+
+ML99_ASSERT_EQ(sumTree(TREE), v(28));
+
+int main(void) {}
diff --git a/test/external/metalang99/examples/demo.c b/test/external/metalang99/examples/demo.c
new file mode 100644
index 0000000..4a209d9
--- /dev/null
+++ b/test/external/metalang99/examples/demo.c
@@ -0,0 +1,48 @@
+// `...` is sometimes used to workaround a TCC bug, see
+// <https://github.com/hirrolot/datatype99/issues/10#issuecomment-830813172>.
+
+#include <metalang99.h>
+
+// Compile-time list manipulation:
+
+// 3, 3, 3, 3, 3
+static int five_threes[] = {
+ ML99_LIST_EVAL_COMMA_SEP(ML99_listReplicate(v(5), v(3))),
+};
+
+// 5, 4, 3, 2, 1
+static int from_5_to_1[] = {
+ ML99_LIST_EVAL_COMMA_SEP(ML99_listReverse(ML99_list(v(1, 2, 3, 4, 5)))),
+};
+
+// 9, 2, 5
+static int lesser_than_10[] = {
+ ML99_LIST_EVAL_COMMA_SEP(
+ ML99_listFilter(ML99_appl(v(ML99_greater), v(10)), ML99_list(v(9, 2, 11, 13, 5)))),
+};
+
+// Macro recursion:
+#define factorial(n) ML99_natMatch(n, v(factorial_))
+#define factorial_Z_IMPL(...) v(1) // `...` due to the TCC's bug.
+#define factorial_S_IMPL(n) ML99_mul(ML99_inc(v(n)), factorial(v(n)))
+
+ML99_ASSERT_EQ(factorial(v(4)), v(24));
+
+// Overloading on a number of arguments:
+typedef struct {
+ double width, height;
+} Rect;
+
+#define Rect_new(...) ML99_OVERLOAD(Rect_new_, __VA_ARGS__)
+#define Rect_new_1(x) \
+ { x, x }
+#define Rect_new_2(x, y) \
+ { x, y }
+
+static Rect _7x8 = Rect_new(7, 8), _10x10 = Rect_new(10);
+
+// ... and more!
+
+int main(void) {
+ // Yeah. All is done at compile time.
+}
diff --git a/test/external/metalang99/examples/duffs_device.c b/test/external/metalang99/examples/duffs_device.c
new file mode 100644
index 0000000..cc5ade0
--- /dev/null
+++ b/test/external/metalang99/examples/duffs_device.c
@@ -0,0 +1,76 @@
+/**
+ * Duff's device [1] is a technique to implement loop unrolling through amalgamation of a switch
+ * statement with a do-while loop.
+ *
+ * In this example, we are going to implement automatic generation of Duff's device.
+ *
+ * [1]: https://en.wikipedia.org/wiki/Duff's_device
+ */
+
+#include <metalang99.h>
+
+#include <assert.h>
+
+#define DUFFS_DEVICE(unrolling_factor, counter_ty, count, ...) \
+ do { \
+ if ((count) > 0) { \
+ counter_ty DUFFS_DEVICE_n = ((count) + ML99_DEC(unrolling_factor)) / unrolling_factor; \
+ switch ((count) % unrolling_factor) { \
+ case 0: \
+ do { \
+ __VA_ARGS__ \
+ ML99_EVAL(ML99_callUneval(genCases, ML99_DEC(unrolling_factor), __VA_ARGS__)) \
+ } while (--DUFFS_DEVICE_n > 0); \
+ } \
+ } \
+ } while (0)
+
+#define genCases_IMPL(i, ...) \
+ ML99_IF( \
+ ML99_NAT_EQ(i, 0), \
+ ML99_empty(), \
+ ML99_TERMS( \
+ v(/* FALLTHROUGH */ case i \
+ : __VA_ARGS__), \
+ ML99_callUneval(genCases, ML99_DEC(i), __VA_ARGS__)))
+
+int main(void) {
+#define ARRAY_LEN 50
+#define UNROLLING_FACTOR 3
+
+ int array[ARRAY_LEN] = { ML99_EVAL(ML99_times(v(ARRAY_LEN), v(5, ))) };
+ int *n_ptr = array;
+
+ // Square all the elements in the array.
+ DUFFS_DEVICE(UNROLLING_FACTOR, int, ARRAY_LEN, {
+ *n_ptr *= *n_ptr;
+ n_ptr++;
+ });
+
+ for (int i = 0; i < ARRAY_LEN; i++) {
+ assert(25 == array[i]);
+ }
+}
+
+/*
+The generated Duff's device:
+
+int DUFFS_DEVICE_n = ((50) + 2) / 3;
+switch ((50) % 3) {
+case 0:
+ do {
+ {
+ *n_ptr *= *n_ptr;
+ n_ptr++;
+ }
+ case 2: {
+ *n_ptr *= *n_ptr;
+ n_ptr++;
+ }
+ case 1: {
+ *n_ptr *= *n_ptr;
+ n_ptr++;
+ }
+ } while (--DUFFS_DEVICE_n > 0);
+}
+*/
diff --git a/test/external/metalang99/examples/factorial.c b/test/external/metalang99/examples/factorial.c
new file mode 100644
index 0000000..ed381fa
--- /dev/null
+++ b/test/external/metalang99/examples/factorial.c
@@ -0,0 +1,16 @@
+// `...` is sometimes used to workaround a TCC bug, see
+// <https://github.com/hirrolot/datatype99/issues/10#issuecomment-830813172>.
+
+#include <metalang99.h>
+
+#define factorial(n) ML99_natMatch(n, v(factorial_))
+#define factorial_Z_IMPL(...) v(1) // `...` due to the TCC's bug.
+#define factorial_S_IMPL(n) ML99_mul(ML99_inc(v(n)), factorial(v(n)))
+
+ML99_ASSERT_EQ(factorial(v(0)), v(1));
+ML99_ASSERT_EQ(factorial(v(1)), v(1));
+ML99_ASSERT_EQ(factorial(v(2)), v(2));
+ML99_ASSERT_EQ(factorial(v(3)), v(6));
+ML99_ASSERT_EQ(factorial(v(4)), v(24));
+
+int main(void) {}
diff --git a/test/external/metalang99/examples/lambda_calculus.c b/test/external/metalang99/examples/lambda_calculus.c
new file mode 100644
index 0000000..e300304
--- /dev/null
+++ b/test/external/metalang99/examples/lambda_calculus.c
@@ -0,0 +1,209 @@
+/*
+ * An untyped lambda calculus [1] interpreter using De Bruijn indices [2] and normal order
+ * evaluation strategy [3].
+ *
+ * [1] https://en.wikipedia.org/wiki/Lambda_calculus
+ * [2] https://en.wikipedia.org/wiki/De_Bruijn_index
+ * [3] https://en.wikipedia.org/wiki/Evaluation_strategy#Normal_order
+ */
+
+#include <metalang99.h>
+
+// Syntactic terms {
+
+#define var(i) ML99_call(var, i)
+#define appl(M, N) ML99_call(appl, M, N)
+#define lam(M) ML99_call(lam, M)
+
+#define var_IMPL(i) v(VAR(i))
+#define appl_IMPL(M, N) v(APPL(M, N))
+#define lam_IMPL(M) v(LAM(M))
+
+#define VAR(i) ML99_CHOICE(var, i)
+#define APPL(M, N) ML99_CHOICE(appl, M, N)
+#define LAM(M) ML99_CHOICE(lam, M)
+// } (Syntactic terms)
+
+// Variable substitution: `M[1=x]` {
+
+#define subst(M, x) ML99_call(subst, M, x)
+
+#define subst_IMPL(M, x) substAux_IMPL(M, x, 1)
+#define substAux_IMPL(M, x, depth) ML99_callUneval(ML99_matchWithArgs, M, substAux_, x, depth)
+
+#define substAux_var_IMPL(i, x, depth) \
+ ML99_IF( \
+ ML99_NAT_EQ(i, depth), \
+ v(x), \
+ ML99_call(ML99_if, ML99_callUneval(ML99_greater, i, depth), v(VAR(ML99_DEC(i)), VAR(i))))
+#define substAux_appl_IMPL(M, N, x, depth) \
+ appl(substAux_IMPL(M, x, depth), substAux_IMPL(N, x, depth))
+#define substAux_lam_IMPL(M, x, depth) \
+ lam(ML99_call(substAux, v(M), incFreeVars_IMPL(x), v(ML99_INC(depth))))
+// } (Variable substitution)
+
+// Increment free variables in `M` {
+
+#define incFreeVars(M) ML99_call(incFreeVars, M)
+
+#define incFreeVars_IMPL(M) incFreeVarsAux_IMPL(M, 1)
+#define incFreeVarsAux_IMPL(M, depth) ML99_callUneval(ML99_matchWithArgs, M, incFreeVarsAux_, depth)
+
+#define incFreeVarsAux_var_IMPL(i, depth) \
+ ML99_call(ML99_if, ML99_callUneval(ML99_greaterEq, i, depth), v(VAR(ML99_INC(i)), VAR(i)))
+#define incFreeVarsAux_appl_IMPL(M, N, depth) \
+ appl(incFreeVarsAux_IMPL(M, depth), incFreeVarsAux_IMPL(N, depth))
+#define incFreeVarsAux_lam_IMPL(M, depth) lam(incFreeVarsAux_IMPL(M, ML99_INC(depth)))
+// } (Increment free variables)
+
+// Evaluation {
+
+#define eval(M) ML99_call(eval, M)
+
+#define eval_IMPL(M) ML99_callUneval(ML99_match, M, eval_)
+#define eval_var_IMPL(i) v(VAR(i))
+#define eval_appl_IMPL(M, N) ML99_callUneval(ML99_matchWithArgs, M, eval_appl_, N)
+#define eval_lam_IMPL(M) lam(eval_IMPL(M))
+
+#define eval_appl_var_IMPL(i, N) appl(v(VAR(i)), eval_IMPL(N))
+#define eval_appl_appl_IMPL(M, N, N1) \
+ ML99_call(ML99_matchWithArgs, eval(appl_IMPL(M, N)), v(eval_appl_appl_, N1))
+#define eval_appl_lam_IMPL(M, N) eval(subst_IMPL(M, N))
+
+#define eval_appl_appl_var_IMPL eval_appl_var_IMPL
+#define eval_appl_appl_appl_IMPL(M, N, N1) appl(appl_IMPL(M, N), eval_IMPL(N1))
+#define eval_appl_appl_lam_IMPL eval_appl_lam_IMPL
+// } (Evaluation)
+
+// Syntactical equality {
+
+#define termEq(lhs, rhs) ML99_matchWithArgs(lhs, v(termEq_), rhs)
+#define termEq_var_IMPL(i, rhs) termEqPropagate(var, rhs, i)
+#define termEq_appl_IMPL(M, N, rhs) termEqPropagate(appl, rhs, M, N)
+#define termEq_lam_IMPL(M, rhs) termEqPropagate(lam, rhs, M)
+
+#define termEqPropagate(term_kind, rhs, ...) \
+ ML99_IF( \
+ ML99_IDENT_EQ(TERM_, ML99_CHOICE_TAG(rhs), term_kind), \
+ ML99_matchWithArgs(v(rhs), v(termEq_##term_kind##_), v(__VA_ARGS__)), \
+ ML99_false())
+
+#define termEq_var_var_IMPL(j, i) v(ML99_NAT_EQ(i, j))
+#define termEq_appl_appl_IMPL(M, N, M1, N1) ML99_and(termEq(v(M), v(M1)), termEq(v(N), v(N1)))
+#define termEq_lam_lam_IMPL(M, M1) termEq(v(M), v(M1))
+
+#define TERM_var_var ()
+#define TERM_appl_appl ()
+#define TERM_lam_lam ()
+// } (Syntactical equality)
+
+#define ASSERT_REDUCES_TO(lhs, rhs) \
+ /* Use two interpreter passes: one for `eval(lhs)`, one for `termEq`. Thereby we achieve more \
+ * Metalang99 reduction steps available. */ \
+ ML99_ASSERT_UNEVAL(ML99_EVAL(termEq(v(ML99_EVAL(eval(v(lhs)))), v(ML99_EVAL(eval(v(rhs)))))))
+
+// The identity combinator {
+
+#define I LAM(VAR(1))
+
+ASSERT_REDUCES_TO(APPL(I, VAR(5)), VAR(5));
+// } (The identity combinator)
+
+// The K, S combinators {
+
+#define K LAM(LAM(VAR(2)))
+#define S LAM(LAM(LAM(APPL(APPL(VAR(3), VAR(1)), APPL(VAR(2), VAR(1))))))
+
+ASSERT_REDUCES_TO(APPL(APPL(S, K), K), I);
+ASSERT_REDUCES_TO(APPL(APPL(APPL(S, K), S), K), K);
+
+ASSERT_REDUCES_TO(APPL(APPL(APPL(S, K), VAR(5)), VAR(6)), VAR(6));
+ASSERT_REDUCES_TO(APPL(APPL(K, VAR(5)), VAR(6)), VAR(5));
+// } (The K, S combinators)
+
+// Church booleans {
+
+#define T LAM(LAM(VAR(2)))
+#define F LAM(LAM(VAR(1)))
+
+#define NOT LAM(APPL(APPL(VAR(1), F), T))
+#define AND LAM(LAM(APPL(APPL(VAR(2), VAR(1)), VAR(2))))
+#define OR LAM(LAM(APPL(APPL(VAR(2), VAR(2)), VAR(1))))
+#define XOR LAM(LAM(APPL(APPL(VAR(2), APPL(NOT, VAR(1))), VAR(1))))
+
+#define IF LAM(LAM(LAM(APPL(APPL(VAR(3), VAR(2)), VAR(1)))))
+
+ASSERT_REDUCES_TO(APPL(NOT, T), F);
+ASSERT_REDUCES_TO(APPL(NOT, F), T);
+ASSERT_REDUCES_TO(APPL(NOT, APPL(NOT, T)), T);
+ASSERT_REDUCES_TO(APPL(NOT, APPL(NOT, F)), F);
+
+ASSERT_REDUCES_TO(APPL(APPL(AND, T), T), T);
+ASSERT_REDUCES_TO(APPL(APPL(AND, T), F), F);
+ASSERT_REDUCES_TO(APPL(APPL(AND, F), T), F);
+ASSERT_REDUCES_TO(APPL(APPL(AND, F), F), F);
+
+ASSERT_REDUCES_TO(APPL(APPL(OR, T), T), T);
+ASSERT_REDUCES_TO(APPL(APPL(OR, T), F), T);
+ASSERT_REDUCES_TO(APPL(APPL(OR, F), T), T);
+ASSERT_REDUCES_TO(APPL(APPL(OR, F), F), F);
+
+ASSERT_REDUCES_TO(APPL(APPL(XOR, T), T), F);
+ASSERT_REDUCES_TO(APPL(APPL(XOR, T), F), T);
+ASSERT_REDUCES_TO(APPL(APPL(XOR, F), T), T);
+ASSERT_REDUCES_TO(APPL(APPL(XOR, F), F), F);
+
+ASSERT_REDUCES_TO(APPL(APPL(APPL(IF, T), VAR(5)), VAR(6)), VAR(5));
+ASSERT_REDUCES_TO(APPL(APPL(APPL(IF, F), VAR(5)), VAR(6)), VAR(6));
+// } (Church booleans)
+
+// Church numerals {
+
+#define ZERO LAM(LAM(VAR(1)))
+#define SUCC LAM(LAM(LAM(APPL(VAR(2), APPL(APPL(VAR(3), VAR(2)), VAR(1))))))
+
+#define ONE APPL(SUCC, ZERO)
+#define TWO APPL(SUCC, ONE)
+#define THREE APPL(SUCC, TWO)
+#define FOUR APPL(SUCC, THREE)
+
+#define ADD LAM(LAM(LAM(LAM(APPL(APPL(VAR(4), VAR(2)), APPL(APPL(VAR(3), VAR(2)), VAR(1)))))))
+#define MUL LAM(LAM(LAM(LAM(APPL(APPL(VAR(4), APPL(VAR(3), VAR(2))), VAR(1))))))
+
+ASSERT_REDUCES_TO(APPL(APPL(ADD, ZERO), ZERO), ZERO);
+ASSERT_REDUCES_TO(APPL(APPL(ADD, ZERO), ONE), ONE);
+ASSERT_REDUCES_TO(APPL(APPL(ADD, ONE), ZERO), ONE);
+ASSERT_REDUCES_TO(APPL(APPL(ADD, ONE), TWO), THREE);
+
+ASSERT_REDUCES_TO(APPL(APPL(MUL, ZERO), ZERO), ZERO);
+ASSERT_REDUCES_TO(APPL(APPL(MUL, ZERO), ONE), ZERO);
+ASSERT_REDUCES_TO(APPL(APPL(MUL, ONE), ZERO), ZERO);
+ASSERT_REDUCES_TO(APPL(APPL(MUL, TWO), TWO), FOUR);
+// } (Church numerals)
+
+// Church pairs {
+
+#define PAIR LAM(LAM(LAM(APPL(APPL(VAR(1), VAR(3)), VAR(2)))))
+#define FST LAM(APPL(VAR(1), T))
+#define SND LAM(APPL(VAR(1), F))
+
+ASSERT_REDUCES_TO(APPL(FST, APPL(APPL(PAIR, VAR(5)), VAR(6))), VAR(5));
+ASSERT_REDUCES_TO(APPL(SND, APPL(APPL(PAIR, VAR(5)), VAR(6))), VAR(6));
+// } (Church pairs)
+
+// Church lists {
+
+#define NIL F
+#define CONS PAIR
+#define IS_NIL LAM(APPL(APPL(VAR(1), LAM(LAM(LAM(F)))), T))
+
+#define LIST_1_2_3 APPL(APPL(CONS, VAR(1)), APPL(APPL(CONS, VAR(2)), APPL(APPL(CONS, VAR(3)), NIL)))
+
+ASSERT_REDUCES_TO(APPL(IS_NIL, NIL), T);
+ASSERT_REDUCES_TO(APPL(IS_NIL, LIST_1_2_3), F);
+// } (Church lists)
+
+// Recursion via self-application (or the Y combinator) is perfectly expressible, though when
+// executed, it exhausts the Metalang99 recursion engine limit.
+
+int main(void) {}
diff --git a/test/external/metalang99/examples/overload.c b/test/external/metalang99/examples/overload.c
new file mode 100644
index 0000000..8b5d6fd
--- /dev/null
+++ b/test/external/metalang99/examples/overload.c
@@ -0,0 +1,15 @@
+#include <metalang99.h>
+
+typedef struct {
+ double width, height;
+} Rect;
+
+#define Rect_new(...) ML99_OVERLOAD(Rect_new_, __VA_ARGS__)
+#define Rect_new_1(x) \
+ { x, x }
+#define Rect_new_2(x, y) \
+ { x, y }
+
+static Rect _7x8 = Rect_new(7, 8), _10x10 = Rect_new(10);
+
+int main(void) {}
diff --git a/test/external/metalang99/examples/rectangle.c b/test/external/metalang99/examples/rectangle.c
new file mode 100644
index 0000000..1ab2bbf
--- /dev/null
+++ b/test/external/metalang99/examples/rectangle.c
@@ -0,0 +1,25 @@
+// Computes the area of a rectangle.
+
+#include <metalang99.h>
+
+#define rect(width, height) ML99_tuple(width, height)
+#define rectWidth ML99_tupleGet(0)
+#define rectHeight ML99_tupleGet(1)
+
+#define rectArea(rect) ML99_mul(rectWidth(rect), rectHeight(rect))
+
+/*
+ * 15
+ * +------------------------------+
+ * | |
+ * | |
+ * | | 7
+ * | |
+ * | |
+ * +------------------------------+
+ */
+#define RECTANGLE rect(v(15), v(7))
+
+ML99_ASSERT_EQ(rectArea(RECTANGLE), v(15 * 7));
+
+int main(void) {}
diff --git a/test/external/metalang99/idioms.md b/test/external/metalang99/idioms.md
new file mode 100644
index 0000000..3ed23c8
--- /dev/null
+++ b/test/external/metalang99/idioms.md
@@ -0,0 +1,44 @@
+# Idioms
+
+_This document describes common idioms when using Metalang99, i.e., code patterns that have not been reified into abstractions yet._
+
+## Detecting a keyword followed by parentheses
+
+To detect something like `abracadabra(1, 2, 3)`, follow this simple pattern:
+
+```c
+#define DETECT_ABRACADABRA(x) ML99_IS_TUPLE(ML99_CAT(DETECT_ABRACADABRA_, x))
+#define DETECT_ABRACADABRA_abracadabra(...) ()
+
+// 1
+DETECT_ABRACADABRA(abracadabra(1, 2, 3))
+
+// 0
+DETECT_ABRACADABRA(blah)
+```
+
+## Extracting a value of a keyword followed by parentheses
+
+To get `1, 2, 3` from `abracadabra(1, 2, 3)`:
+
+```c
+#define EXTRACT_ABRACADABRA(x) ML99_CAT(EXTRACT_ABRACADABRA_, x)
+#define EXTRACT_ABRACADABRA_abracadabra(...) __VA_ARGS__
+
+// 1, 2, 3
+EXTRACT_ABRACADABRA(abracadabra(1, 2, 3))
+```
+
+## Interspersing a comma
+
+To intersperse a comma between one or more elements, put a comma before each element and pass them all to `ML99_variadicsTail`:
+
+```c
+#define ARRAY_SUBSCRIPTS(array, n) \
+ ML99_EVAL(ML99_variadicsTail(ML99_repeat(v(n), ML99_appl(v(GEN_SUBSCRIPT), v(array)))))
+#define GEN_SUBSCRIPT_IMPL(array, i) v(, (array)[i])
+#define GEN_SUBSCRIPT_ARITY 2
+
+// (animals)[0], (animals)[1], (animals)[2]
+ARRAY_SUBSCRIPTS(animals, 3)
+```
diff --git a/test/external/metalang99/include/metalang99.h b/test/external/metalang99/include/metalang99.h
new file mode 100644
index 0000000..714c525
--- /dev/null
+++ b/test/external/metalang99/include/metalang99.h
@@ -0,0 +1,33 @@
+#ifndef ML99_H
+#define ML99_H
+
+#if defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL
+#error Please, specify /Zc:preprocessor to enable a standard-compliant C99/C++11 preprocessor.
+#endif
+
+#include <metalang99/assert.h>
+#include <metalang99/bool.h>
+#include <metalang99/choice.h>
+#include <metalang99/either.h>
+#include <metalang99/gen.h>
+#include <metalang99/ident.h>
+#include <metalang99/lang.h>
+#include <metalang99/list.h>
+#include <metalang99/maybe.h>
+#include <metalang99/nat.h>
+#include <metalang99/seq.h>
+#include <metalang99/stmt.h>
+#include <metalang99/tuple.h>
+#include <metalang99/util.h>
+#include <metalang99/variadics.h>
+
+#define ML99_MAJOR 1
+#define ML99_MINOR 13
+#define ML99_PATCH 5
+
+#define ML99_VERSION_COMPATIBLE(x, y, z) \
+ (ML99_MAJOR == (x) && ((ML99_MINOR == (y) && ML99_PATCH >= (z)) || (ML99_MINOR > (y))))
+
+#define ML99_VERSION_EQ(x, y, z) (ML99_MAJOR == (x) && ML99_MINOR == (y) && ML99_PATCH == (z))
+
+#endif // ML99_H
diff --git a/test/external/metalang99/include/metalang99/assert.h b/test/external/metalang99/include/metalang99/assert.h
new file mode 100644
index 0000000..bbaa89b
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/assert.h
@@ -0,0 +1,134 @@
+/**
+ * @file
+ * Static assertions.
+ *
+ * For the sake of convenience, this header automatically includes `metalang99/bool.h`.
+ *
+ * @note [C99] Any of the following assertion macros must **not** appear on the same line number
+ * twice with itself as well as with any other Metalang99 assertion macro.
+ * @note [C11] The following assertion macros expand to `_Static_assert` and, therefore, can be used
+ * on the same line twice.
+ */
+
+#ifndef ML99_ASSERT_H
+#define ML99_ASSERT_H
+
+#include <metalang99/priv/compiler_specific.h>
+
+#include <metalang99/bool.h>
+#include <metalang99/lang.h>
+
+/**
+ * The same as #ML99_ASSERT but results in a Metalang99 term.
+ *
+ * It can be used inside other Metalang99-compliant macros, unlike #ML99_ASSERT, which uses
+ * #ML99_EVAL internally.
+ */
+#define ML99_assert(expr) ML99_call(ML99_assert, expr)
+
+/**
+ * Like #ML99_assert but compares @p lhs with @p rhs for equality (`==`).
+ */
+#define ML99_assertEq(lhs, rhs) ML99_call(ML99_assertEq, lhs, rhs)
+
+/**
+ * Asserts `ML99_EVAL(expr)` at compile-time.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/assert.h>
+ *
+ * ML99_ASSERT(v(123 == 123));
+ * @endcode
+ */
+#define ML99_ASSERT(expr) ML99_ASSERT_EQ(expr, ML99_true())
+
+/**
+ * Asserts `ML99_EVAL(lhs) == ML99_EVAL(rhs)` at compile-time.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/assert.h>
+ *
+ * ML99_ASSERT_EQ(v(123), v(123));
+ * @endcode
+ */
+#define ML99_ASSERT_EQ(lhs, rhs) ML99_ASSERT_UNEVAL((ML99_EVAL(lhs)) == (ML99_EVAL(rhs)))
+
+/**
+ * Asserts the C constant expression @p expr;
+ * [static_assert](https://en.cppreference.com/w/c/error/static_assert) in pure C99.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/assert.h>
+ *
+ * ML99_ASSERT_UNEVAL(123 == 123);
+ * @endcode
+ */
+#define ML99_ASSERT_UNEVAL(expr) ML99_PRIV_ASSERT_UNEVAL_INNER(expr)
+
+/**
+ * Asserts that `ML99_EVAL(expr)` is emptiness.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/assert.h>
+ *
+ * // Passes:
+ * ML99_ASSERT_EMPTY(v());
+ *
+ * // Fails:
+ * ML99_ASSERT_EMPTY(v(123));
+ * @endcode
+ */
+#define ML99_ASSERT_EMPTY(expr) ML99_ASSERT_EMPTY_UNEVAL(ML99_EVAL(expr))
+
+/**
+ * Asserts that @p expr is emptiness.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/assert.h>
+ *
+ * // Passes:
+ * ML99_ASSERT_EMPTY_UNEVAL();
+ *
+ * // Fails:
+ * ML99_ASSERT_EMPTY_UNEVAL(123);
+ * @endcode
+ */
+#define ML99_ASSERT_EMPTY_UNEVAL(expr) \
+ ML99_ASSERT_UNEVAL(ML99_PRIV_CAT(ML99_PRIV_ASSERT_EMPTY_, expr))
+
+#ifndef DOXYGEN_IGNORE
+
+#define ML99_assert_IMPL(expr) v(ML99_ASSERT_UNEVAL(expr))
+#define ML99_assertEq_IMPL(lhs, rhs) v(ML99_ASSERT_UNEVAL((lhs) == (rhs)))
+
+#ifdef ML99_PRIV_C11_STATIC_ASSERT_AVAILABLE
+#define ML99_PRIV_ASSERT_UNEVAL_INNER(expr) _Static_assert((expr), "Metalang99 assertion failed")
+#else
+// How to imitate static assertions in C99: <https://stackoverflow.com/a/3385694/13166656>.
+#define ML99_PRIV_ASSERT_UNEVAL_INNER(expr) \
+ static const char ML99_PRIV_CAT( \
+ ml99_assert_, \
+ __LINE__)[(expr) ? 1 : -1] ML99_PRIV_COMPILER_ATTR_UNUSED = {0}
+#endif
+
+#define ML99_PRIV_ASSERT_EMPTY_ 1
+
+// Arity specifiers {
+
+#define ML99_assert_ARITY 1
+#define ML99_assertEq_ARITY 2
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_ASSERT_H
diff --git a/test/external/metalang99/include/metalang99/bool.h b/test/external/metalang99/include/metalang99/bool.h
new file mode 100644
index 0000000..0213cb2
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/bool.h
@@ -0,0 +1,246 @@
+/**
+ * @file
+ * Boolean algebra.
+ */
+
+#ifndef ML99_BOOL_H
+#define ML99_BOOL_H
+
+#include <metalang99/priv/bool.h>
+#include <metalang99/priv/tuple.h>
+
+#include <metalang99/lang.h>
+
+/**
+ * Truth.
+ */
+#define ML99_true(...) ML99_callUneval(ML99_true, )
+
+/**
+ * Falsehood.
+ */
+#define ML99_false(...) ML99_callUneval(ML99_false, )
+
+/**
+ * Logical negation.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/bool.h>
+ *
+ * // 1
+ * ML99_not(v(0))
+ *
+ * // 0
+ * ML99_not(v(1))
+ * @endcode
+ */
+#define ML99_not(x) ML99_call(ML99_not, x)
+
+/**
+ * Logical conjunction.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/bool.h>
+ *
+ * // 0
+ * ML99_and(v(0), v(0))
+ *
+ * // 0
+ * ML99_and(v(0), v(1))
+ *
+ * // 0
+ * ML99_and(v(1), v(0))
+ *
+ * // 1
+ * ML99_and(v(1), v(1))
+ * @endcode
+ */
+#define ML99_and(x, y) ML99_call(ML99_and, x, y)
+
+/**
+ * Logical inclusive OR.
+ *
+ * # Examples
+ * @code
+ * #include <metalang99/bool.h>
+ *
+ * // 0
+ * ML99_or(v(0), v(0))
+ *
+ * // 1
+ * ML99_or(v(0), v(1))
+ *
+ * // 1
+ * ML99_or(v(1), v(0))
+ *
+ * // 1
+ * ML99_or(v(1), v(1))
+ * @endcode
+ */
+#define ML99_or(x, y) ML99_call(ML99_or, x, y)
+
+/**
+ * Logical exclusive OR.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/bool.h>
+ *
+ * // 0
+ * ML99_xor(v(0), v(0))
+ *
+ * // 1
+ * ML99_xor(v(0), v(1))
+ *
+ * // 1
+ * ML99_xor(v(1), v(0))
+ *
+ * // 0
+ * ML99_xor(v(1), v(1))
+ * @endcode
+ */
+#define ML99_xor(x, y) ML99_call(ML99_xor, x, y)
+
+/**
+ * Tests @p x and @p y for equality.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/bool.h>
+ *
+ * // 1
+ * ML99_boolEq(v(0), v(0))
+ *
+ * // 0
+ * ML99_boolEq(v(0), v(1))
+ *
+ * // 0
+ * ML99_boolEq(v(1), v(0))
+ *
+ * // 1
+ * ML99_boolEq(v(1), v(1))
+ * @endcode
+ */
+#define ML99_boolEq(x, y) ML99_call(ML99_boolEq, x, y)
+
+/**
+ * Matches @p x against the two cases: if it is 0 or 1.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/bool.h>
+ *
+ * #define MATCH_1_IMPL() v(Billie)
+ * #define MATCH_0_IMPL() v(Jean)
+ *
+ * // Billie
+ * ML99_boolMatch(v(1), v(MATCH_))
+ *
+ * // Jean
+ * ML99_boolMatch(v(0), v(MATCH_))
+ * @endcode
+ *
+ * @note This function calls @p f with #ML99_call, so no partial application occurs, and so
+ * arity specifiers are not needed.
+ */
+#define ML99_boolMatch(x, matcher) ML99_call(ML99_boolMatch, x, matcher)
+
+/**
+ * The same as #ML99_boolMatch but provides additional arguments to all branches.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/bool.h>
+ *
+ * #define MATCH_1_IMPL(x, y, z) v(Billie ~ x y z)
+ * #define MATCH_0_IMPL(x, y, z) v(Jean ~ x y z)
+ *
+ * // Billie ~ 1 2 3
+ * ML99_boolMatchWithArgs(v(1), v(MATCH_), v(1, 2, 3))
+ *
+ * // Jean ~ 1 2 3
+ * ML99_boolMatchWithArgs(v(0), v(MATCH_), v(1, 2, 3))
+ * @endcode
+ */
+#define ML99_boolMatchWithArgs(x, matcher, ...) \
+ ML99_call(ML99_boolMatchWithArgs, x, matcher, __VA_ARGS__)
+
+/**
+ * If @p cond is true, evaluates to @p x, otherwise @p y.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/bool.h>
+ *
+ * // 123
+ * ML99_if(v(1), v(123), v(18))
+ *
+ * // 18
+ * ML99_if(v(0), v(123), v(18))
+ * @endcode
+ */
+#define ML99_if(cond, x, y) ML99_call(ML99_if, cond, x, y)
+
+/**
+ * The plain version of #ML99_if.
+ *
+ * This macro can imitate lazy evaluation: `ML99_IF(<cond>, <term>, <another-term>)` will expand to
+ * one of the two terms, which can be evaluated further; if `<cond>` is 0, then `<term>` will
+ * **not** be evaluated, and the same with `<another-term>`.
+ *
+ * @note @p x and @p y can possibly expand to commas. It means that you can supply `ML99_TERMS(...)`
+ * as a branch, for example.
+ */
+#define ML99_IF(cond, x, y) ML99_PRIV_UNTUPLE(ML99_PRIV_IF(cond, (x), (y)))
+
+#define ML99_TRUE(...) 1
+#define ML99_FALSE(...) 0
+
+#define ML99_NOT(x) ML99_PRIV_NOT(x)
+#define ML99_AND(x, y) ML99_PRIV_AND(x, y)
+#define ML99_OR(x, y) ML99_PRIV_OR(x, y)
+#define ML99_XOR(x, y) ML99_PRIV_XOR(x, y)
+#define ML99_BOOL_EQ(x, y) ML99_PRIV_BOOL_EQ(x, y)
+
+#ifndef DOXYGEN_IGNORE
+
+#define ML99_true_IMPL(...) v(ML99_TRUE())
+#define ML99_false_IMPL(...) v(ML99_FALSE())
+
+#define ML99_not_IMPL(x) v(ML99_NOT(x))
+#define ML99_and_IMPL(x, y) v(ML99_AND(x, y))
+#define ML99_or_IMPL(x, y) v(ML99_OR(x, y))
+#define ML99_xor_IMPL(x, y) v(ML99_XOR(x, y))
+#define ML99_boolEq_IMPL(x, y) v(ML99_BOOL_EQ(x, y))
+
+#define ML99_boolMatch_IMPL(x, matcher) ML99_callUneval(matcher##x, )
+#define ML99_boolMatchWithArgs_IMPL(x, matcher, ...) ML99_callUneval(matcher##x, __VA_ARGS__)
+
+#define ML99_if_IMPL(cond, x, y) v(ML99_PRIV_IF(cond, x, y))
+
+// Arity specifiers {
+
+#define ML99_true_ARITY 1
+#define ML99_false_ARITY 1
+#define ML99_not_ARITY 1
+#define ML99_and_ARITY 2
+#define ML99_or_ARITY 2
+#define ML99_xor_ARITY 2
+#define ML99_boolEq_ARITY 2
+#define ML99_boolMatch_ARITY 2
+#define ML99_boolMatchWithArgs_ARITY 3
+#define ML99_if_ARITY 3
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_BOOL_H
diff --git a/test/external/metalang99/include/metalang99/choice.h b/test/external/metalang99/include/metalang99/choice.h
new file mode 100644
index 0000000..fcdcf07
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/choice.h
@@ -0,0 +1,129 @@
+/**
+ * @file
+ * Choice types: `(tag, ...)`.
+ *
+ * A choice type, also known as [tagged union], is represented as `(tag, ...)`, where `tag` is the
+ * type of a value and `...` is the value. Perhaps the most common example of a choice type is a
+ * binary tree:
+ *
+ * [[examples/binary_tree.c](https://github.com/hirrolot/metalang99/blob/master/examples/binary_tree.c)]
+ * @include binary_tree.c
+ *
+ * [tagged union]: https://en.wikipedia.org/wiki/Tagged_union
+ */
+
+#ifndef ML99_CHOICE_H
+#define ML99_CHOICE_H
+
+#include <metalang99/priv/util.h>
+
+#include <metalang99/lang.h>
+
+/**
+ * Constructs an instance of a choice type.
+ *
+ * # Examples
+ *
+ * See
+ * [examples/binary_tree.c](https://github.com/hirrolot/metalang99/blob/master/examples/binary_tree.c).
+ *
+ * @note Specify `~` if you do not want to supply data; then, to match it, write a `_` parameter to
+ * ignore.
+ */
+#define ML99_choice(tag, ...) ML99_call(ML99_choice, tag, __VA_ARGS__)
+
+/**
+ * Evaluates to the tag of @p choice.
+ *
+ * This macro is essentially the same as `ML99_tupleGet(0)`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/choice.h>
+ *
+ * // foo
+ * ML99_choiceTag(ML99_choice(v(foo), v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_choiceTag(choice) ML99_call(ML99_choiceTag, choice)
+
+/**
+ * Evaluates to the data of @p choice.
+ *
+ * This macro is essentially the same as #ML99_tupleTail.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/choice.h>
+ *
+ * // 1, 2, 3
+ * ML99_choiceData(ML99_choice(v(foo), v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_choiceData(choice) ML99_call(ML99_choiceData, choice)
+
+/**
+ * Matches the instance @p choice of a choice type.
+ *
+ * This macro results in `ML99_call(ML99_cat(matcher, ML99_choiceTag(choice)), <choice data>)`.
+ *
+ * # Examples
+ *
+ * See
+ * [examples/binary_tree.c](https://github.com/hirrolot/metalang99/blob/master/examples/binary_tree.c).
+ */
+#define ML99_match(choice, matcher) ML99_call(ML99_match, choice, matcher)
+
+/**
+ * The same as #ML99_match but supplies additional arguments to all branches.
+ *
+ * This macro results in `ML99_call(ML99_cat(matcher, ML99_choiceTag(choice)), <choice data>,
+ * args...)`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/choice.h>
+ *
+ * #define MATCH_A_IMPL(x, y, z) v(x ~ y ~ z)
+ *
+ * // 123 ~ 456 ~ 789
+ * ML99_matchWithArgs(ML99_choice(v(A), v(123)), v(MATCH_), v(456, 789))
+ * @endcode
+ */
+#define ML99_matchWithArgs(choice, matcher, ...) \
+ ML99_call(ML99_matchWithArgs, choice, matcher, __VA_ARGS__)
+
+#define ML99_CHOICE(tag, ...) (tag, __VA_ARGS__)
+#define ML99_CHOICE_TAG(choice) ML99_PRIV_HEAD_AUX choice
+#define ML99_CHOICE_DATA(choice) ML99_PRIV_TAIL_AUX choice
+
+#ifndef DOXYGEN_IGNORE
+
+#define ML99_choice_IMPL(tag, ...) v(ML99_CHOICE(tag, __VA_ARGS__))
+#define ML99_choiceTag_IMPL(choice) v(ML99_CHOICE_TAG(choice))
+#define ML99_choiceData_IMPL(choice) v(ML99_CHOICE_DATA(choice))
+
+#define ML99_match_IMPL(choice, matcher) \
+ ML99_callUneval(ML99_PRIV_CAT(matcher, ML99_PRIV_HEAD_AUX choice), ML99_PRIV_TAIL_AUX choice)
+
+#define ML99_matchWithArgs_IMPL(choice, matcher, ...) \
+ ML99_callUneval( \
+ ML99_PRIV_CAT(matcher, ML99_PRIV_HEAD_AUX choice), \
+ ML99_PRIV_TAIL_AUX choice, \
+ __VA_ARGS__)
+
+// Arity specifiers {
+
+#define ML99_choice_ARITY 2
+#define ML99_choiceTag_ARITY 1
+#define ML99_choiceData_ARITY 1
+#define ML99_match_ARITY 2
+#define ML99_matchWithArgs_ARITY 3
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_CHOICE_H
diff --git a/test/external/metalang99/include/metalang99/control.h b/test/external/metalang99/include/metalang99/control.h
new file mode 100644
index 0000000..13ed33b
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/control.h
@@ -0,0 +1,13 @@
+/**
+ * @file
+ * This module is deprecated and exists only for backwards compatibility.
+ */
+
+#ifndef ML99_CONTROL_H
+#define ML99_CONTROL_H
+
+#include <metalang99/bool.h> // ML99_if, ML99_IF
+#include <metalang99/gen.h> // ML99_times, ML99_repeat
+#include <metalang99/variadics.h> // ML99_OVERLOAD
+
+#endif // ML99_CONTROL_H
diff --git a/test/external/metalang99/include/metalang99/either.h b/test/external/metalang99/include/metalang99/either.h
new file mode 100644
index 0000000..c3b7732
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/either.h
@@ -0,0 +1,170 @@
+/**
+ * @file
+ * A choice type with two cases.
+ */
+
+#ifndef ML99_EITHER_H
+#define ML99_EITHER_H
+
+#include <metalang99/priv/util.h>
+
+#include <metalang99/bool.h>
+#include <metalang99/choice.h>
+#include <metalang99/ident.h>
+
+/**
+ * The left value @p x.
+ */
+#define ML99_left(x) ML99_call(ML99_left, x)
+
+/**
+ * The right value @p x.
+ */
+#define ML99_right(x) ML99_call(ML99_right, x)
+
+/**
+ * `ML99_true()` if @p either contains a left value, otherwise `ML99_false()`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/either.h>
+ *
+ * // 1
+ * ML99_isLeft(ML99_left(v(123)))
+ *
+ * // 0
+ * ML99_isLeft(ML99_right(v(123)))
+ * @endcode
+ */
+#define ML99_isLeft(either) ML99_call(ML99_isLeft, either)
+
+/**
+ * The inverse of #ML99_isLeft.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/either.h>
+ *
+ * // 1
+ * ML99_isRight(ML99_right(v(123)))
+ *
+ * // 0
+ * ML99_isRight(ML99_left(v(123)))
+ * @endcode
+ */
+#define ML99_isRight(either) ML99_call(ML99_isRight, either)
+
+/**
+ * Tests @p either and @p other for equality.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/either.h>
+ * #include <metalang99/nat.h>
+ *
+ * // 1
+ * ML99_eitherEq(v(ML99_natEq), ML99_left(v(123)), ML99_left(v(123)))
+ *
+ * // 0
+ * ML99_eitherEq(v(ML99_natEq), ML99_right(v(123)), ML99_left(v(8)))
+ *
+ * // 0
+ * ML99_eitherEq(v(ML99_natEq), ML99_right(v(123)), ML99_left(v(123)))
+ * @endcode
+ */
+#define ML99_eitherEq(cmp, either, other) ML99_call(ML99_eitherEq, cmp, either, other)
+
+/**
+ * Returns the left value on `ML99_left(x)` or emits a fatal error on `ML99_right(y)`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/either.h>
+ *
+ * // 123
+ * ML99_unwrapLeft(ML99_left(v(123)))
+ *
+ * // Emits a fatal error.
+ * ML99_unwrapLeft(ML99_right(v(123)))
+ * @endcode
+ */
+#define ML99_unwrapLeft(either) ML99_call(ML99_unwrapLeft, either)
+
+/**
+ * The inverse of #ML99_unwrapLeft.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/either.h>
+ *
+ * // 123
+ * ML99_unwrapRight(ML99_right(v(123)))
+ *
+ * // Emits a fatal error.
+ * ML99_unwrapRight(ML99_left(v(123)))
+ * @endcode
+ */
+#define ML99_unwrapRight(either) ML99_call(ML99_unwrapRight, either)
+
+#define ML99_LEFT(x) ML99_CHOICE(left, x)
+#define ML99_RIGHT(x) ML99_CHOICE(right, x)
+#define ML99_IS_LEFT(either) ML99_PRIV_IS_LEFT(either)
+#define ML99_IS_RIGHT(either) ML99_NOT(ML99_IS_LEFT(either))
+
+#ifndef DOXYGEN_IGNORE
+
+#define ML99_left_IMPL(x) v(ML99_LEFT(x))
+#define ML99_right_IMPL(x) v(ML99_RIGHT(x))
+
+#define ML99_isLeft_IMPL(either) v(ML99_IS_LEFT(either))
+#define ML99_isRight_IMPL(either) v(ML99_IS_RIGHT(either))
+
+// ML99_eitherEq_IMPL {
+
+#define ML99_eitherEq_IMPL(cmp, either, other) \
+ ML99_matchWithArgs_IMPL(either, ML99_PRIV_eitherEq_, cmp, other)
+
+#define ML99_PRIV_eitherEq_left_IMPL(x, cmp, other) \
+ ML99_matchWithArgs_IMPL(other, ML99_PRIV_eitherEq_left_, cmp, x)
+#define ML99_PRIV_eitherEq_right_IMPL(x, cmp, other) \
+ ML99_matchWithArgs_IMPL(other, ML99_PRIV_eitherEq_right_, cmp, x)
+
+#define ML99_PRIV_eitherEq_left_left_IMPL(y, cmp, x) ML99_appl2_IMPL(cmp, x, y)
+#define ML99_PRIV_eitherEq_left_right_IMPL ML99_false_IMPL
+
+#define ML99_PRIV_eitherEq_right_left_IMPL ML99_false_IMPL
+#define ML99_PRIV_eitherEq_right_right_IMPL(y, cmp, x) ML99_appl2_IMPL(cmp, x, y)
+// } (ML99_eitherEq_IMPL)
+
+#define ML99_unwrapLeft_IMPL(either) ML99_match_IMPL(either, ML99_PRIV_unwrapLeft_)
+#define ML99_PRIV_unwrapLeft_left_IMPL(x) v(x)
+#define ML99_PRIV_unwrapLeft_right_IMPL(_x) \
+ ML99_fatal(ML99_unwrapLeft, expected ML99_left but found ML99_right)
+
+#define ML99_unwrapRight_IMPL(either) ML99_match_IMPL(either, ML99_PRIV_unwrapRight_)
+#define ML99_PRIV_unwrapRight_left_IMPL(_x) \
+ ML99_fatal(ML99_unwrapRight, expected ML99_right but found ML99_left)
+#define ML99_PRIV_unwrapRight_right_IMPL(x) v(x)
+
+#define ML99_PRIV_IS_LEFT(either) ML99_DETECT_IDENT(ML99_PRIV_IS_LEFT_, ML99_CHOICE_TAG(either))
+#define ML99_PRIV_IS_LEFT_left ()
+
+// Arity specifiers {
+
+#define ML99_left_ARITY 1
+#define ML99_right_ARITY 1
+#define ML99_isLeft_ARITY 1
+#define ML99_isRight_ARITY 1
+#define ML99_eitherEq_ARITY 3
+#define ML99_unwrapLeft_ARITY 1
+#define ML99_unwrapRight_ARITY 1
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_EITHER_H
diff --git a/test/external/metalang99/include/metalang99/eval/acc.h b/test/external/metalang99/include/metalang99/eval/acc.h
new file mode 100644
index 0000000..cd284f2
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/eval/acc.h
@@ -0,0 +1,14 @@
+#ifndef ML99_EVAL_ACC_H
+#define ML99_EVAL_ACC_H
+
+#include <metalang99/priv/util.h>
+
+#define ML99_PRIV_EVAL_ACC (, )
+#define ML99_PRIV_EVAL_ACC_COMMA_SEP ()
+
+#define ML99_PRIV_EVAL_0fspace(acc, ...) (ML99_PRIV_EXPAND acc __VA_ARGS__)
+#define ML99_PRIV_EVAL_0fcomma(acc, ...) (ML99_PRIV_EXPAND acc, __VA_ARGS__)
+
+#define ML99_PRIV_EVAL_ACC_UNWRAP(_emptiness, ...) __VA_ARGS__
+
+#endif // ML99_EVAL_ACC_H
diff --git a/test/external/metalang99/include/metalang99/eval/eval.h b/test/external/metalang99/include/metalang99/eval/eval.h
new file mode 100644
index 0000000..394a1e2
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/eval/eval.h
@@ -0,0 +1,130 @@
+#ifndef ML99_EVAL_EVAL_H
+#define ML99_EVAL_EVAL_H
+
+// Explanation is in the spec: <https://github.com/hirrolot/metalang99/blob/master/spec/spec.pdf>.
+
+#include <metalang99/priv/compiler_specific.h>
+#include <metalang99/priv/util.h>
+
+#include <metalang99/eval/acc.h>
+#include <metalang99/eval/rec.h>
+#include <metalang99/eval/syntax_checker.h>
+
+#define ML99_PRIV_EVAL(...) \
+ ML99_PRIV_REC_UNROLL(ML99_PRIV_EVAL_MATCH( \
+ ML99_PRIV_REC_STOP, \
+ (~), \
+ 0fspace, \
+ ML99_PRIV_EVAL_ACC, \
+ __VA_ARGS__, \
+ (0end, ~), \
+ ~))
+
+// Recursion hooks {
+
+#define ML99_PRIV_EVAL_MATCH_HOOK() ML99_PRIV_EVAL_MATCH
+#define ML99_PRIV_EVAL_0v_K_HOOK() ML99_PRIV_EVAL_0v_K
+#define ML99_PRIV_EVAL_0args_K_HOOK() ML99_PRIV_EVAL_0args_K
+#define ML99_PRIV_EVAL_0op_K_HOOK() ML99_PRIV_EVAL_0op_K
+#define ML99_PRIV_EVAL_0callUneval_K_HOOK() ML99_PRIV_EVAL_0callUneval_K
+// } (Recursion hooks)
+
+#define ML99_PRIV_EVAL_MATCH(k, k_cx, folder, acc, head, ...) \
+ ML99_PRIV_CHECK_TERM(head, ML99_PRIV_TERM_MATCH) \
+ (head)(k, k_cx, folder, acc, (__VA_ARGS__), ML99_PRIV_TERM_DATA head)
+
+#define ML99_PRIV_TERM_MATCH(term) ML99_PRIV_CAT(ML99_PRIV_EVAL_, ML99_PRIV_TERM_KIND term)
+#define ML99_PRIV_TERM_KIND(kind, ...) kind
+#define ML99_PRIV_TERM_DATA(_kind, ...) __VA_ARGS__
+
+// Reduction rules {
+
+#define ML99_PRIV_EVAL_0v ML99_PRIV_REC_CONTINUE(ML99_PRIV_EVAL_0v_K)
+#define ML99_PRIV_EVAL_0args ML99_PRIV_REC_CONTINUE(ML99_PRIV_EVAL_0args_K)
+#define ML99_PRIV_EVAL_0op ML99_PRIV_REC_CONTINUE(ML99_PRIV_EVAL_0op_K)
+#define ML99_PRIV_EVAL_0callUneval ML99_PRIV_REC_CONTINUE(ML99_PRIV_EVAL_0callUneval_K)
+
+#define ML99_PRIV_EVAL_0fatal(...) ML99_PRIV_EVAL_0fatal_AUX(__VA_ARGS__)
+#define ML99_PRIV_EVAL_0fatal_AUX(_k, _k_cx, _folder, _acc, _tail, f, message) \
+ ML99_PRIV_REC_CONTINUE(ML99_PRIV_REC_STOP)((~), ML99_PRIV_FATAL_ERROR(f, message))
+
+#ifdef ML99_PRIV_EMIT_ERROR
+#define ML99_PRIV_FATAL_ERROR(f, message) ML99_PRIV_EMIT_ERROR(#f ": " message);
+#else
+// clang-format off
+#define ML99_PRIV_FATAL_ERROR(f, message) !"Metalang99 error" (f): message
+// clang-format on
+#endif
+
+#define ML99_PRIV_EVAL_0abort(_k, k_cx, folder, acc, _tail, ...) \
+ ML99_PRIV_REC_CONTINUE(ML99_PRIV_EVAL_MATCH) \
+ (ML99_PRIV_REC_STOP, (~), 0fspace, ML99_PRIV_EVAL_ACC, __VA_ARGS__, (0end, ~), ~)
+
+#define ML99_PRIV_EVAL_0end(k, k_cx, _folder, acc, _tail, _) \
+ ML99_PRIV_REC_CONTINUE(k) \
+ (ML99_PRIV_EXPAND k_cx, ML99_PRIV_EVAL_ACC_UNWRAP acc)
+// } (Reduction rules)
+
+// Continuations {
+
+#define ML99_PRIV_EVAL_0v_K(k, k_cx, folder, acc, tail, ...) \
+ ML99_PRIV_MACHINE_REDUCE( \
+ k, \
+ k_cx, \
+ folder, \
+ ML99_PRIV_EVAL_##folder(acc, __VA_ARGS__), \
+ ML99_PRIV_EXPAND tail)
+
+#define ML99_PRIV_EVAL_0args_K(k, k_cx, folder, acc, tail, op, ...) \
+ ML99_PRIV_MACHINE_REDUCE( \
+ ML99_PRIV_EVAL_0callUneval_K, \
+ (k, k_cx, folder, acc, tail, op), \
+ 0fcomma, \
+ ML99_PRIV_EVAL_ACC_COMMA_SEP, \
+ __VA_ARGS__, \
+ (0end, ~), \
+ ~)
+
+#define ML99_PRIV_EVAL_0op_K(k, k_cx, folder, acc, tail, op, ...) \
+ ML99_PRIV_MACHINE_REDUCE( \
+ ML99_PRIV_EVAL_0callUneval_K, \
+ (k, k_cx, folder, acc, tail), \
+ 0fcomma, \
+ ML99_PRIV_EVAL_ACC_COMMA_SEP, \
+ op, \
+ __VA_ARGS__, \
+ (0end, ~), \
+ ~)
+
+/*
+ * In this subroutine, we employ the following optimization:
+ *
+ * - If `evaluated_op` expands to many terms, we first evaluate these terms and accumulate them
+ * (`ML99_PRIV_EVAL_0callUneval_K_1`).
+ * - Otherwise, we just paste a single term with the rest of the tail
+ * (`ML99_PRIV_EVAL_0callUneval_K_0`).
+ */
+#define ML99_PRIV_EVAL_0callUneval_K(k, k_cx, folder, acc, tail, evaluated_op, ...) \
+ ML99_PRIV_EVAL_0callUneval_K_AUX(k, k_cx, folder, acc, tail, evaluated_op##_IMPL(__VA_ARGS__))
+
+#define ML99_PRIV_EVAL_0callUneval_K_AUX(k, k_cx, folder, acc, tail, ...) \
+ ML99_PRIV_CAT(ML99_PRIV_EVAL_0callUneval_K_, ML99_PRIV_CONTAINS_COMMA(__VA_ARGS__)) \
+ (k, k_cx, folder, acc, tail, __VA_ARGS__)
+
+#define ML99_PRIV_EVAL_0callUneval_K_0(k, k_cx, folder, acc, tail, body) \
+ ML99_PRIV_MACHINE_REDUCE(k, k_cx, folder, acc, body, ML99_PRIV_EXPAND tail)
+
+#define ML99_PRIV_EVAL_0callUneval_K_1(k, k_cx, folder, acc, tail, ...) \
+ ML99_PRIV_MACHINE_REDUCE( \
+ ML99_PRIV_EVAL_0v_K, \
+ (k, k_cx, folder, acc, tail), \
+ 0fspace, \
+ ML99_PRIV_EVAL_ACC, \
+ __VA_ARGS__, \
+ (0end, ~), \
+ ~)
+
+#define ML99_PRIV_MACHINE_REDUCE(...) ML99_PRIV_EVAL_MATCH(__VA_ARGS__)
+// } (Continuations)
+
+#endif // ML99_EVAL_EVAL_H
diff --git a/test/external/metalang99/include/metalang99/eval/rec.h b/test/external/metalang99/include/metalang99/eval/rec.h
new file mode 100644
index 0000000..aab238a
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/eval/rec.h
@@ -0,0 +1,1098 @@
+/*
+ * This recursion engine takes its roots from map-macro [1] and Cloak [2], with a few improvements:
+ *
+ * - It can do many more expansions (roughly 1024 * 16 or 2^14).
+ *
+ * - The expansion chain is linear: `ML99_PRIV_REC_0` invokes `ML99_PRIV_REC_1`, `ML99_PRIV_REC_1`
+ * invokes `ML99_PRIV_REC_2`, and so on.
+ *
+ * - If a given metaprogram does not require more expansions, then it will stop expanding. I.e.,
+ * perform only as many expansions as needed. This is controlled by `ML99_PRIV_REC_NEXT`: if
+ * `choice` is `0stop`, then just terminate the expansion chain.
+ *
+ * - The last expander `ML99_PRIV_REC_1023` really results in a deferred `ML99_PRIV_REC_0`, not to
+ * make it painted blue. Then, in `ML99_PRIV_REC_UNROLL_AUX`, this `ML99_PRIV_REC_0` is expanded
+ * once again 16 times.
+ *
+ * - It requires recursive macros to be written in CPS, continuation-passing style [3]. This is
+ * controlled by `ML99_PRIV_REC_CONTINUE`: the `k` parameter stands for "continuation". `k` must
+ * eventually expand to yet another `ML99_PRIV_REC_CONTINUE`. Also, there is a special continuation
+ * called `ML99_PRIV_REC_STOP` -- it terminates the engine.
+ *
+ * The minimal usage example is located at `tests/eval/rec.c`.
+ *
+ * [1] https://github.com/swansontec/map-macro
+ * [2] https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms#recursion
+ * [3] https://en.wikipedia.org/wiki/Continuation-passing_style
+ */
+
+#ifndef ML99_EVAL_REC_H
+#define ML99_EVAL_REC_H
+
+#define ML99_PRIV_REC_CONTINUE(k) 0continue, ML99_PRIV_REC_DEFER(k##_HOOK)()
+#define ML99_PRIV_REC_STOP(_k_cx, ...) 0stop, __VA_ARGS__
+#define ML99_PRIV_REC_STOP_HOOK() ML99_PRIV_REC_STOP
+
+#define ML99_PRIV_REC_DEFER(op) op ML99_PRIV_REC_EMPTY
+#define ML99_PRIV_REC_EMPTY
+#define ML99_PRIV_REC_EXPAND(...) __VA_ARGS__
+
+#define ML99_PRIV_REC_NEXT(next_lvl, choice) ML99_PRIV_REC_NEXT_##choice(next_lvl)
+#define ML99_PRIV_REC_NEXT_0continue(next_lvl) ML99_PRIV_REC_##next_lvl
+#define ML99_PRIV_REC_NEXT_0stop(_next_lvl) ML99_PRIV_REC_HALT
+
+#define ML99_PRIV_REC_HALT(...) __VA_ARGS__
+
+#define ML99_PRIV_REC_UNROLL(...) ML99_PRIV_REC_UNROLL_AUX(__VA_ARGS__)
+
+// clang-format off
+#define ML99_PRIV_REC_UNROLL_AUX(choice, ...) \
+ /* Approximately 1024 * 16 reduction steps. */ \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_EXPAND( \
+ ML99_PRIV_REC_NEXT(0, choice)(__VA_ARGS__) \
+ ))))))))))))))))
+// clang-format on
+
+#define ML99_PRIV_REC_0(choice, ...) ML99_PRIV_REC_NEXT(1, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1(choice, ...) ML99_PRIV_REC_NEXT(2, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_2(choice, ...) ML99_PRIV_REC_NEXT(3, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_3(choice, ...) ML99_PRIV_REC_NEXT(4, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_4(choice, ...) ML99_PRIV_REC_NEXT(5, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_5(choice, ...) ML99_PRIV_REC_NEXT(6, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_6(choice, ...) ML99_PRIV_REC_NEXT(7, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_7(choice, ...) ML99_PRIV_REC_NEXT(8, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_8(choice, ...) ML99_PRIV_REC_NEXT(9, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_9(choice, ...) ML99_PRIV_REC_NEXT(10, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_10(choice, ...) ML99_PRIV_REC_NEXT(11, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_11(choice, ...) ML99_PRIV_REC_NEXT(12, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_12(choice, ...) ML99_PRIV_REC_NEXT(13, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_13(choice, ...) ML99_PRIV_REC_NEXT(14, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_14(choice, ...) ML99_PRIV_REC_NEXT(15, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_15(choice, ...) ML99_PRIV_REC_NEXT(16, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_16(choice, ...) ML99_PRIV_REC_NEXT(17, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_17(choice, ...) ML99_PRIV_REC_NEXT(18, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_18(choice, ...) ML99_PRIV_REC_NEXT(19, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_19(choice, ...) ML99_PRIV_REC_NEXT(20, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_20(choice, ...) ML99_PRIV_REC_NEXT(21, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_21(choice, ...) ML99_PRIV_REC_NEXT(22, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_22(choice, ...) ML99_PRIV_REC_NEXT(23, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_23(choice, ...) ML99_PRIV_REC_NEXT(24, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_24(choice, ...) ML99_PRIV_REC_NEXT(25, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_25(choice, ...) ML99_PRIV_REC_NEXT(26, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_26(choice, ...) ML99_PRIV_REC_NEXT(27, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_27(choice, ...) ML99_PRIV_REC_NEXT(28, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_28(choice, ...) ML99_PRIV_REC_NEXT(29, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_29(choice, ...) ML99_PRIV_REC_NEXT(30, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_30(choice, ...) ML99_PRIV_REC_NEXT(31, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_31(choice, ...) ML99_PRIV_REC_NEXT(32, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_32(choice, ...) ML99_PRIV_REC_NEXT(33, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_33(choice, ...) ML99_PRIV_REC_NEXT(34, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_34(choice, ...) ML99_PRIV_REC_NEXT(35, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_35(choice, ...) ML99_PRIV_REC_NEXT(36, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_36(choice, ...) ML99_PRIV_REC_NEXT(37, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_37(choice, ...) ML99_PRIV_REC_NEXT(38, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_38(choice, ...) ML99_PRIV_REC_NEXT(39, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_39(choice, ...) ML99_PRIV_REC_NEXT(40, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_40(choice, ...) ML99_PRIV_REC_NEXT(41, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_41(choice, ...) ML99_PRIV_REC_NEXT(42, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_42(choice, ...) ML99_PRIV_REC_NEXT(43, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_43(choice, ...) ML99_PRIV_REC_NEXT(44, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_44(choice, ...) ML99_PRIV_REC_NEXT(45, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_45(choice, ...) ML99_PRIV_REC_NEXT(46, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_46(choice, ...) ML99_PRIV_REC_NEXT(47, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_47(choice, ...) ML99_PRIV_REC_NEXT(48, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_48(choice, ...) ML99_PRIV_REC_NEXT(49, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_49(choice, ...) ML99_PRIV_REC_NEXT(50, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_50(choice, ...) ML99_PRIV_REC_NEXT(51, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_51(choice, ...) ML99_PRIV_REC_NEXT(52, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_52(choice, ...) ML99_PRIV_REC_NEXT(53, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_53(choice, ...) ML99_PRIV_REC_NEXT(54, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_54(choice, ...) ML99_PRIV_REC_NEXT(55, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_55(choice, ...) ML99_PRIV_REC_NEXT(56, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_56(choice, ...) ML99_PRIV_REC_NEXT(57, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_57(choice, ...) ML99_PRIV_REC_NEXT(58, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_58(choice, ...) ML99_PRIV_REC_NEXT(59, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_59(choice, ...) ML99_PRIV_REC_NEXT(60, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_60(choice, ...) ML99_PRIV_REC_NEXT(61, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_61(choice, ...) ML99_PRIV_REC_NEXT(62, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_62(choice, ...) ML99_PRIV_REC_NEXT(63, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_63(choice, ...) ML99_PRIV_REC_NEXT(64, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_64(choice, ...) ML99_PRIV_REC_NEXT(65, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_65(choice, ...) ML99_PRIV_REC_NEXT(66, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_66(choice, ...) ML99_PRIV_REC_NEXT(67, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_67(choice, ...) ML99_PRIV_REC_NEXT(68, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_68(choice, ...) ML99_PRIV_REC_NEXT(69, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_69(choice, ...) ML99_PRIV_REC_NEXT(70, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_70(choice, ...) ML99_PRIV_REC_NEXT(71, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_71(choice, ...) ML99_PRIV_REC_NEXT(72, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_72(choice, ...) ML99_PRIV_REC_NEXT(73, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_73(choice, ...) ML99_PRIV_REC_NEXT(74, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_74(choice, ...) ML99_PRIV_REC_NEXT(75, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_75(choice, ...) ML99_PRIV_REC_NEXT(76, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_76(choice, ...) ML99_PRIV_REC_NEXT(77, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_77(choice, ...) ML99_PRIV_REC_NEXT(78, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_78(choice, ...) ML99_PRIV_REC_NEXT(79, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_79(choice, ...) ML99_PRIV_REC_NEXT(80, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_80(choice, ...) ML99_PRIV_REC_NEXT(81, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_81(choice, ...) ML99_PRIV_REC_NEXT(82, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_82(choice, ...) ML99_PRIV_REC_NEXT(83, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_83(choice, ...) ML99_PRIV_REC_NEXT(84, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_84(choice, ...) ML99_PRIV_REC_NEXT(85, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_85(choice, ...) ML99_PRIV_REC_NEXT(86, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_86(choice, ...) ML99_PRIV_REC_NEXT(87, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_87(choice, ...) ML99_PRIV_REC_NEXT(88, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_88(choice, ...) ML99_PRIV_REC_NEXT(89, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_89(choice, ...) ML99_PRIV_REC_NEXT(90, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_90(choice, ...) ML99_PRIV_REC_NEXT(91, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_91(choice, ...) ML99_PRIV_REC_NEXT(92, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_92(choice, ...) ML99_PRIV_REC_NEXT(93, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_93(choice, ...) ML99_PRIV_REC_NEXT(94, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_94(choice, ...) ML99_PRIV_REC_NEXT(95, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_95(choice, ...) ML99_PRIV_REC_NEXT(96, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_96(choice, ...) ML99_PRIV_REC_NEXT(97, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_97(choice, ...) ML99_PRIV_REC_NEXT(98, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_98(choice, ...) ML99_PRIV_REC_NEXT(99, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_99(choice, ...) ML99_PRIV_REC_NEXT(100, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_100(choice, ...) ML99_PRIV_REC_NEXT(101, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_101(choice, ...) ML99_PRIV_REC_NEXT(102, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_102(choice, ...) ML99_PRIV_REC_NEXT(103, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_103(choice, ...) ML99_PRIV_REC_NEXT(104, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_104(choice, ...) ML99_PRIV_REC_NEXT(105, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_105(choice, ...) ML99_PRIV_REC_NEXT(106, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_106(choice, ...) ML99_PRIV_REC_NEXT(107, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_107(choice, ...) ML99_PRIV_REC_NEXT(108, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_108(choice, ...) ML99_PRIV_REC_NEXT(109, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_109(choice, ...) ML99_PRIV_REC_NEXT(110, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_110(choice, ...) ML99_PRIV_REC_NEXT(111, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_111(choice, ...) ML99_PRIV_REC_NEXT(112, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_112(choice, ...) ML99_PRIV_REC_NEXT(113, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_113(choice, ...) ML99_PRIV_REC_NEXT(114, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_114(choice, ...) ML99_PRIV_REC_NEXT(115, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_115(choice, ...) ML99_PRIV_REC_NEXT(116, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_116(choice, ...) ML99_PRIV_REC_NEXT(117, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_117(choice, ...) ML99_PRIV_REC_NEXT(118, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_118(choice, ...) ML99_PRIV_REC_NEXT(119, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_119(choice, ...) ML99_PRIV_REC_NEXT(120, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_120(choice, ...) ML99_PRIV_REC_NEXT(121, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_121(choice, ...) ML99_PRIV_REC_NEXT(122, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_122(choice, ...) ML99_PRIV_REC_NEXT(123, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_123(choice, ...) ML99_PRIV_REC_NEXT(124, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_124(choice, ...) ML99_PRIV_REC_NEXT(125, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_125(choice, ...) ML99_PRIV_REC_NEXT(126, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_126(choice, ...) ML99_PRIV_REC_NEXT(127, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_127(choice, ...) ML99_PRIV_REC_NEXT(128, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_128(choice, ...) ML99_PRIV_REC_NEXT(129, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_129(choice, ...) ML99_PRIV_REC_NEXT(130, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_130(choice, ...) ML99_PRIV_REC_NEXT(131, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_131(choice, ...) ML99_PRIV_REC_NEXT(132, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_132(choice, ...) ML99_PRIV_REC_NEXT(133, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_133(choice, ...) ML99_PRIV_REC_NEXT(134, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_134(choice, ...) ML99_PRIV_REC_NEXT(135, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_135(choice, ...) ML99_PRIV_REC_NEXT(136, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_136(choice, ...) ML99_PRIV_REC_NEXT(137, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_137(choice, ...) ML99_PRIV_REC_NEXT(138, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_138(choice, ...) ML99_PRIV_REC_NEXT(139, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_139(choice, ...) ML99_PRIV_REC_NEXT(140, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_140(choice, ...) ML99_PRIV_REC_NEXT(141, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_141(choice, ...) ML99_PRIV_REC_NEXT(142, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_142(choice, ...) ML99_PRIV_REC_NEXT(143, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_143(choice, ...) ML99_PRIV_REC_NEXT(144, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_144(choice, ...) ML99_PRIV_REC_NEXT(145, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_145(choice, ...) ML99_PRIV_REC_NEXT(146, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_146(choice, ...) ML99_PRIV_REC_NEXT(147, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_147(choice, ...) ML99_PRIV_REC_NEXT(148, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_148(choice, ...) ML99_PRIV_REC_NEXT(149, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_149(choice, ...) ML99_PRIV_REC_NEXT(150, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_150(choice, ...) ML99_PRIV_REC_NEXT(151, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_151(choice, ...) ML99_PRIV_REC_NEXT(152, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_152(choice, ...) ML99_PRIV_REC_NEXT(153, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_153(choice, ...) ML99_PRIV_REC_NEXT(154, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_154(choice, ...) ML99_PRIV_REC_NEXT(155, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_155(choice, ...) ML99_PRIV_REC_NEXT(156, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_156(choice, ...) ML99_PRIV_REC_NEXT(157, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_157(choice, ...) ML99_PRIV_REC_NEXT(158, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_158(choice, ...) ML99_PRIV_REC_NEXT(159, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_159(choice, ...) ML99_PRIV_REC_NEXT(160, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_160(choice, ...) ML99_PRIV_REC_NEXT(161, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_161(choice, ...) ML99_PRIV_REC_NEXT(162, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_162(choice, ...) ML99_PRIV_REC_NEXT(163, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_163(choice, ...) ML99_PRIV_REC_NEXT(164, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_164(choice, ...) ML99_PRIV_REC_NEXT(165, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_165(choice, ...) ML99_PRIV_REC_NEXT(166, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_166(choice, ...) ML99_PRIV_REC_NEXT(167, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_167(choice, ...) ML99_PRIV_REC_NEXT(168, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_168(choice, ...) ML99_PRIV_REC_NEXT(169, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_169(choice, ...) ML99_PRIV_REC_NEXT(170, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_170(choice, ...) ML99_PRIV_REC_NEXT(171, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_171(choice, ...) ML99_PRIV_REC_NEXT(172, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_172(choice, ...) ML99_PRIV_REC_NEXT(173, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_173(choice, ...) ML99_PRIV_REC_NEXT(174, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_174(choice, ...) ML99_PRIV_REC_NEXT(175, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_175(choice, ...) ML99_PRIV_REC_NEXT(176, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_176(choice, ...) ML99_PRIV_REC_NEXT(177, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_177(choice, ...) ML99_PRIV_REC_NEXT(178, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_178(choice, ...) ML99_PRIV_REC_NEXT(179, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_179(choice, ...) ML99_PRIV_REC_NEXT(180, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_180(choice, ...) ML99_PRIV_REC_NEXT(181, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_181(choice, ...) ML99_PRIV_REC_NEXT(182, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_182(choice, ...) ML99_PRIV_REC_NEXT(183, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_183(choice, ...) ML99_PRIV_REC_NEXT(184, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_184(choice, ...) ML99_PRIV_REC_NEXT(185, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_185(choice, ...) ML99_PRIV_REC_NEXT(186, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_186(choice, ...) ML99_PRIV_REC_NEXT(187, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_187(choice, ...) ML99_PRIV_REC_NEXT(188, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_188(choice, ...) ML99_PRIV_REC_NEXT(189, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_189(choice, ...) ML99_PRIV_REC_NEXT(190, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_190(choice, ...) ML99_PRIV_REC_NEXT(191, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_191(choice, ...) ML99_PRIV_REC_NEXT(192, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_192(choice, ...) ML99_PRIV_REC_NEXT(193, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_193(choice, ...) ML99_PRIV_REC_NEXT(194, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_194(choice, ...) ML99_PRIV_REC_NEXT(195, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_195(choice, ...) ML99_PRIV_REC_NEXT(196, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_196(choice, ...) ML99_PRIV_REC_NEXT(197, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_197(choice, ...) ML99_PRIV_REC_NEXT(198, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_198(choice, ...) ML99_PRIV_REC_NEXT(199, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_199(choice, ...) ML99_PRIV_REC_NEXT(200, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_200(choice, ...) ML99_PRIV_REC_NEXT(201, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_201(choice, ...) ML99_PRIV_REC_NEXT(202, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_202(choice, ...) ML99_PRIV_REC_NEXT(203, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_203(choice, ...) ML99_PRIV_REC_NEXT(204, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_204(choice, ...) ML99_PRIV_REC_NEXT(205, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_205(choice, ...) ML99_PRIV_REC_NEXT(206, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_206(choice, ...) ML99_PRIV_REC_NEXT(207, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_207(choice, ...) ML99_PRIV_REC_NEXT(208, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_208(choice, ...) ML99_PRIV_REC_NEXT(209, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_209(choice, ...) ML99_PRIV_REC_NEXT(210, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_210(choice, ...) ML99_PRIV_REC_NEXT(211, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_211(choice, ...) ML99_PRIV_REC_NEXT(212, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_212(choice, ...) ML99_PRIV_REC_NEXT(213, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_213(choice, ...) ML99_PRIV_REC_NEXT(214, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_214(choice, ...) ML99_PRIV_REC_NEXT(215, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_215(choice, ...) ML99_PRIV_REC_NEXT(216, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_216(choice, ...) ML99_PRIV_REC_NEXT(217, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_217(choice, ...) ML99_PRIV_REC_NEXT(218, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_218(choice, ...) ML99_PRIV_REC_NEXT(219, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_219(choice, ...) ML99_PRIV_REC_NEXT(220, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_220(choice, ...) ML99_PRIV_REC_NEXT(221, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_221(choice, ...) ML99_PRIV_REC_NEXT(222, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_222(choice, ...) ML99_PRIV_REC_NEXT(223, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_223(choice, ...) ML99_PRIV_REC_NEXT(224, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_224(choice, ...) ML99_PRIV_REC_NEXT(225, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_225(choice, ...) ML99_PRIV_REC_NEXT(226, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_226(choice, ...) ML99_PRIV_REC_NEXT(227, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_227(choice, ...) ML99_PRIV_REC_NEXT(228, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_228(choice, ...) ML99_PRIV_REC_NEXT(229, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_229(choice, ...) ML99_PRIV_REC_NEXT(230, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_230(choice, ...) ML99_PRIV_REC_NEXT(231, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_231(choice, ...) ML99_PRIV_REC_NEXT(232, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_232(choice, ...) ML99_PRIV_REC_NEXT(233, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_233(choice, ...) ML99_PRIV_REC_NEXT(234, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_234(choice, ...) ML99_PRIV_REC_NEXT(235, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_235(choice, ...) ML99_PRIV_REC_NEXT(236, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_236(choice, ...) ML99_PRIV_REC_NEXT(237, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_237(choice, ...) ML99_PRIV_REC_NEXT(238, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_238(choice, ...) ML99_PRIV_REC_NEXT(239, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_239(choice, ...) ML99_PRIV_REC_NEXT(240, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_240(choice, ...) ML99_PRIV_REC_NEXT(241, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_241(choice, ...) ML99_PRIV_REC_NEXT(242, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_242(choice, ...) ML99_PRIV_REC_NEXT(243, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_243(choice, ...) ML99_PRIV_REC_NEXT(244, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_244(choice, ...) ML99_PRIV_REC_NEXT(245, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_245(choice, ...) ML99_PRIV_REC_NEXT(246, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_246(choice, ...) ML99_PRIV_REC_NEXT(247, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_247(choice, ...) ML99_PRIV_REC_NEXT(248, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_248(choice, ...) ML99_PRIV_REC_NEXT(249, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_249(choice, ...) ML99_PRIV_REC_NEXT(250, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_250(choice, ...) ML99_PRIV_REC_NEXT(251, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_251(choice, ...) ML99_PRIV_REC_NEXT(252, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_252(choice, ...) ML99_PRIV_REC_NEXT(253, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_253(choice, ...) ML99_PRIV_REC_NEXT(254, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_254(choice, ...) ML99_PRIV_REC_NEXT(255, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_255(choice, ...) ML99_PRIV_REC_NEXT(256, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_256(choice, ...) ML99_PRIV_REC_NEXT(257, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_257(choice, ...) ML99_PRIV_REC_NEXT(258, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_258(choice, ...) ML99_PRIV_REC_NEXT(259, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_259(choice, ...) ML99_PRIV_REC_NEXT(260, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_260(choice, ...) ML99_PRIV_REC_NEXT(261, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_261(choice, ...) ML99_PRIV_REC_NEXT(262, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_262(choice, ...) ML99_PRIV_REC_NEXT(263, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_263(choice, ...) ML99_PRIV_REC_NEXT(264, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_264(choice, ...) ML99_PRIV_REC_NEXT(265, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_265(choice, ...) ML99_PRIV_REC_NEXT(266, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_266(choice, ...) ML99_PRIV_REC_NEXT(267, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_267(choice, ...) ML99_PRIV_REC_NEXT(268, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_268(choice, ...) ML99_PRIV_REC_NEXT(269, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_269(choice, ...) ML99_PRIV_REC_NEXT(270, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_270(choice, ...) ML99_PRIV_REC_NEXT(271, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_271(choice, ...) ML99_PRIV_REC_NEXT(272, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_272(choice, ...) ML99_PRIV_REC_NEXT(273, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_273(choice, ...) ML99_PRIV_REC_NEXT(274, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_274(choice, ...) ML99_PRIV_REC_NEXT(275, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_275(choice, ...) ML99_PRIV_REC_NEXT(276, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_276(choice, ...) ML99_PRIV_REC_NEXT(277, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_277(choice, ...) ML99_PRIV_REC_NEXT(278, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_278(choice, ...) ML99_PRIV_REC_NEXT(279, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_279(choice, ...) ML99_PRIV_REC_NEXT(280, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_280(choice, ...) ML99_PRIV_REC_NEXT(281, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_281(choice, ...) ML99_PRIV_REC_NEXT(282, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_282(choice, ...) ML99_PRIV_REC_NEXT(283, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_283(choice, ...) ML99_PRIV_REC_NEXT(284, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_284(choice, ...) ML99_PRIV_REC_NEXT(285, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_285(choice, ...) ML99_PRIV_REC_NEXT(286, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_286(choice, ...) ML99_PRIV_REC_NEXT(287, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_287(choice, ...) ML99_PRIV_REC_NEXT(288, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_288(choice, ...) ML99_PRIV_REC_NEXT(289, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_289(choice, ...) ML99_PRIV_REC_NEXT(290, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_290(choice, ...) ML99_PRIV_REC_NEXT(291, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_291(choice, ...) ML99_PRIV_REC_NEXT(292, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_292(choice, ...) ML99_PRIV_REC_NEXT(293, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_293(choice, ...) ML99_PRIV_REC_NEXT(294, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_294(choice, ...) ML99_PRIV_REC_NEXT(295, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_295(choice, ...) ML99_PRIV_REC_NEXT(296, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_296(choice, ...) ML99_PRIV_REC_NEXT(297, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_297(choice, ...) ML99_PRIV_REC_NEXT(298, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_298(choice, ...) ML99_PRIV_REC_NEXT(299, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_299(choice, ...) ML99_PRIV_REC_NEXT(300, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_300(choice, ...) ML99_PRIV_REC_NEXT(301, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_301(choice, ...) ML99_PRIV_REC_NEXT(302, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_302(choice, ...) ML99_PRIV_REC_NEXT(303, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_303(choice, ...) ML99_PRIV_REC_NEXT(304, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_304(choice, ...) ML99_PRIV_REC_NEXT(305, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_305(choice, ...) ML99_PRIV_REC_NEXT(306, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_306(choice, ...) ML99_PRIV_REC_NEXT(307, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_307(choice, ...) ML99_PRIV_REC_NEXT(308, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_308(choice, ...) ML99_PRIV_REC_NEXT(309, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_309(choice, ...) ML99_PRIV_REC_NEXT(310, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_310(choice, ...) ML99_PRIV_REC_NEXT(311, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_311(choice, ...) ML99_PRIV_REC_NEXT(312, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_312(choice, ...) ML99_PRIV_REC_NEXT(313, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_313(choice, ...) ML99_PRIV_REC_NEXT(314, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_314(choice, ...) ML99_PRIV_REC_NEXT(315, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_315(choice, ...) ML99_PRIV_REC_NEXT(316, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_316(choice, ...) ML99_PRIV_REC_NEXT(317, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_317(choice, ...) ML99_PRIV_REC_NEXT(318, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_318(choice, ...) ML99_PRIV_REC_NEXT(319, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_319(choice, ...) ML99_PRIV_REC_NEXT(320, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_320(choice, ...) ML99_PRIV_REC_NEXT(321, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_321(choice, ...) ML99_PRIV_REC_NEXT(322, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_322(choice, ...) ML99_PRIV_REC_NEXT(323, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_323(choice, ...) ML99_PRIV_REC_NEXT(324, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_324(choice, ...) ML99_PRIV_REC_NEXT(325, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_325(choice, ...) ML99_PRIV_REC_NEXT(326, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_326(choice, ...) ML99_PRIV_REC_NEXT(327, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_327(choice, ...) ML99_PRIV_REC_NEXT(328, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_328(choice, ...) ML99_PRIV_REC_NEXT(329, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_329(choice, ...) ML99_PRIV_REC_NEXT(330, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_330(choice, ...) ML99_PRIV_REC_NEXT(331, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_331(choice, ...) ML99_PRIV_REC_NEXT(332, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_332(choice, ...) ML99_PRIV_REC_NEXT(333, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_333(choice, ...) ML99_PRIV_REC_NEXT(334, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_334(choice, ...) ML99_PRIV_REC_NEXT(335, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_335(choice, ...) ML99_PRIV_REC_NEXT(336, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_336(choice, ...) ML99_PRIV_REC_NEXT(337, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_337(choice, ...) ML99_PRIV_REC_NEXT(338, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_338(choice, ...) ML99_PRIV_REC_NEXT(339, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_339(choice, ...) ML99_PRIV_REC_NEXT(340, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_340(choice, ...) ML99_PRIV_REC_NEXT(341, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_341(choice, ...) ML99_PRIV_REC_NEXT(342, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_342(choice, ...) ML99_PRIV_REC_NEXT(343, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_343(choice, ...) ML99_PRIV_REC_NEXT(344, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_344(choice, ...) ML99_PRIV_REC_NEXT(345, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_345(choice, ...) ML99_PRIV_REC_NEXT(346, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_346(choice, ...) ML99_PRIV_REC_NEXT(347, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_347(choice, ...) ML99_PRIV_REC_NEXT(348, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_348(choice, ...) ML99_PRIV_REC_NEXT(349, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_349(choice, ...) ML99_PRIV_REC_NEXT(350, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_350(choice, ...) ML99_PRIV_REC_NEXT(351, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_351(choice, ...) ML99_PRIV_REC_NEXT(352, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_352(choice, ...) ML99_PRIV_REC_NEXT(353, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_353(choice, ...) ML99_PRIV_REC_NEXT(354, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_354(choice, ...) ML99_PRIV_REC_NEXT(355, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_355(choice, ...) ML99_PRIV_REC_NEXT(356, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_356(choice, ...) ML99_PRIV_REC_NEXT(357, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_357(choice, ...) ML99_PRIV_REC_NEXT(358, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_358(choice, ...) ML99_PRIV_REC_NEXT(359, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_359(choice, ...) ML99_PRIV_REC_NEXT(360, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_360(choice, ...) ML99_PRIV_REC_NEXT(361, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_361(choice, ...) ML99_PRIV_REC_NEXT(362, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_362(choice, ...) ML99_PRIV_REC_NEXT(363, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_363(choice, ...) ML99_PRIV_REC_NEXT(364, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_364(choice, ...) ML99_PRIV_REC_NEXT(365, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_365(choice, ...) ML99_PRIV_REC_NEXT(366, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_366(choice, ...) ML99_PRIV_REC_NEXT(367, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_367(choice, ...) ML99_PRIV_REC_NEXT(368, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_368(choice, ...) ML99_PRIV_REC_NEXT(369, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_369(choice, ...) ML99_PRIV_REC_NEXT(370, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_370(choice, ...) ML99_PRIV_REC_NEXT(371, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_371(choice, ...) ML99_PRIV_REC_NEXT(372, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_372(choice, ...) ML99_PRIV_REC_NEXT(373, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_373(choice, ...) ML99_PRIV_REC_NEXT(374, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_374(choice, ...) ML99_PRIV_REC_NEXT(375, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_375(choice, ...) ML99_PRIV_REC_NEXT(376, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_376(choice, ...) ML99_PRIV_REC_NEXT(377, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_377(choice, ...) ML99_PRIV_REC_NEXT(378, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_378(choice, ...) ML99_PRIV_REC_NEXT(379, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_379(choice, ...) ML99_PRIV_REC_NEXT(380, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_380(choice, ...) ML99_PRIV_REC_NEXT(381, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_381(choice, ...) ML99_PRIV_REC_NEXT(382, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_382(choice, ...) ML99_PRIV_REC_NEXT(383, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_383(choice, ...) ML99_PRIV_REC_NEXT(384, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_384(choice, ...) ML99_PRIV_REC_NEXT(385, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_385(choice, ...) ML99_PRIV_REC_NEXT(386, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_386(choice, ...) ML99_PRIV_REC_NEXT(387, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_387(choice, ...) ML99_PRIV_REC_NEXT(388, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_388(choice, ...) ML99_PRIV_REC_NEXT(389, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_389(choice, ...) ML99_PRIV_REC_NEXT(390, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_390(choice, ...) ML99_PRIV_REC_NEXT(391, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_391(choice, ...) ML99_PRIV_REC_NEXT(392, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_392(choice, ...) ML99_PRIV_REC_NEXT(393, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_393(choice, ...) ML99_PRIV_REC_NEXT(394, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_394(choice, ...) ML99_PRIV_REC_NEXT(395, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_395(choice, ...) ML99_PRIV_REC_NEXT(396, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_396(choice, ...) ML99_PRIV_REC_NEXT(397, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_397(choice, ...) ML99_PRIV_REC_NEXT(398, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_398(choice, ...) ML99_PRIV_REC_NEXT(399, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_399(choice, ...) ML99_PRIV_REC_NEXT(400, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_400(choice, ...) ML99_PRIV_REC_NEXT(401, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_401(choice, ...) ML99_PRIV_REC_NEXT(402, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_402(choice, ...) ML99_PRIV_REC_NEXT(403, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_403(choice, ...) ML99_PRIV_REC_NEXT(404, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_404(choice, ...) ML99_PRIV_REC_NEXT(405, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_405(choice, ...) ML99_PRIV_REC_NEXT(406, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_406(choice, ...) ML99_PRIV_REC_NEXT(407, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_407(choice, ...) ML99_PRIV_REC_NEXT(408, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_408(choice, ...) ML99_PRIV_REC_NEXT(409, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_409(choice, ...) ML99_PRIV_REC_NEXT(410, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_410(choice, ...) ML99_PRIV_REC_NEXT(411, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_411(choice, ...) ML99_PRIV_REC_NEXT(412, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_412(choice, ...) ML99_PRIV_REC_NEXT(413, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_413(choice, ...) ML99_PRIV_REC_NEXT(414, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_414(choice, ...) ML99_PRIV_REC_NEXT(415, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_415(choice, ...) ML99_PRIV_REC_NEXT(416, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_416(choice, ...) ML99_PRIV_REC_NEXT(417, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_417(choice, ...) ML99_PRIV_REC_NEXT(418, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_418(choice, ...) ML99_PRIV_REC_NEXT(419, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_419(choice, ...) ML99_PRIV_REC_NEXT(420, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_420(choice, ...) ML99_PRIV_REC_NEXT(421, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_421(choice, ...) ML99_PRIV_REC_NEXT(422, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_422(choice, ...) ML99_PRIV_REC_NEXT(423, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_423(choice, ...) ML99_PRIV_REC_NEXT(424, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_424(choice, ...) ML99_PRIV_REC_NEXT(425, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_425(choice, ...) ML99_PRIV_REC_NEXT(426, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_426(choice, ...) ML99_PRIV_REC_NEXT(427, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_427(choice, ...) ML99_PRIV_REC_NEXT(428, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_428(choice, ...) ML99_PRIV_REC_NEXT(429, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_429(choice, ...) ML99_PRIV_REC_NEXT(430, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_430(choice, ...) ML99_PRIV_REC_NEXT(431, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_431(choice, ...) ML99_PRIV_REC_NEXT(432, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_432(choice, ...) ML99_PRIV_REC_NEXT(433, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_433(choice, ...) ML99_PRIV_REC_NEXT(434, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_434(choice, ...) ML99_PRIV_REC_NEXT(435, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_435(choice, ...) ML99_PRIV_REC_NEXT(436, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_436(choice, ...) ML99_PRIV_REC_NEXT(437, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_437(choice, ...) ML99_PRIV_REC_NEXT(438, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_438(choice, ...) ML99_PRIV_REC_NEXT(439, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_439(choice, ...) ML99_PRIV_REC_NEXT(440, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_440(choice, ...) ML99_PRIV_REC_NEXT(441, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_441(choice, ...) ML99_PRIV_REC_NEXT(442, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_442(choice, ...) ML99_PRIV_REC_NEXT(443, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_443(choice, ...) ML99_PRIV_REC_NEXT(444, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_444(choice, ...) ML99_PRIV_REC_NEXT(445, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_445(choice, ...) ML99_PRIV_REC_NEXT(446, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_446(choice, ...) ML99_PRIV_REC_NEXT(447, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_447(choice, ...) ML99_PRIV_REC_NEXT(448, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_448(choice, ...) ML99_PRIV_REC_NEXT(449, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_449(choice, ...) ML99_PRIV_REC_NEXT(450, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_450(choice, ...) ML99_PRIV_REC_NEXT(451, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_451(choice, ...) ML99_PRIV_REC_NEXT(452, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_452(choice, ...) ML99_PRIV_REC_NEXT(453, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_453(choice, ...) ML99_PRIV_REC_NEXT(454, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_454(choice, ...) ML99_PRIV_REC_NEXT(455, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_455(choice, ...) ML99_PRIV_REC_NEXT(456, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_456(choice, ...) ML99_PRIV_REC_NEXT(457, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_457(choice, ...) ML99_PRIV_REC_NEXT(458, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_458(choice, ...) ML99_PRIV_REC_NEXT(459, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_459(choice, ...) ML99_PRIV_REC_NEXT(460, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_460(choice, ...) ML99_PRIV_REC_NEXT(461, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_461(choice, ...) ML99_PRIV_REC_NEXT(462, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_462(choice, ...) ML99_PRIV_REC_NEXT(463, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_463(choice, ...) ML99_PRIV_REC_NEXT(464, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_464(choice, ...) ML99_PRIV_REC_NEXT(465, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_465(choice, ...) ML99_PRIV_REC_NEXT(466, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_466(choice, ...) ML99_PRIV_REC_NEXT(467, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_467(choice, ...) ML99_PRIV_REC_NEXT(468, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_468(choice, ...) ML99_PRIV_REC_NEXT(469, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_469(choice, ...) ML99_PRIV_REC_NEXT(470, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_470(choice, ...) ML99_PRIV_REC_NEXT(471, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_471(choice, ...) ML99_PRIV_REC_NEXT(472, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_472(choice, ...) ML99_PRIV_REC_NEXT(473, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_473(choice, ...) ML99_PRIV_REC_NEXT(474, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_474(choice, ...) ML99_PRIV_REC_NEXT(475, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_475(choice, ...) ML99_PRIV_REC_NEXT(476, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_476(choice, ...) ML99_PRIV_REC_NEXT(477, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_477(choice, ...) ML99_PRIV_REC_NEXT(478, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_478(choice, ...) ML99_PRIV_REC_NEXT(479, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_479(choice, ...) ML99_PRIV_REC_NEXT(480, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_480(choice, ...) ML99_PRIV_REC_NEXT(481, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_481(choice, ...) ML99_PRIV_REC_NEXT(482, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_482(choice, ...) ML99_PRIV_REC_NEXT(483, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_483(choice, ...) ML99_PRIV_REC_NEXT(484, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_484(choice, ...) ML99_PRIV_REC_NEXT(485, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_485(choice, ...) ML99_PRIV_REC_NEXT(486, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_486(choice, ...) ML99_PRIV_REC_NEXT(487, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_487(choice, ...) ML99_PRIV_REC_NEXT(488, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_488(choice, ...) ML99_PRIV_REC_NEXT(489, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_489(choice, ...) ML99_PRIV_REC_NEXT(490, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_490(choice, ...) ML99_PRIV_REC_NEXT(491, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_491(choice, ...) ML99_PRIV_REC_NEXT(492, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_492(choice, ...) ML99_PRIV_REC_NEXT(493, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_493(choice, ...) ML99_PRIV_REC_NEXT(494, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_494(choice, ...) ML99_PRIV_REC_NEXT(495, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_495(choice, ...) ML99_PRIV_REC_NEXT(496, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_496(choice, ...) ML99_PRIV_REC_NEXT(497, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_497(choice, ...) ML99_PRIV_REC_NEXT(498, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_498(choice, ...) ML99_PRIV_REC_NEXT(499, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_499(choice, ...) ML99_PRIV_REC_NEXT(500, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_500(choice, ...) ML99_PRIV_REC_NEXT(501, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_501(choice, ...) ML99_PRIV_REC_NEXT(502, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_502(choice, ...) ML99_PRIV_REC_NEXT(503, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_503(choice, ...) ML99_PRIV_REC_NEXT(504, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_504(choice, ...) ML99_PRIV_REC_NEXT(505, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_505(choice, ...) ML99_PRIV_REC_NEXT(506, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_506(choice, ...) ML99_PRIV_REC_NEXT(507, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_507(choice, ...) ML99_PRIV_REC_NEXT(508, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_508(choice, ...) ML99_PRIV_REC_NEXT(509, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_509(choice, ...) ML99_PRIV_REC_NEXT(510, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_510(choice, ...) ML99_PRIV_REC_NEXT(511, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_511(choice, ...) ML99_PRIV_REC_NEXT(512, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_512(choice, ...) ML99_PRIV_REC_NEXT(513, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_513(choice, ...) ML99_PRIV_REC_NEXT(514, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_514(choice, ...) ML99_PRIV_REC_NEXT(515, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_515(choice, ...) ML99_PRIV_REC_NEXT(516, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_516(choice, ...) ML99_PRIV_REC_NEXT(517, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_517(choice, ...) ML99_PRIV_REC_NEXT(518, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_518(choice, ...) ML99_PRIV_REC_NEXT(519, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_519(choice, ...) ML99_PRIV_REC_NEXT(520, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_520(choice, ...) ML99_PRIV_REC_NEXT(521, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_521(choice, ...) ML99_PRIV_REC_NEXT(522, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_522(choice, ...) ML99_PRIV_REC_NEXT(523, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_523(choice, ...) ML99_PRIV_REC_NEXT(524, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_524(choice, ...) ML99_PRIV_REC_NEXT(525, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_525(choice, ...) ML99_PRIV_REC_NEXT(526, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_526(choice, ...) ML99_PRIV_REC_NEXT(527, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_527(choice, ...) ML99_PRIV_REC_NEXT(528, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_528(choice, ...) ML99_PRIV_REC_NEXT(529, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_529(choice, ...) ML99_PRIV_REC_NEXT(530, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_530(choice, ...) ML99_PRIV_REC_NEXT(531, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_531(choice, ...) ML99_PRIV_REC_NEXT(532, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_532(choice, ...) ML99_PRIV_REC_NEXT(533, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_533(choice, ...) ML99_PRIV_REC_NEXT(534, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_534(choice, ...) ML99_PRIV_REC_NEXT(535, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_535(choice, ...) ML99_PRIV_REC_NEXT(536, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_536(choice, ...) ML99_PRIV_REC_NEXT(537, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_537(choice, ...) ML99_PRIV_REC_NEXT(538, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_538(choice, ...) ML99_PRIV_REC_NEXT(539, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_539(choice, ...) ML99_PRIV_REC_NEXT(540, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_540(choice, ...) ML99_PRIV_REC_NEXT(541, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_541(choice, ...) ML99_PRIV_REC_NEXT(542, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_542(choice, ...) ML99_PRIV_REC_NEXT(543, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_543(choice, ...) ML99_PRIV_REC_NEXT(544, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_544(choice, ...) ML99_PRIV_REC_NEXT(545, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_545(choice, ...) ML99_PRIV_REC_NEXT(546, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_546(choice, ...) ML99_PRIV_REC_NEXT(547, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_547(choice, ...) ML99_PRIV_REC_NEXT(548, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_548(choice, ...) ML99_PRIV_REC_NEXT(549, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_549(choice, ...) ML99_PRIV_REC_NEXT(550, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_550(choice, ...) ML99_PRIV_REC_NEXT(551, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_551(choice, ...) ML99_PRIV_REC_NEXT(552, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_552(choice, ...) ML99_PRIV_REC_NEXT(553, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_553(choice, ...) ML99_PRIV_REC_NEXT(554, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_554(choice, ...) ML99_PRIV_REC_NEXT(555, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_555(choice, ...) ML99_PRIV_REC_NEXT(556, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_556(choice, ...) ML99_PRIV_REC_NEXT(557, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_557(choice, ...) ML99_PRIV_REC_NEXT(558, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_558(choice, ...) ML99_PRIV_REC_NEXT(559, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_559(choice, ...) ML99_PRIV_REC_NEXT(560, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_560(choice, ...) ML99_PRIV_REC_NEXT(561, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_561(choice, ...) ML99_PRIV_REC_NEXT(562, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_562(choice, ...) ML99_PRIV_REC_NEXT(563, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_563(choice, ...) ML99_PRIV_REC_NEXT(564, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_564(choice, ...) ML99_PRIV_REC_NEXT(565, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_565(choice, ...) ML99_PRIV_REC_NEXT(566, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_566(choice, ...) ML99_PRIV_REC_NEXT(567, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_567(choice, ...) ML99_PRIV_REC_NEXT(568, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_568(choice, ...) ML99_PRIV_REC_NEXT(569, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_569(choice, ...) ML99_PRIV_REC_NEXT(570, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_570(choice, ...) ML99_PRIV_REC_NEXT(571, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_571(choice, ...) ML99_PRIV_REC_NEXT(572, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_572(choice, ...) ML99_PRIV_REC_NEXT(573, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_573(choice, ...) ML99_PRIV_REC_NEXT(574, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_574(choice, ...) ML99_PRIV_REC_NEXT(575, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_575(choice, ...) ML99_PRIV_REC_NEXT(576, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_576(choice, ...) ML99_PRIV_REC_NEXT(577, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_577(choice, ...) ML99_PRIV_REC_NEXT(578, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_578(choice, ...) ML99_PRIV_REC_NEXT(579, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_579(choice, ...) ML99_PRIV_REC_NEXT(580, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_580(choice, ...) ML99_PRIV_REC_NEXT(581, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_581(choice, ...) ML99_PRIV_REC_NEXT(582, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_582(choice, ...) ML99_PRIV_REC_NEXT(583, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_583(choice, ...) ML99_PRIV_REC_NEXT(584, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_584(choice, ...) ML99_PRIV_REC_NEXT(585, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_585(choice, ...) ML99_PRIV_REC_NEXT(586, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_586(choice, ...) ML99_PRIV_REC_NEXT(587, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_587(choice, ...) ML99_PRIV_REC_NEXT(588, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_588(choice, ...) ML99_PRIV_REC_NEXT(589, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_589(choice, ...) ML99_PRIV_REC_NEXT(590, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_590(choice, ...) ML99_PRIV_REC_NEXT(591, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_591(choice, ...) ML99_PRIV_REC_NEXT(592, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_592(choice, ...) ML99_PRIV_REC_NEXT(593, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_593(choice, ...) ML99_PRIV_REC_NEXT(594, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_594(choice, ...) ML99_PRIV_REC_NEXT(595, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_595(choice, ...) ML99_PRIV_REC_NEXT(596, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_596(choice, ...) ML99_PRIV_REC_NEXT(597, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_597(choice, ...) ML99_PRIV_REC_NEXT(598, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_598(choice, ...) ML99_PRIV_REC_NEXT(599, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_599(choice, ...) ML99_PRIV_REC_NEXT(600, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_600(choice, ...) ML99_PRIV_REC_NEXT(601, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_601(choice, ...) ML99_PRIV_REC_NEXT(602, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_602(choice, ...) ML99_PRIV_REC_NEXT(603, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_603(choice, ...) ML99_PRIV_REC_NEXT(604, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_604(choice, ...) ML99_PRIV_REC_NEXT(605, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_605(choice, ...) ML99_PRIV_REC_NEXT(606, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_606(choice, ...) ML99_PRIV_REC_NEXT(607, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_607(choice, ...) ML99_PRIV_REC_NEXT(608, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_608(choice, ...) ML99_PRIV_REC_NEXT(609, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_609(choice, ...) ML99_PRIV_REC_NEXT(610, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_610(choice, ...) ML99_PRIV_REC_NEXT(611, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_611(choice, ...) ML99_PRIV_REC_NEXT(612, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_612(choice, ...) ML99_PRIV_REC_NEXT(613, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_613(choice, ...) ML99_PRIV_REC_NEXT(614, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_614(choice, ...) ML99_PRIV_REC_NEXT(615, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_615(choice, ...) ML99_PRIV_REC_NEXT(616, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_616(choice, ...) ML99_PRIV_REC_NEXT(617, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_617(choice, ...) ML99_PRIV_REC_NEXT(618, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_618(choice, ...) ML99_PRIV_REC_NEXT(619, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_619(choice, ...) ML99_PRIV_REC_NEXT(620, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_620(choice, ...) ML99_PRIV_REC_NEXT(621, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_621(choice, ...) ML99_PRIV_REC_NEXT(622, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_622(choice, ...) ML99_PRIV_REC_NEXT(623, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_623(choice, ...) ML99_PRIV_REC_NEXT(624, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_624(choice, ...) ML99_PRIV_REC_NEXT(625, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_625(choice, ...) ML99_PRIV_REC_NEXT(626, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_626(choice, ...) ML99_PRIV_REC_NEXT(627, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_627(choice, ...) ML99_PRIV_REC_NEXT(628, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_628(choice, ...) ML99_PRIV_REC_NEXT(629, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_629(choice, ...) ML99_PRIV_REC_NEXT(630, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_630(choice, ...) ML99_PRIV_REC_NEXT(631, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_631(choice, ...) ML99_PRIV_REC_NEXT(632, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_632(choice, ...) ML99_PRIV_REC_NEXT(633, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_633(choice, ...) ML99_PRIV_REC_NEXT(634, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_634(choice, ...) ML99_PRIV_REC_NEXT(635, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_635(choice, ...) ML99_PRIV_REC_NEXT(636, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_636(choice, ...) ML99_PRIV_REC_NEXT(637, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_637(choice, ...) ML99_PRIV_REC_NEXT(638, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_638(choice, ...) ML99_PRIV_REC_NEXT(639, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_639(choice, ...) ML99_PRIV_REC_NEXT(640, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_640(choice, ...) ML99_PRIV_REC_NEXT(641, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_641(choice, ...) ML99_PRIV_REC_NEXT(642, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_642(choice, ...) ML99_PRIV_REC_NEXT(643, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_643(choice, ...) ML99_PRIV_REC_NEXT(644, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_644(choice, ...) ML99_PRIV_REC_NEXT(645, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_645(choice, ...) ML99_PRIV_REC_NEXT(646, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_646(choice, ...) ML99_PRIV_REC_NEXT(647, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_647(choice, ...) ML99_PRIV_REC_NEXT(648, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_648(choice, ...) ML99_PRIV_REC_NEXT(649, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_649(choice, ...) ML99_PRIV_REC_NEXT(650, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_650(choice, ...) ML99_PRIV_REC_NEXT(651, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_651(choice, ...) ML99_PRIV_REC_NEXT(652, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_652(choice, ...) ML99_PRIV_REC_NEXT(653, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_653(choice, ...) ML99_PRIV_REC_NEXT(654, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_654(choice, ...) ML99_PRIV_REC_NEXT(655, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_655(choice, ...) ML99_PRIV_REC_NEXT(656, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_656(choice, ...) ML99_PRIV_REC_NEXT(657, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_657(choice, ...) ML99_PRIV_REC_NEXT(658, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_658(choice, ...) ML99_PRIV_REC_NEXT(659, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_659(choice, ...) ML99_PRIV_REC_NEXT(660, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_660(choice, ...) ML99_PRIV_REC_NEXT(661, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_661(choice, ...) ML99_PRIV_REC_NEXT(662, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_662(choice, ...) ML99_PRIV_REC_NEXT(663, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_663(choice, ...) ML99_PRIV_REC_NEXT(664, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_664(choice, ...) ML99_PRIV_REC_NEXT(665, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_665(choice, ...) ML99_PRIV_REC_NEXT(666, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_666(choice, ...) ML99_PRIV_REC_NEXT(667, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_667(choice, ...) ML99_PRIV_REC_NEXT(668, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_668(choice, ...) ML99_PRIV_REC_NEXT(669, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_669(choice, ...) ML99_PRIV_REC_NEXT(670, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_670(choice, ...) ML99_PRIV_REC_NEXT(671, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_671(choice, ...) ML99_PRIV_REC_NEXT(672, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_672(choice, ...) ML99_PRIV_REC_NEXT(673, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_673(choice, ...) ML99_PRIV_REC_NEXT(674, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_674(choice, ...) ML99_PRIV_REC_NEXT(675, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_675(choice, ...) ML99_PRIV_REC_NEXT(676, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_676(choice, ...) ML99_PRIV_REC_NEXT(677, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_677(choice, ...) ML99_PRIV_REC_NEXT(678, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_678(choice, ...) ML99_PRIV_REC_NEXT(679, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_679(choice, ...) ML99_PRIV_REC_NEXT(680, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_680(choice, ...) ML99_PRIV_REC_NEXT(681, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_681(choice, ...) ML99_PRIV_REC_NEXT(682, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_682(choice, ...) ML99_PRIV_REC_NEXT(683, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_683(choice, ...) ML99_PRIV_REC_NEXT(684, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_684(choice, ...) ML99_PRIV_REC_NEXT(685, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_685(choice, ...) ML99_PRIV_REC_NEXT(686, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_686(choice, ...) ML99_PRIV_REC_NEXT(687, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_687(choice, ...) ML99_PRIV_REC_NEXT(688, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_688(choice, ...) ML99_PRIV_REC_NEXT(689, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_689(choice, ...) ML99_PRIV_REC_NEXT(690, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_690(choice, ...) ML99_PRIV_REC_NEXT(691, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_691(choice, ...) ML99_PRIV_REC_NEXT(692, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_692(choice, ...) ML99_PRIV_REC_NEXT(693, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_693(choice, ...) ML99_PRIV_REC_NEXT(694, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_694(choice, ...) ML99_PRIV_REC_NEXT(695, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_695(choice, ...) ML99_PRIV_REC_NEXT(696, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_696(choice, ...) ML99_PRIV_REC_NEXT(697, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_697(choice, ...) ML99_PRIV_REC_NEXT(698, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_698(choice, ...) ML99_PRIV_REC_NEXT(699, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_699(choice, ...) ML99_PRIV_REC_NEXT(700, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_700(choice, ...) ML99_PRIV_REC_NEXT(701, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_701(choice, ...) ML99_PRIV_REC_NEXT(702, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_702(choice, ...) ML99_PRIV_REC_NEXT(703, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_703(choice, ...) ML99_PRIV_REC_NEXT(704, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_704(choice, ...) ML99_PRIV_REC_NEXT(705, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_705(choice, ...) ML99_PRIV_REC_NEXT(706, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_706(choice, ...) ML99_PRIV_REC_NEXT(707, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_707(choice, ...) ML99_PRIV_REC_NEXT(708, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_708(choice, ...) ML99_PRIV_REC_NEXT(709, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_709(choice, ...) ML99_PRIV_REC_NEXT(710, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_710(choice, ...) ML99_PRIV_REC_NEXT(711, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_711(choice, ...) ML99_PRIV_REC_NEXT(712, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_712(choice, ...) ML99_PRIV_REC_NEXT(713, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_713(choice, ...) ML99_PRIV_REC_NEXT(714, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_714(choice, ...) ML99_PRIV_REC_NEXT(715, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_715(choice, ...) ML99_PRIV_REC_NEXT(716, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_716(choice, ...) ML99_PRIV_REC_NEXT(717, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_717(choice, ...) ML99_PRIV_REC_NEXT(718, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_718(choice, ...) ML99_PRIV_REC_NEXT(719, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_719(choice, ...) ML99_PRIV_REC_NEXT(720, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_720(choice, ...) ML99_PRIV_REC_NEXT(721, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_721(choice, ...) ML99_PRIV_REC_NEXT(722, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_722(choice, ...) ML99_PRIV_REC_NEXT(723, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_723(choice, ...) ML99_PRIV_REC_NEXT(724, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_724(choice, ...) ML99_PRIV_REC_NEXT(725, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_725(choice, ...) ML99_PRIV_REC_NEXT(726, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_726(choice, ...) ML99_PRIV_REC_NEXT(727, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_727(choice, ...) ML99_PRIV_REC_NEXT(728, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_728(choice, ...) ML99_PRIV_REC_NEXT(729, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_729(choice, ...) ML99_PRIV_REC_NEXT(730, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_730(choice, ...) ML99_PRIV_REC_NEXT(731, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_731(choice, ...) ML99_PRIV_REC_NEXT(732, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_732(choice, ...) ML99_PRIV_REC_NEXT(733, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_733(choice, ...) ML99_PRIV_REC_NEXT(734, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_734(choice, ...) ML99_PRIV_REC_NEXT(735, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_735(choice, ...) ML99_PRIV_REC_NEXT(736, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_736(choice, ...) ML99_PRIV_REC_NEXT(737, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_737(choice, ...) ML99_PRIV_REC_NEXT(738, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_738(choice, ...) ML99_PRIV_REC_NEXT(739, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_739(choice, ...) ML99_PRIV_REC_NEXT(740, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_740(choice, ...) ML99_PRIV_REC_NEXT(741, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_741(choice, ...) ML99_PRIV_REC_NEXT(742, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_742(choice, ...) ML99_PRIV_REC_NEXT(743, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_743(choice, ...) ML99_PRIV_REC_NEXT(744, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_744(choice, ...) ML99_PRIV_REC_NEXT(745, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_745(choice, ...) ML99_PRIV_REC_NEXT(746, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_746(choice, ...) ML99_PRIV_REC_NEXT(747, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_747(choice, ...) ML99_PRIV_REC_NEXT(748, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_748(choice, ...) ML99_PRIV_REC_NEXT(749, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_749(choice, ...) ML99_PRIV_REC_NEXT(750, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_750(choice, ...) ML99_PRIV_REC_NEXT(751, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_751(choice, ...) ML99_PRIV_REC_NEXT(752, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_752(choice, ...) ML99_PRIV_REC_NEXT(753, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_753(choice, ...) ML99_PRIV_REC_NEXT(754, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_754(choice, ...) ML99_PRIV_REC_NEXT(755, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_755(choice, ...) ML99_PRIV_REC_NEXT(756, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_756(choice, ...) ML99_PRIV_REC_NEXT(757, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_757(choice, ...) ML99_PRIV_REC_NEXT(758, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_758(choice, ...) ML99_PRIV_REC_NEXT(759, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_759(choice, ...) ML99_PRIV_REC_NEXT(760, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_760(choice, ...) ML99_PRIV_REC_NEXT(761, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_761(choice, ...) ML99_PRIV_REC_NEXT(762, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_762(choice, ...) ML99_PRIV_REC_NEXT(763, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_763(choice, ...) ML99_PRIV_REC_NEXT(764, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_764(choice, ...) ML99_PRIV_REC_NEXT(765, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_765(choice, ...) ML99_PRIV_REC_NEXT(766, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_766(choice, ...) ML99_PRIV_REC_NEXT(767, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_767(choice, ...) ML99_PRIV_REC_NEXT(768, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_768(choice, ...) ML99_PRIV_REC_NEXT(769, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_769(choice, ...) ML99_PRIV_REC_NEXT(770, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_770(choice, ...) ML99_PRIV_REC_NEXT(771, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_771(choice, ...) ML99_PRIV_REC_NEXT(772, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_772(choice, ...) ML99_PRIV_REC_NEXT(773, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_773(choice, ...) ML99_PRIV_REC_NEXT(774, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_774(choice, ...) ML99_PRIV_REC_NEXT(775, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_775(choice, ...) ML99_PRIV_REC_NEXT(776, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_776(choice, ...) ML99_PRIV_REC_NEXT(777, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_777(choice, ...) ML99_PRIV_REC_NEXT(778, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_778(choice, ...) ML99_PRIV_REC_NEXT(779, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_779(choice, ...) ML99_PRIV_REC_NEXT(780, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_780(choice, ...) ML99_PRIV_REC_NEXT(781, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_781(choice, ...) ML99_PRIV_REC_NEXT(782, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_782(choice, ...) ML99_PRIV_REC_NEXT(783, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_783(choice, ...) ML99_PRIV_REC_NEXT(784, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_784(choice, ...) ML99_PRIV_REC_NEXT(785, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_785(choice, ...) ML99_PRIV_REC_NEXT(786, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_786(choice, ...) ML99_PRIV_REC_NEXT(787, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_787(choice, ...) ML99_PRIV_REC_NEXT(788, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_788(choice, ...) ML99_PRIV_REC_NEXT(789, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_789(choice, ...) ML99_PRIV_REC_NEXT(790, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_790(choice, ...) ML99_PRIV_REC_NEXT(791, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_791(choice, ...) ML99_PRIV_REC_NEXT(792, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_792(choice, ...) ML99_PRIV_REC_NEXT(793, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_793(choice, ...) ML99_PRIV_REC_NEXT(794, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_794(choice, ...) ML99_PRIV_REC_NEXT(795, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_795(choice, ...) ML99_PRIV_REC_NEXT(796, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_796(choice, ...) ML99_PRIV_REC_NEXT(797, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_797(choice, ...) ML99_PRIV_REC_NEXT(798, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_798(choice, ...) ML99_PRIV_REC_NEXT(799, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_799(choice, ...) ML99_PRIV_REC_NEXT(800, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_800(choice, ...) ML99_PRIV_REC_NEXT(801, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_801(choice, ...) ML99_PRIV_REC_NEXT(802, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_802(choice, ...) ML99_PRIV_REC_NEXT(803, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_803(choice, ...) ML99_PRIV_REC_NEXT(804, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_804(choice, ...) ML99_PRIV_REC_NEXT(805, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_805(choice, ...) ML99_PRIV_REC_NEXT(806, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_806(choice, ...) ML99_PRIV_REC_NEXT(807, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_807(choice, ...) ML99_PRIV_REC_NEXT(808, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_808(choice, ...) ML99_PRIV_REC_NEXT(809, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_809(choice, ...) ML99_PRIV_REC_NEXT(810, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_810(choice, ...) ML99_PRIV_REC_NEXT(811, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_811(choice, ...) ML99_PRIV_REC_NEXT(812, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_812(choice, ...) ML99_PRIV_REC_NEXT(813, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_813(choice, ...) ML99_PRIV_REC_NEXT(814, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_814(choice, ...) ML99_PRIV_REC_NEXT(815, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_815(choice, ...) ML99_PRIV_REC_NEXT(816, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_816(choice, ...) ML99_PRIV_REC_NEXT(817, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_817(choice, ...) ML99_PRIV_REC_NEXT(818, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_818(choice, ...) ML99_PRIV_REC_NEXT(819, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_819(choice, ...) ML99_PRIV_REC_NEXT(820, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_820(choice, ...) ML99_PRIV_REC_NEXT(821, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_821(choice, ...) ML99_PRIV_REC_NEXT(822, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_822(choice, ...) ML99_PRIV_REC_NEXT(823, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_823(choice, ...) ML99_PRIV_REC_NEXT(824, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_824(choice, ...) ML99_PRIV_REC_NEXT(825, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_825(choice, ...) ML99_PRIV_REC_NEXT(826, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_826(choice, ...) ML99_PRIV_REC_NEXT(827, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_827(choice, ...) ML99_PRIV_REC_NEXT(828, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_828(choice, ...) ML99_PRIV_REC_NEXT(829, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_829(choice, ...) ML99_PRIV_REC_NEXT(830, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_830(choice, ...) ML99_PRIV_REC_NEXT(831, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_831(choice, ...) ML99_PRIV_REC_NEXT(832, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_832(choice, ...) ML99_PRIV_REC_NEXT(833, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_833(choice, ...) ML99_PRIV_REC_NEXT(834, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_834(choice, ...) ML99_PRIV_REC_NEXT(835, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_835(choice, ...) ML99_PRIV_REC_NEXT(836, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_836(choice, ...) ML99_PRIV_REC_NEXT(837, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_837(choice, ...) ML99_PRIV_REC_NEXT(838, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_838(choice, ...) ML99_PRIV_REC_NEXT(839, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_839(choice, ...) ML99_PRIV_REC_NEXT(840, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_840(choice, ...) ML99_PRIV_REC_NEXT(841, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_841(choice, ...) ML99_PRIV_REC_NEXT(842, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_842(choice, ...) ML99_PRIV_REC_NEXT(843, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_843(choice, ...) ML99_PRIV_REC_NEXT(844, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_844(choice, ...) ML99_PRIV_REC_NEXT(845, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_845(choice, ...) ML99_PRIV_REC_NEXT(846, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_846(choice, ...) ML99_PRIV_REC_NEXT(847, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_847(choice, ...) ML99_PRIV_REC_NEXT(848, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_848(choice, ...) ML99_PRIV_REC_NEXT(849, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_849(choice, ...) ML99_PRIV_REC_NEXT(850, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_850(choice, ...) ML99_PRIV_REC_NEXT(851, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_851(choice, ...) ML99_PRIV_REC_NEXT(852, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_852(choice, ...) ML99_PRIV_REC_NEXT(853, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_853(choice, ...) ML99_PRIV_REC_NEXT(854, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_854(choice, ...) ML99_PRIV_REC_NEXT(855, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_855(choice, ...) ML99_PRIV_REC_NEXT(856, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_856(choice, ...) ML99_PRIV_REC_NEXT(857, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_857(choice, ...) ML99_PRIV_REC_NEXT(858, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_858(choice, ...) ML99_PRIV_REC_NEXT(859, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_859(choice, ...) ML99_PRIV_REC_NEXT(860, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_860(choice, ...) ML99_PRIV_REC_NEXT(861, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_861(choice, ...) ML99_PRIV_REC_NEXT(862, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_862(choice, ...) ML99_PRIV_REC_NEXT(863, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_863(choice, ...) ML99_PRIV_REC_NEXT(864, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_864(choice, ...) ML99_PRIV_REC_NEXT(865, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_865(choice, ...) ML99_PRIV_REC_NEXT(866, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_866(choice, ...) ML99_PRIV_REC_NEXT(867, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_867(choice, ...) ML99_PRIV_REC_NEXT(868, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_868(choice, ...) ML99_PRIV_REC_NEXT(869, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_869(choice, ...) ML99_PRIV_REC_NEXT(870, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_870(choice, ...) ML99_PRIV_REC_NEXT(871, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_871(choice, ...) ML99_PRIV_REC_NEXT(872, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_872(choice, ...) ML99_PRIV_REC_NEXT(873, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_873(choice, ...) ML99_PRIV_REC_NEXT(874, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_874(choice, ...) ML99_PRIV_REC_NEXT(875, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_875(choice, ...) ML99_PRIV_REC_NEXT(876, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_876(choice, ...) ML99_PRIV_REC_NEXT(877, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_877(choice, ...) ML99_PRIV_REC_NEXT(878, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_878(choice, ...) ML99_PRIV_REC_NEXT(879, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_879(choice, ...) ML99_PRIV_REC_NEXT(880, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_880(choice, ...) ML99_PRIV_REC_NEXT(881, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_881(choice, ...) ML99_PRIV_REC_NEXT(882, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_882(choice, ...) ML99_PRIV_REC_NEXT(883, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_883(choice, ...) ML99_PRIV_REC_NEXT(884, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_884(choice, ...) ML99_PRIV_REC_NEXT(885, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_885(choice, ...) ML99_PRIV_REC_NEXT(886, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_886(choice, ...) ML99_PRIV_REC_NEXT(887, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_887(choice, ...) ML99_PRIV_REC_NEXT(888, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_888(choice, ...) ML99_PRIV_REC_NEXT(889, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_889(choice, ...) ML99_PRIV_REC_NEXT(890, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_890(choice, ...) ML99_PRIV_REC_NEXT(891, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_891(choice, ...) ML99_PRIV_REC_NEXT(892, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_892(choice, ...) ML99_PRIV_REC_NEXT(893, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_893(choice, ...) ML99_PRIV_REC_NEXT(894, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_894(choice, ...) ML99_PRIV_REC_NEXT(895, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_895(choice, ...) ML99_PRIV_REC_NEXT(896, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_896(choice, ...) ML99_PRIV_REC_NEXT(897, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_897(choice, ...) ML99_PRIV_REC_NEXT(898, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_898(choice, ...) ML99_PRIV_REC_NEXT(899, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_899(choice, ...) ML99_PRIV_REC_NEXT(900, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_900(choice, ...) ML99_PRIV_REC_NEXT(901, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_901(choice, ...) ML99_PRIV_REC_NEXT(902, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_902(choice, ...) ML99_PRIV_REC_NEXT(903, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_903(choice, ...) ML99_PRIV_REC_NEXT(904, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_904(choice, ...) ML99_PRIV_REC_NEXT(905, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_905(choice, ...) ML99_PRIV_REC_NEXT(906, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_906(choice, ...) ML99_PRIV_REC_NEXT(907, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_907(choice, ...) ML99_PRIV_REC_NEXT(908, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_908(choice, ...) ML99_PRIV_REC_NEXT(909, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_909(choice, ...) ML99_PRIV_REC_NEXT(910, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_910(choice, ...) ML99_PRIV_REC_NEXT(911, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_911(choice, ...) ML99_PRIV_REC_NEXT(912, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_912(choice, ...) ML99_PRIV_REC_NEXT(913, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_913(choice, ...) ML99_PRIV_REC_NEXT(914, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_914(choice, ...) ML99_PRIV_REC_NEXT(915, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_915(choice, ...) ML99_PRIV_REC_NEXT(916, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_916(choice, ...) ML99_PRIV_REC_NEXT(917, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_917(choice, ...) ML99_PRIV_REC_NEXT(918, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_918(choice, ...) ML99_PRIV_REC_NEXT(919, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_919(choice, ...) ML99_PRIV_REC_NEXT(920, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_920(choice, ...) ML99_PRIV_REC_NEXT(921, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_921(choice, ...) ML99_PRIV_REC_NEXT(922, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_922(choice, ...) ML99_PRIV_REC_NEXT(923, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_923(choice, ...) ML99_PRIV_REC_NEXT(924, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_924(choice, ...) ML99_PRIV_REC_NEXT(925, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_925(choice, ...) ML99_PRIV_REC_NEXT(926, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_926(choice, ...) ML99_PRIV_REC_NEXT(927, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_927(choice, ...) ML99_PRIV_REC_NEXT(928, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_928(choice, ...) ML99_PRIV_REC_NEXT(929, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_929(choice, ...) ML99_PRIV_REC_NEXT(930, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_930(choice, ...) ML99_PRIV_REC_NEXT(931, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_931(choice, ...) ML99_PRIV_REC_NEXT(932, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_932(choice, ...) ML99_PRIV_REC_NEXT(933, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_933(choice, ...) ML99_PRIV_REC_NEXT(934, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_934(choice, ...) ML99_PRIV_REC_NEXT(935, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_935(choice, ...) ML99_PRIV_REC_NEXT(936, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_936(choice, ...) ML99_PRIV_REC_NEXT(937, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_937(choice, ...) ML99_PRIV_REC_NEXT(938, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_938(choice, ...) ML99_PRIV_REC_NEXT(939, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_939(choice, ...) ML99_PRIV_REC_NEXT(940, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_940(choice, ...) ML99_PRIV_REC_NEXT(941, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_941(choice, ...) ML99_PRIV_REC_NEXT(942, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_942(choice, ...) ML99_PRIV_REC_NEXT(943, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_943(choice, ...) ML99_PRIV_REC_NEXT(944, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_944(choice, ...) ML99_PRIV_REC_NEXT(945, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_945(choice, ...) ML99_PRIV_REC_NEXT(946, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_946(choice, ...) ML99_PRIV_REC_NEXT(947, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_947(choice, ...) ML99_PRIV_REC_NEXT(948, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_948(choice, ...) ML99_PRIV_REC_NEXT(949, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_949(choice, ...) ML99_PRIV_REC_NEXT(950, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_950(choice, ...) ML99_PRIV_REC_NEXT(951, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_951(choice, ...) ML99_PRIV_REC_NEXT(952, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_952(choice, ...) ML99_PRIV_REC_NEXT(953, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_953(choice, ...) ML99_PRIV_REC_NEXT(954, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_954(choice, ...) ML99_PRIV_REC_NEXT(955, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_955(choice, ...) ML99_PRIV_REC_NEXT(956, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_956(choice, ...) ML99_PRIV_REC_NEXT(957, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_957(choice, ...) ML99_PRIV_REC_NEXT(958, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_958(choice, ...) ML99_PRIV_REC_NEXT(959, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_959(choice, ...) ML99_PRIV_REC_NEXT(960, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_960(choice, ...) ML99_PRIV_REC_NEXT(961, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_961(choice, ...) ML99_PRIV_REC_NEXT(962, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_962(choice, ...) ML99_PRIV_REC_NEXT(963, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_963(choice, ...) ML99_PRIV_REC_NEXT(964, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_964(choice, ...) ML99_PRIV_REC_NEXT(965, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_965(choice, ...) ML99_PRIV_REC_NEXT(966, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_966(choice, ...) ML99_PRIV_REC_NEXT(967, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_967(choice, ...) ML99_PRIV_REC_NEXT(968, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_968(choice, ...) ML99_PRIV_REC_NEXT(969, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_969(choice, ...) ML99_PRIV_REC_NEXT(970, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_970(choice, ...) ML99_PRIV_REC_NEXT(971, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_971(choice, ...) ML99_PRIV_REC_NEXT(972, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_972(choice, ...) ML99_PRIV_REC_NEXT(973, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_973(choice, ...) ML99_PRIV_REC_NEXT(974, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_974(choice, ...) ML99_PRIV_REC_NEXT(975, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_975(choice, ...) ML99_PRIV_REC_NEXT(976, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_976(choice, ...) ML99_PRIV_REC_NEXT(977, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_977(choice, ...) ML99_PRIV_REC_NEXT(978, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_978(choice, ...) ML99_PRIV_REC_NEXT(979, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_979(choice, ...) ML99_PRIV_REC_NEXT(980, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_980(choice, ...) ML99_PRIV_REC_NEXT(981, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_981(choice, ...) ML99_PRIV_REC_NEXT(982, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_982(choice, ...) ML99_PRIV_REC_NEXT(983, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_983(choice, ...) ML99_PRIV_REC_NEXT(984, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_984(choice, ...) ML99_PRIV_REC_NEXT(985, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_985(choice, ...) ML99_PRIV_REC_NEXT(986, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_986(choice, ...) ML99_PRIV_REC_NEXT(987, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_987(choice, ...) ML99_PRIV_REC_NEXT(988, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_988(choice, ...) ML99_PRIV_REC_NEXT(989, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_989(choice, ...) ML99_PRIV_REC_NEXT(990, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_990(choice, ...) ML99_PRIV_REC_NEXT(991, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_991(choice, ...) ML99_PRIV_REC_NEXT(992, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_992(choice, ...) ML99_PRIV_REC_NEXT(993, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_993(choice, ...) ML99_PRIV_REC_NEXT(994, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_994(choice, ...) ML99_PRIV_REC_NEXT(995, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_995(choice, ...) ML99_PRIV_REC_NEXT(996, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_996(choice, ...) ML99_PRIV_REC_NEXT(997, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_997(choice, ...) ML99_PRIV_REC_NEXT(998, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_998(choice, ...) ML99_PRIV_REC_NEXT(999, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_999(choice, ...) ML99_PRIV_REC_NEXT(1000, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1000(choice, ...) ML99_PRIV_REC_NEXT(1001, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1001(choice, ...) ML99_PRIV_REC_NEXT(1002, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1002(choice, ...) ML99_PRIV_REC_NEXT(1003, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1003(choice, ...) ML99_PRIV_REC_NEXT(1004, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1004(choice, ...) ML99_PRIV_REC_NEXT(1005, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1005(choice, ...) ML99_PRIV_REC_NEXT(1006, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1006(choice, ...) ML99_PRIV_REC_NEXT(1007, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1007(choice, ...) ML99_PRIV_REC_NEXT(1008, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1008(choice, ...) ML99_PRIV_REC_NEXT(1009, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1009(choice, ...) ML99_PRIV_REC_NEXT(1010, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1010(choice, ...) ML99_PRIV_REC_NEXT(1011, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1011(choice, ...) ML99_PRIV_REC_NEXT(1012, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1012(choice, ...) ML99_PRIV_REC_NEXT(1013, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1013(choice, ...) ML99_PRIV_REC_NEXT(1014, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1014(choice, ...) ML99_PRIV_REC_NEXT(1015, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1015(choice, ...) ML99_PRIV_REC_NEXT(1016, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1016(choice, ...) ML99_PRIV_REC_NEXT(1017, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1017(choice, ...) ML99_PRIV_REC_NEXT(1018, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1018(choice, ...) ML99_PRIV_REC_NEXT(1019, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1019(choice, ...) ML99_PRIV_REC_NEXT(1020, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1020(choice, ...) ML99_PRIV_REC_NEXT(1021, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1021(choice, ...) ML99_PRIV_REC_NEXT(1022, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1022(choice, ...) ML99_PRIV_REC_NEXT(1023, choice)(__VA_ARGS__)
+#define ML99_PRIV_REC_1023 ML99_PRIV_REC_DEFER(ML99_PRIV_REC_0_HOOK)()
+
+#define ML99_PRIV_REC_0_HOOK() ML99_PRIV_REC_0
+
+#endif // ML99_EVAL_REC_H
diff --git a/test/external/metalang99/include/metalang99/eval/syntax_checker.h b/test/external/metalang99/include/metalang99/eval/syntax_checker.h
new file mode 100644
index 0000000..0f87bef
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/eval/syntax_checker.h
@@ -0,0 +1,42 @@
+#ifndef ML99_EVAL_SYNTAX_CHECKER_H
+#define ML99_EVAL_SYNTAX_CHECKER_H
+
+#include <metalang99/priv/bool.h>
+#include <metalang99/priv/compiler_specific.h>
+#include <metalang99/priv/tuple.h>
+#include <metalang99/priv/util.h>
+
+#include <metalang99/eval/rec.h>
+
+#define ML99_PRIV_CHECK_TERM(term, default) \
+ ML99_PRIV_IF(ML99_PRIV_IS_UNTUPLE(term), ML99_PRIV_EMIT_SYNTAX_ERROR, default)
+
+// clang-format off
+#define ML99_PRIV_EMIT_SYNTAX_ERROR(term) \
+ ML99_PRIV_REC_CONTINUE(ML99_PRIV_REC_STOP)((~), ML99_PRIV_SYNTAX_ERROR(term)) \
+ /* Consume arguments passed to ML99_PRIV_TERM_MATCH, see eval.h. */ \
+ ML99_PRIV_EMPTY
+// clang-format on
+
+#define ML99_PRIV_SYNTAX_ERROR(invalid_term) \
+ ML99_PRIV_CAT(ML99_PRIV_SYNTAX_ERROR_, ML99_PRIV_IS_DOUBLE_TUPLE_BEGINNING(invalid_term)) \
+ (invalid_term)
+
+#ifdef ML99_PRIV_EMIT_ERROR
+
+#define ML99_PRIV_SYNTAX_ERROR_0(invalid_term) \
+ ML99_PRIV_EMIT_ERROR("invalid term `" #invalid_term "`");
+#define ML99_PRIV_SYNTAX_ERROR_1(invalid_term) \
+ ML99_PRIV_EMIT_ERROR("invalid term `" #invalid_term "`, did you miss a comma?");
+
+#else
+
+// clang-format off
+#define ML99_PRIV_SYNTAX_ERROR_0(invalid_term) !"Metalang99 syntax error": {invalid_term}
+#define ML99_PRIV_SYNTAX_ERROR_1(invalid_term) \
+ !"Metalang99 syntax error (did you miss a comma?)": {invalid_term}
+// clang-format on
+
+#endif
+
+#endif // ML99_EVAL_SYNTAX_CHECKER_H
diff --git a/test/external/metalang99/include/metalang99/gen.h b/test/external/metalang99/include/metalang99/gen.h
new file mode 100644
index 0000000..dbb7ca8
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/gen.h
@@ -0,0 +1,407 @@
+/**
+ * @file
+ * Support for C language constructions.
+ *
+ * Some decent usage examples can be found in
+ * [datatype99/examples/derive](https://github.com/hirrolot/datatype99/tree/master/examples/derive).
+ */
+
+#ifndef ML99_GEN_H
+#define ML99_GEN_H
+
+#include <metalang99/priv/bool.h>
+
+#include <metalang99/choice.h>
+#include <metalang99/lang.h>
+#include <metalang99/list.h>
+#include <metalang99/nat.h>
+#include <metalang99/tuple.h>
+#include <metalang99/variadics.h>
+
+#include <metalang99/stmt.h> // For backwards compatibility.
+#include <metalang99/util.h> // For backwards compatibility: ML99_GEN_SYM, ML99_TRAILING_SEMICOLON.
+
+/**
+ * Puts a semicolon after provided arguments.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // int x = 5;
+ * ML99_semicoloned(v(int x = 5))
+ * @endcode
+ */
+#define ML99_semicoloned(...) ML99_call(ML99_semicoloned, __VA_ARGS__)
+
+/**
+ * Puts provided arguments into braces.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // { int a, b, c; }
+ * ML99_braced(v(int a, b, c;))
+ * @endcode
+ */
+#define ML99_braced(...) ML99_call(ML99_braced, __VA_ARGS__)
+
+/**
+ * Generates an assignment of provided variadic arguments to @p lhs.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // x = 5, 6, 7
+ * ML99_assign(v(x), v(5, 6, 7))
+ * @endcode
+ */
+#define ML99_assign(lhs, ...) ML99_call(ML99_assign, lhs, __VA_ARGS__)
+
+/**
+ * A shortcut for `ML99_assign(lhs, ML99_braced(...))`.
+ */
+#define ML99_assignInitializerList(lhs, ...) ML99_call(ML99_assignInitializerList, lhs, __VA_ARGS__)
+
+/**
+ * A shortcut for `ML99_semicoloned(ML99_assign(lhs, ...))`.
+ */
+#define ML99_assignStmt(lhs, ...) ML99_call(ML99_assignStmt, lhs, __VA_ARGS__)
+
+/**
+ * A shortcut for `ML99_assignStmt(lhs, ML99_braced(...))`.
+ */
+#define ML99_assignInitializerListStmt(lhs, ...) \
+ ML99_call(ML99_assignInitializerListStmt, lhs, __VA_ARGS__)
+
+/**
+ * Generates a function/macro invocation.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // If you are on C11.
+ * ML99_invoke(v(_Static_assert), v(1 == 1, "Must be true"))
+ * @endcode
+ */
+#define ML99_invoke(f, ...) ML99_call(ML99_invoke, f, __VA_ARGS__)
+
+/**
+ * A shortcut for `ML99_semicoloned(ML99_invoke(f, ...))`.
+ */
+#define ML99_invokeStmt(f, ...) ML99_call(ML99_invokeStmt, f, __VA_ARGS__)
+
+/**
+ * Generates `prefix { code }`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // if (1 == 1) {
+ * // printf("x = %d\n", x);
+ * // }
+ * ML99_prefixedBlock(v(if (1 == 1)), v(printf("x = %d\n", x);))
+ * @endcode
+ */
+#define ML99_prefixedBlock(prefix, ...) ML99_call(ML99_prefixedBlock, prefix, __VA_ARGS__)
+
+/**
+ * Generates a type definition.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // typedef struct { int x, y; } Point;
+ * ML99_typedef(v(Point), v(struct { int x, y; }))
+ * @endcode
+ */
+#define ML99_typedef(ident, ...) ML99_call(ML99_typedef, ident, __VA_ARGS__)
+
+/**
+ * Generates a C structure.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // struct Point { int x, y; }
+ * ML99_struct(v(Point), v(int x, y;))
+ * @endcode
+ */
+#define ML99_struct(ident, ...) ML99_call(ML99_struct, ident, __VA_ARGS__)
+
+/**
+ * Generates an anonymous C structure.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // struct { int x, y; }
+ * ML99_struct(v(int x, y;))
+ * @endcode
+ */
+#define ML99_anonStruct(...) ML99_call(ML99_anonStruct, __VA_ARGS__)
+
+/**
+ * The same as #ML99_struct but generates a union.
+ */
+#define ML99_union(ident, ...) ML99_call(ML99_union, ident, __VA_ARGS__)
+
+/**
+ * The same as #ML99_anonStruct but generates a union.
+ */
+#define ML99_anonUnion(...) ML99_call(ML99_anonUnion, __VA_ARGS__)
+
+/**
+ * The same as #ML99_struct but generates an enumeration.
+ */
+#define ML99_enum(ident, ...) ML99_call(ML99_enum, ident, __VA_ARGS__)
+
+/**
+ * The same as #ML99_anonStruct but generates an enumeration.
+ */
+#define ML99_anonEnum(...) ML99_call(ML99_anonEnum, __VA_ARGS__)
+
+/**
+ * Generates a function pointer.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // int (*add)(int x, int y)
+ * ML99_fnPtr(v(int), v(add), v(int x), v(int y))
+ *
+ * // const char *(*title)(void)
+ * ML99_fnPtr(v(const char *), v(title), v(void))
+ * @endcode
+ */
+#define ML99_fnPtr(ret_ty, name, ...) ML99_call(ML99_fnPtr, ret_ty, name, __VA_ARGS__)
+
+/**
+ * A shortcut for `ML99_semicoloned(ML99_fnPtr(ret_ty, name, ...))`.
+ */
+#define ML99_fnPtrStmt(ret_ty, name, ...) ML99_call(ML99_fnPtrStmt, ret_ty, name, __VA_ARGS__)
+
+/**
+ * Pastes provided arguments @p n times.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // ~ ~ ~ ~ ~
+ * ML99_times(v(5), v(~))
+ * @endcode
+ */
+#define ML99_times(n, ...) ML99_call(ML99_times, n, __VA_ARGS__)
+
+/**
+ * Invokes @p f @p n times, providing an iteration index each time.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ * #include <metalang99/util.h>
+ *
+ * // _0 _1 _2
+ * ML99_repeat(v(3), ML99_appl(v(ML99_cat), v(_)))
+ * @endcode
+ */
+#define ML99_repeat(n, f) ML99_call(ML99_repeat, n, f)
+
+/**
+ * Generates \f$(T_0 \ \_0, ..., T_n \ \_n)\f$.
+ *
+ * If @p type_list is empty, this macro results in `(void)`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // (int _0, long long _1, const char * _2)
+ * ML99_indexedParams(ML99_list(v(int, long long, const char *)))
+ *
+ * // (void)
+ * ML99_indexedParams(ML99_nil())
+ * @endcode
+ */
+#define ML99_indexedParams(type_list) ML99_call(ML99_indexedParams, type_list)
+
+/**
+ * Generates \f$T_0 \ \_0; ...; T_n \ \_n\f$.
+ *
+ * If @p type_list is empty, this macro results in emptiness.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // int _0; long long _1; const char * _2;
+ * ML99_indexedFields(ML99_list(v(int, long long, const char *)))
+ *
+ * // ML99_empty()
+ * ML99_indexedFields(ML99_nil())
+ * @endcode
+ */
+#define ML99_indexedFields(type_list) ML99_call(ML99_indexedFields, type_list)
+
+/**
+ * Generates \f$\{ \_0, ..., \_{n - 1} \}\f$.
+ *
+ * If @p n is 0, this macro results in `{ 0 }`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // { _0, _1, _2 }
+ * ML99_indexedInitializerList(v(3))
+ *
+ * // { 0 }
+ * ML99_indexedInitializerList(v(0))
+ * @endcode
+ */
+#define ML99_indexedInitializerList(n) ML99_call(ML99_indexedInitializerList, n)
+
+/**
+ * Generates \f$\_0, ..., \_{n - 1}\f$.
+ *
+ * If @p n is 0, this macro results in emptiness.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/gen.h>
+ *
+ * // _0, _1, _2
+ * ML99_indexedArgs(v(3))
+ *
+ * // ML99_empty()
+ * ML99_indexedArgs(v(0))
+ * @endcode
+ */
+#define ML99_indexedArgs(n) ML99_call(ML99_indexedArgs, n)
+
+#ifndef DOXYGEN_IGNORE
+
+#define ML99_semicoloned_IMPL(...) v(__VA_ARGS__;)
+#define ML99_braced_IMPL(...) v({__VA_ARGS__})
+#define ML99_assign_IMPL(lhs, ...) v(lhs = __VA_ARGS__)
+#define ML99_assignStmt_IMPL(lhs, ...) v(lhs = __VA_ARGS__;)
+#define ML99_assignInitializerList_IMPL(lhs, ...) v(lhs = {__VA_ARGS__})
+#define ML99_assignInitializerListStmt_IMPL(lhs, ...) v(lhs = {__VA_ARGS__};)
+#define ML99_invoke_IMPL(f, ...) v(f(__VA_ARGS__))
+#define ML99_invokeStmt_IMPL(f, ...) v(f(__VA_ARGS__);)
+#define ML99_typedef_IMPL(ident, ...) v(typedef __VA_ARGS__ ident;)
+#define ML99_fnPtr_IMPL(ret_ty, name, ...) v(ret_ty (*name)(__VA_ARGS__))
+#define ML99_fnPtrStmt_IMPL(ret_ty, name, ...) v(ret_ty (*name)(__VA_ARGS__);)
+
+// clang-format off
+#define ML99_prefixedBlock_IMPL(prefix, ...) v(prefix {__VA_ARGS__})
+#define ML99_struct_IMPL(ident, ...) v(struct ident {__VA_ARGS__})
+#define ML99_anonStruct_IMPL(...) v(struct {__VA_ARGS__})
+#define ML99_union_IMPL(ident, ...) v(union ident {__VA_ARGS__})
+#define ML99_anonUnion_IMPL(...) v(union {__VA_ARGS__})
+#define ML99_enum_IMPL(ident, ...) v(enum ident {__VA_ARGS__})
+#define ML99_anonEnum_IMPL(...) v(enum {__VA_ARGS__})
+// clang-format on
+
+#define ML99_times_IMPL(n, ...) ML99_natMatchWithArgs_IMPL(n, ML99_PRIV_times_, __VA_ARGS__)
+#define ML99_PRIV_times_Z_IMPL ML99_empty_IMPL
+#define ML99_PRIV_times_S_IMPL(i, ...) ML99_TERMS(v(__VA_ARGS__), ML99_times_IMPL(i, __VA_ARGS__))
+
+#define ML99_repeat_IMPL(n, f) ML99_natMatchWithArgs_IMPL(n, ML99_PRIV_repeat_, f)
+#define ML99_PRIV_repeat_Z_IMPL ML99_empty_IMPL
+#define ML99_PRIV_repeat_S_IMPL(i, f) ML99_TERMS(ML99_repeat_IMPL(i, f), ML99_appl_IMPL(f, i))
+
+// ML99_indexedParams_IMPL {
+
+#define ML99_indexedParams_IMPL(type_list) \
+ ML99_tuple(ML99_PRIV_IF( \
+ ML99_IS_NIL(type_list), \
+ v(void), \
+ ML99_variadicsTail(ML99_PRIV_indexedParamsAux_IMPL(type_list, 0))))
+
+#define ML99_PRIV_indexedParamsAux_IMPL(type_list, i) \
+ ML99_matchWithArgs_IMPL(type_list, ML99_PRIV_indexedParams_, i)
+#define ML99_PRIV_indexedParams_nil_IMPL ML99_empty_IMPL
+#define ML99_PRIV_indexedParams_cons_IMPL(x, xs, i) \
+ ML99_TERMS(v(, x _##i), ML99_PRIV_indexedParamsAux_IMPL(xs, ML99_INC(i)))
+// } (ML99_indexedParams_IMPL)
+
+// ML99_indexedFields_IMPL {
+
+#define ML99_indexedFields_IMPL(type_list) ML99_PRIV_indexedFieldsAux_IMPL(type_list, 0)
+
+#define ML99_PRIV_indexedFieldsAux_IMPL(type_list, i) \
+ ML99_matchWithArgs_IMPL(type_list, ML99_PRIV_indexedFields_, i)
+#define ML99_PRIV_indexedFields_nil_IMPL ML99_empty_IMPL
+#define ML99_PRIV_indexedFields_cons_IMPL(x, xs, i) \
+ ML99_TERMS(v(x _##i;), ML99_PRIV_indexedFieldsAux_IMPL(xs, ML99_INC(i)))
+// } (ML99_indexedFields_IMPL)
+
+#define ML99_indexedInitializerList_IMPL(n) ML99_braced(ML99_PRIV_INDEXED_ITEMS(n, v(0)))
+#define ML99_indexedArgs_IMPL(n) ML99_PRIV_INDEXED_ITEMS(n, v(ML99_EMPTY()))
+
+#define ML99_PRIV_INDEXED_ITEMS(n, empty_case) \
+ ML99_PRIV_IF( \
+ ML99_NAT_EQ(n, 0), \
+ empty_case, \
+ ML99_variadicsTail(ML99_repeat_IMPL(n, ML99_PRIV_indexedItem)))
+
+#define ML99_PRIV_indexedItem_IMPL(i) v(, _##i)
+
+// Arity specifiers {
+
+#define ML99_semicoloned_ARITY 1
+#define ML99_braced_ARITY 1
+#define ML99_assign_ARITY 2
+#define ML99_assignStmt_ARITY 2
+#define ML99_assignInitializerList_ARITY 2
+#define ML99_assignInitializerListStmt_ARITY 2
+#define ML99_invoke_ARITY 2
+#define ML99_invokeStmt_ARITY 2
+#define ML99_prefixedBlock_ARITY 2
+#define ML99_typedef_ARITY 2
+#define ML99_struct_ARITY 2
+#define ML99_anonStruct_ARITY 1
+#define ML99_union_ARITY 2
+#define ML99_anonUnion_ARITY 1
+#define ML99_enum_ARITY 2
+#define ML99_anonEnum_ARITY 1
+#define ML99_fnPtr_ARITY 3
+#define ML99_fnPtrStmt_ARITY 3
+#define ML99_repeat_ARITY 2
+#define ML99_times_ARITY 2
+#define ML99_indexedParams_ARITY 1
+#define ML99_indexedFields_ARITY 1
+#define ML99_indexedInitializerList_ARITY 1
+#define ML99_indexedArgs_ARITY 1
+
+#define ML99_PRIV_indexedItem_ARITY 1
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_GEN_H
diff --git a/test/external/metalang99/include/metalang99/ident.h b/test/external/metalang99/include/metalang99/ident.h
new file mode 100644
index 0000000..f6bb67a
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/ident.h
@@ -0,0 +1,429 @@
+/**
+ * @file
+ * Identifiers: `[a-zA-Z0-9_]+`.
+ *
+ * An identifier is a sequence of characters. A character is one of:
+ *
+ * - digits (`0123456789`),
+ * - lowercase letters (`abcdefghijklmnopqrstuvwxyz`),
+ * - uppercase letters (`ABCDEFGHIJKLMNOPQRSTUVWXYZ`),
+ * - the underscore character (`_`).
+ *
+ * For example, here are identifiers: `_ak39A`, `192_iAjP_2`, `r9`. But these are **not**
+ * identifiers: `~18nA`, `o78*`, `3i#^hdd`.
+ */
+
+#ifndef ML99_IDENT_H
+#define ML99_IDENT_H
+
+#include <metalang99/priv/bool.h>
+#include <metalang99/priv/tuple.h>
+#include <metalang99/priv/util.h>
+
+#include <metalang99/lang.h>
+
+/**
+ * Tells whether @p ident belongs to a set of identifiers defined by @p prefix.
+ *
+ * If `ML99_cat(prefix, ident)` exists, it must be an object-like macro which expands to `()`. If
+ * so, `ML99_detectIdent(prefix, ident)` will expand to truth, otherwise (`ML99_cat(prefix, ident)`
+ * does **not** exist), `ML99_detectIdent(prefix, ident)` will expand to falsehood.
+ *
+ * # Predefined detectors
+ *
+ * - `ML99_UNDERSCORE_DETECTOR` detects the underscore character (`_`).
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/ident.h>
+ *
+ * #define FOO_x ()
+ * #define FOO_y ()
+ *
+ * // 1
+ * ML99_detectIdent(v(FOO_), v(x))
+ *
+ * // 1
+ * ML99_detectIdent(v(FOO_), v(y))
+ *
+ * // 0
+ * ML99_detectIdent(v(FOO_), v(z))
+ *
+ * // 1
+ * ML99_detectIdent(v(ML99_UNDERSCORE_DETECTOR), v(_))
+ * @endcode
+ */
+#define ML99_detectIdent(prefix, ident) ML99_call(ML99_detectIdent, prefix, ident)
+
+/**
+ * Compares two identifiers @p x and @p y for equality.
+ *
+ * This macro is a shortcut to `ML99_detectIdent(ML99_cat3(prefix, x, v(_)), y)`.
+ *
+ * # Predefined detectors
+ *
+ * - `ML99_C_KEYWORD_DETECTOR` detects all the [C11
+ * keywords](https://en.cppreference.com/w/c/keyword).
+ * - `ML99_LOWERCASE_DETECTOR` detects lowercase letters (`abcdefghijklmnopqrstuvwxyz`).
+ * - `ML99_UPPERCASE_DETECTOR` detects uppercase letters (`ABCDEFGHIJKLMNOPQRSTUVWXYZ`).
+ * - `ML99_DIGIT_DETECTOR` detects digits (`0123456789`).
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/ident.h>
+ *
+ * #define FOO_x_x ()
+ * #define FOO_y_y ()
+ *
+ * // 1
+ * ML99_identEq(v(FOO_), v(x), v(x))
+ *
+ * // 1
+ * ML99_identEq(v(FOO_), v(y), v(y))
+ *
+ * // 0
+ * ML99_identEq(v(FOO_), v(x), v(y))
+ *
+ * // 1
+ * ML99_identEq(v(ML99_C_KEYWORD_DETECTOR), v(while), v(while))
+ * ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(x), v(x))
+ * ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(X), v(X))
+ * ML99_identEq(v(ML99_DIGIT_DETECTOR), v(5), v(5))
+ * @endcode
+ */
+#define ML99_identEq(prefix, x, y) ML99_call(ML99_identEq, prefix, x, y)
+
+/**
+ * Compares two characters @p x and @p y for equality.
+ *
+ * @p x and @p y can be any identifiers, though this function evaluates to true only for characters.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/ident.h>
+ *
+ * // 1
+ * ML99_charEq(v(t), v(t))
+ *
+ * // 0
+ * ML99_charEq(v(9), v(A))
+ *
+ * // 0
+ * ML99_charEq(v(9), v(abcd))
+ * @endcode
+ */
+#define ML99_charEq(x, y) ML99_call(ML99_charEq, x, y)
+
+/**
+ * Tells whether the identifier @p x is a lowercase letter.
+ */
+#define ML99_isLowercase(x) ML99_call(ML99_isLowercase, x)
+
+/**
+ * Tells whether the identifier @p x is an uppercase letter.
+ */
+#define ML99_isUppercase(x) ML99_call(ML99_isUppercase, x)
+
+/**
+ * Tells whether the identifier @p x is a digit.
+ */
+#define ML99_isDigit(x) ML99_call(ML99_isDigit, x)
+
+/**
+ * Tells whether the identifier @p x is a character.
+ */
+#define ML99_isChar(x) ML99_call(ML99_isChar, x)
+
+/**
+ * Converts the Metalang99 character @p x to a C character literal.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang/ident.h>
+ *
+ * // 't'
+ * ML99_charLit(v(t))
+ *
+ * // '9'
+ * ML99_charLit(v(9))
+ *
+ * // '_'
+ * ML99_charLit(v(_))
+ * @endcode
+ *
+ * @note The inverse of this function is impossible, i.e., you cannot get `q` from `'q'`.
+ */
+#define ML99_charLit(x) ML99_call(ML99_charLit, x)
+
+/**
+ * Expands to all comma-separated lowercase letters.
+ *
+ * This macro consumes all arguments.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/ident.h>
+ * #include <metalang99/variadics.h>
+ *
+ * #define F_IMPL(x) v([x])
+ * #define F_ARITY 1
+ *
+ * // [a] [b] [c] ... [x] [y] [z]
+ * ML99_variadicsForEach(v(F), v(ML99_LOWERCASE_CHARS()))
+ * @endcode
+ */
+#define ML99_LOWERCASE_CHARS(...) \
+ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z
+
+/**
+ * The same as #ML99_LOWERCASE_CHARS but for uppercase characters.
+ */
+#define ML99_UPPERCASE_CHARS(...) \
+ A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
+
+/**
+ * The same as #ML99_LOWERCASE_CHARS but for digits.
+ */
+#define ML99_DIGITS(...) 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+
+#define ML99_DETECT_IDENT(prefix, ident) ML99_PRIV_IS_TUPLE_FAST(ML99_PRIV_CAT(prefix, ident))
+#define ML99_IDENT_EQ(prefix, x, y) ML99_DETECT_IDENT(ML99_PRIV_CAT3(prefix, x, _), y)
+
+#define ML99_CHAR_EQ(x, y) \
+ ML99_PRIV_IF( \
+ ML99_DETECT_IDENT(ML99_UNDERSCORE_DETECTOR, x), \
+ ML99_DETECT_IDENT(ML99_UNDERSCORE_DETECTOR, y), \
+ ML99_PRIV_OR3( \
+ ML99_IDENT_EQ(ML99_LOWERCASE_DETECTOR, x, y), \
+ ML99_IDENT_EQ(ML99_UPPERCASE_DETECTOR, x, y), \
+ ML99_IDENT_EQ(ML99_DIGIT_DETECTOR, x, y)))
+
+#define ML99_IS_LOWERCASE(x) ML99_IDENT_EQ(ML99_LOWERCASE_DETECTOR, x, x)
+#define ML99_IS_UPPERCASE(x) ML99_IDENT_EQ(ML99_UPPERCASE_DETECTOR, x, x)
+#define ML99_IS_DIGIT(x) ML99_IDENT_EQ(ML99_DIGIT_DETECTOR, x, x)
+
+#define ML99_IS_CHAR(x) \
+ ML99_PRIV_OR4( \
+ ML99_IS_LOWERCASE(x), \
+ ML99_IS_UPPERCASE(x), \
+ ML99_IS_DIGIT(x), \
+ ML99_DETECT_IDENT(ML99_UNDERSCORE_DETECTOR, x))
+
+#define ML99_CHAR_LIT(x) ML99_PRIV_CAT(ML99_PRIV_CHAR_LIT_, x)
+
+#ifndef DOXYGEN_IGNORE
+
+#define ML99_detectIdent_IMPL(prefix, ident) v(ML99_DETECT_IDENT(prefix, ident))
+#define ML99_identEq_IMPL(prefix, x, y) v(ML99_IDENT_EQ(prefix, x, y))
+#define ML99_charEq_IMPL(x, y) v(ML99_CHAR_EQ(x, y))
+#define ML99_isLowercase_IMPL(x) v(ML99_IS_LOWERCASE(x))
+#define ML99_isUppercase_IMPL(x) v(ML99_IS_UPPERCASE(x))
+#define ML99_isDigit_IMPL(x) v(ML99_IS_DIGIT(x))
+#define ML99_isChar_IMPL(x) v(ML99_IS_CHAR(x))
+#define ML99_charLit_IMPL(x) v(ML99_CHAR_LIT(x))
+
+#define ML99_UNDERSCORE_DETECTOR ML99_PRIV_UNDERSCORE_DETECTOR_
+#define ML99_C_KEYWORD_DETECTOR ML99_PRIV_C_KEYWORD_DETECTOR_
+#define ML99_LOWERCASE_DETECTOR ML99_PRIV_LOWER_DETECTOR_
+#define ML99_UPPERCASE_DETECTOR ML99_PRIV_UPPER_DETECTOR_
+#define ML99_DIGIT_DETECTOR ML99_PRIV_DIGIT_DETECTOR_
+
+#define ML99_PRIV_C_KEYWORD_DETECTOR_auto_auto ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_break_break ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_case_case ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_char_char ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_const_const ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_continue_continue ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_default_default ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_do_do ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_double_double ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_else_else ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_enum_enum ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_extern_extern ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_float_float ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_for_for ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_goto_goto ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_if_if ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_inline_inline ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_int_int ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_long_long ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_register_register ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_restrict_restrict ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_return_return ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_short_short ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_signed_signed ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_sizeof_sizeof ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_static_static ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_struct_struct ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_switch_switch ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_typedef_typedef ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_union_union ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_unsigned_unsigned ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_void_void ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_volatile_volatile ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR_while_while ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR__Alignas__Alignas ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR__Alignof__Alignof ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR__Atomic__Atomic ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR__Bool__Bool ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR__Complex__Complex ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR__Generic__Generic ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR__Imaginary__Imaginary ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR__Noreturn__Noreturn ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR__Static_assert__Static_assert ()
+#define ML99_PRIV_C_KEYWORD_DETECTOR__Thread_local__Thread_local ()
+
+#define ML99_PRIV_UNDERSCORE_DETECTOR__ ()
+
+#define ML99_PRIV_LOWER_DETECTOR_a_a ()
+#define ML99_PRIV_LOWER_DETECTOR_b_b ()
+#define ML99_PRIV_LOWER_DETECTOR_c_c ()
+#define ML99_PRIV_LOWER_DETECTOR_d_d ()
+#define ML99_PRIV_LOWER_DETECTOR_e_e ()
+#define ML99_PRIV_LOWER_DETECTOR_f_f ()
+#define ML99_PRIV_LOWER_DETECTOR_g_g ()
+#define ML99_PRIV_LOWER_DETECTOR_h_h ()
+#define ML99_PRIV_LOWER_DETECTOR_i_i ()
+#define ML99_PRIV_LOWER_DETECTOR_j_j ()
+#define ML99_PRIV_LOWER_DETECTOR_k_k ()
+#define ML99_PRIV_LOWER_DETECTOR_l_l ()
+#define ML99_PRIV_LOWER_DETECTOR_m_m ()
+#define ML99_PRIV_LOWER_DETECTOR_n_n ()
+#define ML99_PRIV_LOWER_DETECTOR_o_o ()
+#define ML99_PRIV_LOWER_DETECTOR_p_p ()
+#define ML99_PRIV_LOWER_DETECTOR_q_q ()
+#define ML99_PRIV_LOWER_DETECTOR_r_r ()
+#define ML99_PRIV_LOWER_DETECTOR_s_s ()
+#define ML99_PRIV_LOWER_DETECTOR_t_t ()
+#define ML99_PRIV_LOWER_DETECTOR_u_u ()
+#define ML99_PRIV_LOWER_DETECTOR_v_v ()
+#define ML99_PRIV_LOWER_DETECTOR_w_w ()
+#define ML99_PRIV_LOWER_DETECTOR_x_x ()
+#define ML99_PRIV_LOWER_DETECTOR_y_y ()
+#define ML99_PRIV_LOWER_DETECTOR_z_z ()
+
+#define ML99_PRIV_UPPER_DETECTOR_A_A ()
+#define ML99_PRIV_UPPER_DETECTOR_B_B ()
+#define ML99_PRIV_UPPER_DETECTOR_C_C ()
+#define ML99_PRIV_UPPER_DETECTOR_D_D ()
+#define ML99_PRIV_UPPER_DETECTOR_E_E ()
+#define ML99_PRIV_UPPER_DETECTOR_F_F ()
+#define ML99_PRIV_UPPER_DETECTOR_G_G ()
+#define ML99_PRIV_UPPER_DETECTOR_H_H ()
+#define ML99_PRIV_UPPER_DETECTOR_I_I ()
+#define ML99_PRIV_UPPER_DETECTOR_J_J ()
+#define ML99_PRIV_UPPER_DETECTOR_K_K ()
+#define ML99_PRIV_UPPER_DETECTOR_L_L ()
+#define ML99_PRIV_UPPER_DETECTOR_M_M ()
+#define ML99_PRIV_UPPER_DETECTOR_N_N ()
+#define ML99_PRIV_UPPER_DETECTOR_O_O ()
+#define ML99_PRIV_UPPER_DETECTOR_P_P ()
+#define ML99_PRIV_UPPER_DETECTOR_Q_Q ()
+#define ML99_PRIV_UPPER_DETECTOR_R_R ()
+#define ML99_PRIV_UPPER_DETECTOR_S_S ()
+#define ML99_PRIV_UPPER_DETECTOR_T_T ()
+#define ML99_PRIV_UPPER_DETECTOR_U_U ()
+#define ML99_PRIV_UPPER_DETECTOR_V_V ()
+#define ML99_PRIV_UPPER_DETECTOR_W_W ()
+#define ML99_PRIV_UPPER_DETECTOR_X_X ()
+#define ML99_PRIV_UPPER_DETECTOR_Y_Y ()
+#define ML99_PRIV_UPPER_DETECTOR_Z_Z ()
+
+#define ML99_PRIV_DIGIT_DETECTOR_0_0 ()
+#define ML99_PRIV_DIGIT_DETECTOR_1_1 ()
+#define ML99_PRIV_DIGIT_DETECTOR_2_2 ()
+#define ML99_PRIV_DIGIT_DETECTOR_3_3 ()
+#define ML99_PRIV_DIGIT_DETECTOR_4_4 ()
+#define ML99_PRIV_DIGIT_DETECTOR_5_5 ()
+#define ML99_PRIV_DIGIT_DETECTOR_6_6 ()
+#define ML99_PRIV_DIGIT_DETECTOR_7_7 ()
+#define ML99_PRIV_DIGIT_DETECTOR_8_8 ()
+#define ML99_PRIV_DIGIT_DETECTOR_9_9 ()
+
+#define ML99_PRIV_CHAR_LIT_a 'a'
+#define ML99_PRIV_CHAR_LIT_b 'b'
+#define ML99_PRIV_CHAR_LIT_c 'c'
+#define ML99_PRIV_CHAR_LIT_d 'd'
+#define ML99_PRIV_CHAR_LIT_e 'e'
+#define ML99_PRIV_CHAR_LIT_f 'f'
+#define ML99_PRIV_CHAR_LIT_g 'g'
+#define ML99_PRIV_CHAR_LIT_h 'h'
+#define ML99_PRIV_CHAR_LIT_i 'i'
+#define ML99_PRIV_CHAR_LIT_j 'j'
+#define ML99_PRIV_CHAR_LIT_k 'k'
+#define ML99_PRIV_CHAR_LIT_l 'l'
+#define ML99_PRIV_CHAR_LIT_m 'm'
+#define ML99_PRIV_CHAR_LIT_n 'n'
+#define ML99_PRIV_CHAR_LIT_o 'o'
+#define ML99_PRIV_CHAR_LIT_p 'p'
+#define ML99_PRIV_CHAR_LIT_q 'q'
+#define ML99_PRIV_CHAR_LIT_r 'r'
+#define ML99_PRIV_CHAR_LIT_s 's'
+#define ML99_PRIV_CHAR_LIT_t 't'
+#define ML99_PRIV_CHAR_LIT_u 'u'
+#define ML99_PRIV_CHAR_LIT_v 'v'
+#define ML99_PRIV_CHAR_LIT_w 'w'
+#define ML99_PRIV_CHAR_LIT_x 'x'
+#define ML99_PRIV_CHAR_LIT_y 'y'
+#define ML99_PRIV_CHAR_LIT_z 'z'
+
+#define ML99_PRIV_CHAR_LIT_A 'A'
+#define ML99_PRIV_CHAR_LIT_B 'B'
+#define ML99_PRIV_CHAR_LIT_C 'C'
+#define ML99_PRIV_CHAR_LIT_D 'D'
+#define ML99_PRIV_CHAR_LIT_E 'E'
+#define ML99_PRIV_CHAR_LIT_F 'F'
+#define ML99_PRIV_CHAR_LIT_G 'G'
+#define ML99_PRIV_CHAR_LIT_H 'H'
+#define ML99_PRIV_CHAR_LIT_I 'I'
+#define ML99_PRIV_CHAR_LIT_J 'J'
+#define ML99_PRIV_CHAR_LIT_K 'K'
+#define ML99_PRIV_CHAR_LIT_L 'L'
+#define ML99_PRIV_CHAR_LIT_M 'M'
+#define ML99_PRIV_CHAR_LIT_N 'N'
+#define ML99_PRIV_CHAR_LIT_O 'O'
+#define ML99_PRIV_CHAR_LIT_P 'P'
+#define ML99_PRIV_CHAR_LIT_Q 'Q'
+#define ML99_PRIV_CHAR_LIT_R 'R'
+#define ML99_PRIV_CHAR_LIT_S 'S'
+#define ML99_PRIV_CHAR_LIT_T 'T'
+#define ML99_PRIV_CHAR_LIT_U 'U'
+#define ML99_PRIV_CHAR_LIT_V 'V'
+#define ML99_PRIV_CHAR_LIT_W 'W'
+#define ML99_PRIV_CHAR_LIT_X 'X'
+#define ML99_PRIV_CHAR_LIT_Y 'Y'
+#define ML99_PRIV_CHAR_LIT_Z 'Z'
+
+#define ML99_PRIV_CHAR_LIT_0 '0'
+#define ML99_PRIV_CHAR_LIT_1 '1'
+#define ML99_PRIV_CHAR_LIT_2 '2'
+#define ML99_PRIV_CHAR_LIT_3 '3'
+#define ML99_PRIV_CHAR_LIT_4 '4'
+#define ML99_PRIV_CHAR_LIT_5 '5'
+#define ML99_PRIV_CHAR_LIT_6 '6'
+#define ML99_PRIV_CHAR_LIT_7 '7'
+#define ML99_PRIV_CHAR_LIT_8 '8'
+#define ML99_PRIV_CHAR_LIT_9 '9'
+
+#define ML99_PRIV_CHAR_LIT__ '_'
+
+// Arity specifiers {
+
+#define ML99_detectIdent_ARITY 2
+#define ML99_identEq_ARITY 3
+#define ML99_charEq_ARITY 2
+#define ML99_isLowercase_ARITY 1
+#define ML99_isUppercase_ARITY 1
+#define ML99_isDigit_ARITY 1
+#define ML99_isChar_ARITY 1
+#define ML99_charLit_ARITY 1
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_IDENT_H
diff --git a/test/external/metalang99/include/metalang99/lang.h b/test/external/metalang99/include/metalang99/lang.h
new file mode 100644
index 0000000..299f8d7
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/lang.h
@@ -0,0 +1,246 @@
+/**
+ * @file
+ * The core metalanguage.
+ */
+
+#ifndef ML99_LANG_H
+#define ML99_LANG_H
+
+#include <metalang99/priv/bool.h>
+#include <metalang99/priv/tuple.h>
+
+#include <metalang99/eval/eval.h>
+#include <metalang99/lang/closure.h>
+
+/**
+ * Evaluates a metaprogram.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/lang.h>
+ *
+ * #define F_IMPL(x, y) v(x + y)
+ *
+ * ML99_EVAL(v(abc ~ 123), ML99_call(F, v(1, 2)))
+ * @endcode
+ */
+#define ML99_EVAL(...) ML99_PRIV_EVAL(__VA_ARGS__)
+
+/**
+ * Invokes a metafunction with arguments.
+ */
+#define ML99_call(op, ...) \
+ (ML99_PRIV_IF(ML99_PRIV_IS_UNTUPLE_FAST(op), 0args, 0op), op, __VA_ARGS__)
+
+/**
+ * Invokes a metafunction @p ident with unevaluated arguments.
+ *
+ * It is semantically the same as `ML99_call(ident, v(...))` but performs one less reduction
+ * steps.
+ */
+#define ML99_callUneval(ident, ...) (0callUneval, ident, __VA_ARGS__)
+
+/**
+ * Applies arguments to @p f.
+ *
+ * This function implements [partial
+ * application](https://en.wikipedia.org/wiki/Partial_application): instead of invoking a
+ * metafunction with all arguments at once, you specify each argument separately. This concept
+ * allows better re-use of metafunctions by specifying some arguments immediately, and the other
+ * arguments later, even in different execution contexts (for example, see this [SO
+ * answer](https://stackoverflow.com/a/12414292/13166656)).
+ *
+ * @p f must be either a term reducing to a macro name or a term obtained via another call to
+ * #ML99_appl. If @p f is a macro name, then a macro named `<f>_ARITY` (its arity specifier)
+ * must denote how many times @p f will be applied to its arguments. (In Metalang99, an arity is an
+ * intentionally more flexible concept than just a number of parameters, see below.) Each time
+ * #ML99_appl is invoked, it accumulates provided variadic arguments and decrements the arity
+ * of @p f; when the arity of @p f is already 1, it eventually calls the initial @p f with all the
+ * accumulated arguments and provided variadic arguments.
+ *
+ * Most often, an arity specifier denotes a count of all named parameters plus 1 if a macro is
+ * variadic (all the functions in the standard library follow this pattern). However, feel free to
+ * specify arities as you wish, with regard to the aforementioned semantics; for example, you can
+ * have a macro accepting `x, y, z` with an arity specifier `2`, then you must invoke
+ * #ML99_appl exactly 2 times (either `x` + `y, z` or `x, y` + `z`). One common pattern is to
+ * match a head and a tail of variadic arguments:
+ *
+ * @code
+ * #include <metalang99/lang.h>
+ *
+ * #define F_IMPL(x, y, z, head, ...) // ...
+ * #define F_ARITY 4
+ * @endcode
+ *
+ * In this case, `x`, `y`, and `z` can be specified separately but other arguments all at once.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/lang.h>
+ *
+ * #define F_IMPL(x, y) v(x##y)
+ * #define F_ARITY 2
+ *
+ * // ab
+ * ML99_appl(ML99_appl(v(F), v(a)), v(b))
+ * @endcode
+ *
+ * @note Currently, the maximum arity is #ML99_NAT_MAX. However, some compilers might not support
+ * more than 127 macro parameters.
+ */
+#define ML99_appl(f, ...) ML99_call(ML99_appl, f, __VA_ARGS__)
+
+/**
+ * Applies @p a and @p b to @p f.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/lang.h>
+ *
+ * #define F_IMPL(x, y) v(x##y)
+ * #define F_ARITY 2
+ *
+ * // ab
+ * ML99_appl2(v(F), v(a), v(b))
+ * @endcode
+ */
+#define ML99_appl2(f, a, b) ML99_call(ML99_appl2, f, a, b)
+
+/**
+ * Applies @p a, @p b, and @p c to @p f.
+ */
+#define ML99_appl3(f, a, b, c) ML99_call(ML99_appl3, f, a, b, c)
+
+/**
+ * Applies @p a, @p b, @p c, and @p d to @p f.
+ */
+#define ML99_appl4(f, a, b, c, d) ML99_call(ML99_appl4, f, a, b, c, d)
+
+/**
+ * Functional composition of @p f and @p g.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/lang.h>
+ *
+ * #define F_IMPL(x) v((x + 1))
+ * #define G_IMPL(x) v((x * 8))
+ *
+ * #define F_ARITY 1
+ * #define G_ARITY 1
+ *
+ * // ((3 * 8) + 1)
+ * ML99_appl(ML99_compose(v(F), v(G)), v(3))
+ * @endcode
+ */
+#define ML99_compose(f, g) ML99_call(ML99_compose, f, g)
+
+/**
+ * A value that is pasted as-is; no evaluation occurs on provided arguments.
+ */
+#define v(...) (0v, __VA_ARGS__)
+
+// clang-format off
+/**
+ * Emits a fatal error.
+ *
+ * @p f must be a macro name that has caused the error and the rest of arguments comprise the error
+ * message.
+ *
+ * #ML99_fatal interprets its variadic arguments without preprocessor expansion -- i.e., they are
+ * pasted as-is. This is intended because otherwise identifiers located in an error message may
+ * stand for other macros that will be unintentionally expanded.
+ *
+ * # Examples
+ *
+ * [`playground.c`]
+ * @code
+ * #include <metalang99/lang.h>
+ *
+ * ML99_EVAL(ML99_fatal(F, the description of your error))
+ * @endcode
+ *
+ * [`/bin/sh`]
+ * @code{.txt}
+ * 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))
+ * | ^~~~~~~~~
+ * @endcode
+ */
+#define ML99_fatal(f, ...) (0fatal, f, #__VA_ARGS__)
+// clang-format on
+
+/**
+ * Immediately aborts the interpretation with evaluated arguments.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/lang.h>
+ *
+ * #define F_IMPL(x) v(~)
+ *
+ * // 123
+ * ML99_call(F, ML99_abort(v(123)))
+ * @endcode
+ */
+#define ML99_abort(...) (0abort, __VA_ARGS__)
+
+/**
+ * A convenience macro to emphasize that your metafunction expands to more than one term.
+ *
+ * This macro just expands to provided arguments.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/lang.h>
+ *
+ * #define F_IMPL(x) ML99_TERMS(v(1), v(x), v(2))
+ * @endcode
+ */
+#define ML99_TERMS(...) __VA_ARGS__
+
+/**
+ * Delays evaluation for provided terms.
+ *
+ * `ML99_QUOTE(...)` is functionally equivalent to `v(...)`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/lang.h>
+ *
+ * #define F_IMPL(x) v(~x)
+ *
+ * #define PROG ML99_TERMS(v(1), v(2), ML99_call(F, v(7)))
+ *
+ * // The same as `PROG` pasted into a source file.
+ * ML99_EVAL(ML99_QUOTE(PROG))
+ * @endcode
+ */
+#define ML99_QUOTE(...) v(__VA_ARGS__)
+
+#ifndef DOXYGEN_IGNORE
+
+#define ML99_compose_IMPL(f, g) ML99_appl2_IMPL(ML99_PRIV_compose, f, g)
+#define ML99_PRIV_compose_IMPL(f, g, x) ML99_appl(v(f), ML99_appl_IMPL(g, x))
+
+// Arity specifiers {
+
+#define ML99_appl_ARITY 2
+#define ML99_appl2_ARITY 3
+#define ML99_appl3_ARITY 4
+#define ML99_appl4_ARITY 5
+#define ML99_compose_ARITY 2
+
+#define ML99_PRIV_compose_ARITY 3
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_LANG_H
diff --git a/test/external/metalang99/include/metalang99/lang/closure.h b/test/external/metalang99/include/metalang99/lang/closure.h
new file mode 100644
index 0000000..3812df0
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/lang/closure.h
@@ -0,0 +1,51 @@
+#ifndef ML99_LANG_CLOSURE_H
+#define ML99_LANG_CLOSURE_H
+
+#include <metalang99/priv/bool.h>
+#include <metalang99/priv/util.h>
+
+#include <metalang99/nat/dec.h>
+#include <metalang99/nat/eq.h>
+
+/*
+ * A closure has the form `(arity, f, ...)`, where `arity` is how many times `ML99_appl` can
+ * be called for this closure, and `...` denotes the closure's environment.
+ *
+ * `ML99_appl` is described by the following algorithm:
+ * - If `f` is an identifier (like `FOO`):
+ * - If `f##_ARITY` is 1, then just call this function with provided arguments.
+ * - Otherwise, return `(f##_ARITY - 1, f, provided args...)`.
+ * - Otherwise (`f` is a closure):
+ * - If `arity` is 1, then just call `f` with its environment and provided arguments.
+ * - Otherwise, return `(arity - 1, f, env..., provided args...)`.
+ *
+ * Thus, each time except the last, `ML99_appl` extends a closure's environment with new
+ * arguments; the last time, it calls `f` with its environment.
+ */
+
+#define ML99_appl_IMPL(f, ...) \
+ ML99_PRIV_IF(ML99_PRIV_IS_UNTUPLE_FAST(f), ML99_PRIV_APPL_F, ML99_PRIV_APPL_CLOSURE) \
+ (f, __VA_ARGS__)
+
+#define ML99_PRIV_APPL_F(f, ...) \
+ ML99_PRIV_IF( \
+ ML99_PRIV_NAT_EQ(f##_ARITY, 1), \
+ ML99_callUneval(f, __VA_ARGS__), \
+ v((ML99_PRIV_DEC(f##_ARITY), f, __VA_ARGS__)))
+
+#define ML99_PRIV_APPL_CLOSURE(closure, ...) \
+ ML99_PRIV_APPL_CLOSURE_AUX(ML99_PRIV_EXPAND closure, __VA_ARGS__)
+
+#define ML99_PRIV_APPL_CLOSURE_AUX(...) ML99_PRIV_APPL_CLOSURE_AUX_AUX(__VA_ARGS__)
+
+#define ML99_PRIV_APPL_CLOSURE_AUX_AUX(arity, f, ...) \
+ ML99_PRIV_IF( \
+ ML99_PRIV_NAT_EQ(arity, 1), \
+ ML99_callUneval(f, __VA_ARGS__), \
+ v((ML99_PRIV_DEC(arity), f, __VA_ARGS__)))
+
+#define ML99_appl2_IMPL(f, a, b) ML99_appl(ML99_appl_IMPL(f, a), v(b))
+#define ML99_appl3_IMPL(f, a, b, c) ML99_appl(ML99_appl2_IMPL(f, a, b), v(c))
+#define ML99_appl4_IMPL(f, a, b, c, d) ML99_appl(ML99_appl3_IMPL(f, a, b, c), v(d))
+
+#endif // ML99_LANG_CLOSURE_H
diff --git a/test/external/metalang99/include/metalang99/list.h b/test/external/metalang99/include/metalang99/list.h
new file mode 100644
index 0000000..bf62916
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/list.h
@@ -0,0 +1,1129 @@
+/**
+ * @file
+ * Cons-lists.
+ */
+
+#ifndef ML99_LIST_H
+#define ML99_LIST_H
+
+#include <metalang99/priv/bool.h>
+#include <metalang99/priv/util.h>
+
+#include <metalang99/bool.h>
+#include <metalang99/choice.h>
+#include <metalang99/nat.h>
+#include <metalang99/seq.h>
+#include <metalang99/util.h>
+#include <metalang99/variadics.h>
+
+/**
+ * Prepends @p x to @p xs.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * ML99_cons(v(1), ML99_cons(v(2), ML99_nil()))
+ * @endcode
+ */
+#define ML99_cons(x, xs) ML99_call(ML99_cons, x, xs)
+
+/**
+ * The empty list.
+ */
+#define ML99_nil(...) ML99_callUneval(ML99_nil, )
+
+/**
+ * Checks @p list for non-emptiness.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 1
+ * ML99_isCons(ML99_list(v(1, 2, 3)))
+ *
+ * // 0
+ * ML99_isCons(ML99_nil())
+ * @endcode
+ */
+#define ML99_isCons(list) ML99_call(ML99_isCons, list)
+
+/**
+ * Checks @p list for emptiness.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 0
+ * ML99_isNil(ML99_list(v(1, 2, 3)))
+ *
+ * // 1
+ * ML99_isNil(ML99_nil())
+ * @endcode
+ */
+#define ML99_isNil(list) ML99_call(ML99_isNil, list)
+
+/**
+ * Extracts the head from the non-empty list @p list.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 1
+ * ML99_listHead(ML99_list(v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_listHead(list) ML99_call(ML99_listHead, list)
+
+/**
+ * Extracts the tail from the non-empty list @p list.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 2, 3
+ * ML99_listTail(ML99_list(v(1, 2, 3)))
+ *
+ * // ML99_nil()
+ * ML99_listTail(ML99_list(v(1)))
+ * @endcode
+ */
+#define ML99_listTail(list) ML99_call(ML99_listTail, list)
+
+/**
+ * Extracts the last element from the non-empty list @p list.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 3
+ * ML99_listLast(ML99_list(v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_listLast(list) ML99_call(ML99_listLast, list)
+
+/**
+ * Extracts all the elements of the non-empty list @p list except the last one.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 1, 2
+ * ML99_listInit(ML99_list(v(1, 2, 3)))
+ *
+ * // ML99_nil()
+ * ML99_listInit(ML99_list(v(1)))
+ * @endcode
+ */
+#define ML99_listInit(list) ML99_call(ML99_listInit, list)
+
+/**
+ * Constructs a list from its arguments.
+ *
+ * At most 63 arguments are acceptable.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 1, 2, 3
+ * ML99_list(v(1, 2, 3))
+ * @endcode
+ */
+#define ML99_list(...) ML99_call(ML99_list, __VA_ARGS__)
+
+/**
+ * Constructs a list from comma-separated [tuples](tuple.html).
+ *
+ * It sequentially applies @p f to each untupled argument, thus forming the resulting list. If some
+ * argument is not a tuple, a fatal error is emitted.
+ *
+ * The result is `ML99_list(ML99_appl(f, ML99_untuple(x1)), ..., ML99_appl(f, ML99_untuple(xN)))`.
+ *
+ * Each variadic argument inherits all the preconditions of #ML99_isUntuple.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * #define F_IMPL(x, y) v(x + y)
+ * #define F_ARITY 1
+ *
+ * // ML99_list(v(1 + 2, 3 + 4, 5 + 6))
+ * ML99_listFromTuples(v(F), v((1, 2), (3, 4), (5, 6)))
+ * @endcode
+ */
+#define ML99_listFromTuples(f, ...) ML99_call(ML99_listFromTuples, f, __VA_ARGS__)
+
+/**
+ * Constructs a list from the [sequence](seq.html) @p seq.
+ *
+ * Note that @p seq items must **not** contain commas. If you want commas in items, such as `(+, -,
+ * *, /)`, consider wrapping an item in parentheses: `((+, -, *, /))`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // ML99_nil()
+ * ML99_listFromSeq(v())
+ *
+ * // ML99_list(v(1, 2, 3))
+ * ML99_listFromSeq(v((1)(2)(3)))
+ * @endcode
+ */
+#define ML99_listFromSeq(seq) ML99_call(ML99_listFromSeq, seq)
+
+/**
+ * Computes the length of @p list.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 0
+ * ML99_listLen(ML99_nil())
+ *
+ * // 3
+ * ML99_listLen(ML99_list(v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_listLen(list) ML99_call(ML99_listLen, list)
+
+/**
+ * Evaluates a metaprogram that reduces to a list, then unwraps it.
+ *
+ * It behaves the same as the composition of #ML99_EVAL and #ML99_listUnwrap.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // Literally 1 2 3
+ * ML99_LIST_EVAL(ML99_list(v(1, 2, 3)))
+ * @endcode
+ *
+ * @note This macro does not result in a Metalang99 term; it literally pastes list elements into a
+ * source file.
+ */
+#define ML99_LIST_EVAL(...) ML99_EVAL(ML99_call(ML99_listUnwrap, __VA_ARGS__))
+
+/**
+ * The same as #ML99_LIST_EVAL but intersperses a comma between list items.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * // Literally 1, 2, 3
+ * ML99_LIST_EVAL_COMMA_SEP(ML99_list(v(1, 2, 3)))
+ * @endcode
+ *
+ * @note This macro does not result in a Metalang99 term; it literally pastes comma-separated list
+ * elements into a source file.
+ */
+#define ML99_LIST_EVAL_COMMA_SEP(...) ML99_EVAL(ML99_call(ML99_listUnwrapCommaSep, __VA_ARGS__))
+
+/**
+ * Appends the list @p other to @p list.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 1, 2, 3
+ * ML99_listAppend(ML99_list(v(1)), ML99_list(v(2, 3)))
+ * @endcode
+ */
+#define ML99_listAppend(list, other) ML99_call(ML99_listAppend, list, other)
+
+/**
+ * Appends the item @p item to @p list.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 1, 2, 3
+ * ML99_listAppendItem(v(3), ML99_list(v(1, 2)))
+ * @endcode
+ */
+#define ML99_listAppendItem(item, list) ML99_call(ML99_listAppendItem, item, list)
+
+/**
+ * Places all the items in @p list as-is.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // Literally 1 2 3
+ * ML99_listUnwrap(ML99_list(v(1, 2, 3)))
+ * @endcode
+ *
+ * @note The resulting value is still a valid Metalang99 term that need to be evaluated further.
+ * @see #ML99_LIST_EVAL
+ * @see #ML99_LIST_EVAL_COMMA_SEP
+ */
+#define ML99_listUnwrap(list) ML99_call(ML99_listUnwrap, list)
+
+/**
+ * Places all the items in @p list as-is, separated by commas.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // Literally 1, 2, 3
+ * ML99_listUnwrapCommaSep(ML99_list(v(1, 2, 3)))
+ * @endcode
+ *
+ * @note The resulting value is still a valid Metalang99 term that need to be evaluated further.
+ * @see #ML99_LIST_EVAL
+ * @see #ML99_LIST_EVAL_COMMA_SEP
+ */
+#define ML99_listUnwrapCommaSep(list) ML99_call(ML99_listUnwrapCommaSep, list)
+
+/**
+ * Reverses the order of items in @p list.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 3, 2, 1
+ * ML99_listReverse(ML99_list(v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_listReverse(list) ML99_call(ML99_listReverse, list)
+
+/**
+ * Extracts the @p i -indexed element.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 2
+ * ML99_listGet(v(1), ML99_list(v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_listGet(i, list) ML99_call(ML99_listGet, i, list)
+
+/**
+ * A right-associative fold over @p list.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * #define ABCDEFG 123
+ *
+ * // 7
+ * ML99_listFoldr(v(ML99_cat), v(7), ML99_nil())
+ *
+ * // 123
+ * ML99_listFoldr(ML99_appl(v(ML99_flip), v(ML99_cat)), v(A), ML99_list(v(G, DEF, BC)))
+ * @endcode
+ */
+#define ML99_listFoldr(f, init, list) ML99_call(ML99_listFoldr, f, init, list)
+
+/**
+ * A left-associative fold over @p list.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * #define ABCDEFG 123
+ *
+ * // 7
+ * ML99_listFoldl(v(ML99_cat), v(7), ML99_nil())
+ *
+ * // 123
+ * ML99_listFoldl(v(ML99_cat), v(A), ML99_list(v(BC, DEF, G)))
+ * @endcode
+ */
+#define ML99_listFoldl(f, init, list) ML99_call(ML99_listFoldl, f, init, list)
+
+/**
+ * The same as #ML99_listFoldl but treats the first element of @p list as the initial value.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * #define ABCDEFG 123
+ *
+ * // 123
+ * ML99_listFoldl1(v(ML99_cat), ML99_list(v(AB, CDEF, G)))
+ * @endcode
+ */
+#define ML99_listFoldl1(f, list) ML99_call(ML99_listFoldl1, f, list)
+
+/**
+ * Intersperses @p item between the items in @p list.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 1, +, 2, +, 3
+ * ML99_listIntersperse(v(+), ML99_list(v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_listIntersperse(item, list) ML99_call(ML99_listIntersperse, item, list)
+
+/**
+ * Prepends @p item to all items in @p list.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // +, 1, +, 2, +, 3
+ * ML99_listPrependToAll(v(+), ML99_list(v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_listPrependToAll(item, list) ML99_call(ML99_listPrependToAll, item, list)
+
+/**
+ * Maps all the elements in @p list with @p f.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ * #include <metalang99/nat.h>
+ *
+ * // 4, 5, 6
+ * ML99_listMap(ML99_appl(v(ML99_add), v(3)), ML99_list(v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_listMap(f, list) ML99_call(ML99_listMap, f, list)
+
+/**
+ * The same as #ML99_listMap but provides an index of an element to @p f.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * #define F_IMPL(x, i) v(x[i])
+ * #define F_ARITY 2
+ *
+ * // a[0], b[1], c[2]
+ * ML99_listMapI(v(F), ML99_list(v(a, b, c)))
+ * @endcode
+ */
+#define ML99_listMapI(f, list) ML99_call(ML99_listMapI, f, list)
+
+/**
+ * A more efficient version of `ML99_listUnwrap(ML99_listMap(f, list))`.
+ *
+ * @note Unlike #ML99_listMap, @p f can evaluate to many terms.
+ */
+#define ML99_listMapInPlace(f, list) ML99_call(ML99_listMapInPlace, f, list)
+
+/**
+ * A more efficient version of `ML99_listUnwrap(ML99_listMapI(f, list))`.
+ *
+ * @note Unlike #ML99_listMapI, @p f can evaluate to many terms.
+ */
+#define ML99_listMapInPlaceI(f, list) ML99_call(ML99_listMapInPlaceI, f, list)
+
+/**
+ * The same as #ML99_listMap but with the reversed order of arguments.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ * #include <metalang99/nat.h>
+ *
+ * // 4, 5, 6
+ * ML99_listFor(ML99_list(v(1, 2, 3)), ML99_appl(v(ML99_add), v(3)))
+ * @endcode
+ */
+#define ML99_listFor(list, f) ML99_call(ML99_listFor, list, f)
+
+/**
+ * Maps the initial elements of the non-empty list @p list with @p f_init and the last element with
+ * @p f_last.
+ *
+ * # Examples
+ *
+ * @code
+ * // 4, 5, 10
+ * ML99_listMapInitLast(ML99_appl(v(ML99_add), v(3)), ML99_appl(v(ML99_add), v(7)), ML99_list(v(1,
+ * 2, 3)))
+ * @endcode
+ */
+#define ML99_listMapInitLast(f_init, f_last, list) \
+ ML99_call(ML99_listMapInitLast, f_init, f_last, list)
+
+/**
+ * The same as #ML99_listMapInitLast but accepts @p list as the first parameter.
+ *
+ * # Examples
+ *
+ * @code
+ * // 4, 5, 10
+ * ML99_listForInitLast(ML99_list(v(1, 2, 3)), ML99_appl(v(ML99_add), v(3)), ML99_appl(v(ML99_add),
+ * v(7)))
+ * @endcode
+ */
+#define ML99_listForInitLast(list, f_init, f_last) \
+ ML99_call(ML99_listForInitLast, list, f_init, f_last)
+
+/**
+ * Filters @p list with @p f.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ * #include <metalang99/nat.h>
+ *
+ * // 9, 11, 6
+ * ML99_listFilter(ML99_appl(v(ML99_lesser), v(5)), ML99_list(v(9, 1, 11, 6, 0, 4)))
+ * @endcode
+ */
+#define ML99_listFilter(f, list) ML99_call(ML99_listFilter, f, list)
+
+/**
+ * A combination of #ML99_listFilter and #ML99_listMap.
+ *
+ * It builds a new list by applying @p f to each element in @p list: if @p f yields `ML99_just(x)`,
+ * `x` is passed to the new list, otherwise (`ML99_nothing()`), the value is neglected.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ * #include <metalang99/maybe.h>
+ *
+ * #define MAYBE_LIST ML99_list(ML99_just(v(5)), ML99_nothing(), ML99_just(v(7)))
+ *
+ * // 5, 7
+ * ML99_listFilterMap(v(ML99_id), MAYBE_LIST)
+ * @endcode
+ */
+#define ML99_listFilterMap(f, list) ML99_call(ML99_listFilterMap, f, list)
+
+/**
+ * Tests @p list and @p other for equality.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ * #include <metalang99/nat.h>
+ *
+ * // 0
+ * ML99_listEq(v(ML99_natEq), ML99_list(v(1, 2, 3)), ML99_list(v(4, 5, 6)))
+ *
+ * // 1
+ * ML99_listEq(v(ML99_natEq), ML99_list(v(1, 2, 3)), ML99_list(v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_listEq(cmp, list, other) ML99_call(ML99_listEq, cmp, list, other)
+
+/**
+ * Checks whether @p item resides in @p list.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ * #include <metalang99/nat.h>
+ *
+ * // 1
+ * ML99_listContains(v(ML99_natEq), v(3), ML99_list(v(1, 2, 3)))
+ *
+ * // 0
+ * ML99_listContains(v(ML99_natEq), v(456), ML99_list(v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_listContains(cmp, item, list) ML99_call(ML99_listContains, cmp, item, list)
+
+/**
+ * Extracts the prefix of @p list of the length @p n. If @p n is greater than the length of @p list,
+ * the whole @p list is returned.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 1, 2
+ * ML99_listTake(v(2), ML99_list(v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_listTake(n, list) ML99_call(ML99_listTake, n, list)
+
+/**
+ * Extracts the items from @p list as long as @p f evaluates to `ML99_true()`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ * #include <metalang99/nat.h>
+ *
+ * // 1, 2, 3
+ * ML99_listTakeWhile(ML99_appl(v(ML99_greater), v(4)), ML99_list(v(1, 2, 3, 4, 5, 6)))
+ * @endcode
+ */
+#define ML99_listTakeWhile(f, list) ML99_call(ML99_listTakeWhile, f, list)
+
+/**
+ * Removes the prefix of @p list of the length @p n. If @p n is greater than the length of @p list,
+ * `ML99_nil()` is returned.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // 2, 3
+ * ML99_listDrop(v(1), ML99_list(v(1, 2, 3)))
+ * @endcode
+ */
+#define ML99_listDrop(n, list) ML99_call(ML99_listDrop, n, list)
+
+/**
+ * Removes the items from @p list as long as @p f evaluates to `ML99_true()`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ * #include <metalang99/nat.h>
+ *
+ * // 4, 5, 6
+ * ML99_listDropWhile(ML99_appl(v(ML99_lesser), v(4)), ML99_list(v(1, 2, 3, 4, 5, 6)))
+ * @endcode
+ */
+#define ML99_listDropWhile(f, list) ML99_call(ML99_listDropWhile, f, list)
+
+/**
+ * Computes a list of two-place tuples of the corresponding items from @p list and @p other.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // (1, 4), (2, 5), (3, 6)
+ * ML99_listZip(ML99_list(v(1, 2, 3)), ML99_list(v(4, 5, 6)))
+ * @endcode
+ */
+#define ML99_listZip(list, other) ML99_call(ML99_listZip, list, other)
+
+/**
+ * Transforms a list of two-place tuples into a tuple of a list of the first components and a list
+ * of the second components.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ * #include <metalang99/tuple.h>
+ *
+ * // ML99_tuple(ML99_list(v(1, 2, 3)), ML99_list(v(4, 5, 6)))
+ * ML99_listUnzip(ML99_list(ML99_tuple(v(1, 4)), ML99_tuple(v(2, 5)), ML99_tuple(v(3, 6))))
+ * @endcode
+ */
+#define ML99_listUnzip(list) ML99_call(ML99_listUnzip, list)
+
+/**
+ * Computes a list of length @p n with each element @p item.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ *
+ * // ~, ~, ~, ~, ~
+ * ML99_listReplicate(v(5), v(~))
+ *
+ * // ML99_nil()
+ * ML99_listReplicate(v(0), v(~))
+ * @endcode
+ */
+#define ML99_listReplicate(n, item) ML99_call(ML99_listReplicate, n, item)
+
+/**
+ * Returns a two-place tuple of lists: those items of @p list the do and do not satisfy the
+ * predicate @p f, respectively.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ * #include <metalang99/nat.h>
+ *
+ * // ML99_tuple(ML99_list(v(4, 7)), ML99_list(v(11, 12, 13)))
+ * ML99_listPartition(ML99_appl(v(ML99_greater), v(10)), ML99_list(v(11, 4, 12, 13, 7)))
+ * @endcode
+ */
+#define ML99_listPartition(f, list) ML99_call(ML99_listPartition, f, list)
+
+/**
+ * Applies all the items in @p list to @p f.
+ *
+ * If the list is empty, results in @p f as-is.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/list.h>
+ * #include <metalang99/nat.h>
+ *
+ * // ML99_add
+ * ML99_listAppl(v(ML99_add), ML99_nil())
+ *
+ * // ML99_appl(v(ML99_add), v(1))
+ * ML99_listAppl(v(ML99_add), ML99_list(v(1)))
+ *
+ * // ML99_appl2(v(ML99_add), v(1), v(2))
+ * ML99_listAppl(v(ML99_add), ML99_list(v(1, 2)))
+ * @endcode
+ */
+#define ML99_listAppl(f, list) ML99_call(ML99_listAppl, f, list)
+
+#define ML99_CONS(x, xs) ML99_CHOICE(cons, x, xs)
+#define ML99_NIL(...) ML99_CHOICE(nil, ~)
+#define ML99_IS_CONS(list) ML99_NOT(ML99_IS_NIL(list))
+#define ML99_IS_NIL(list) ML99_PRIV_IS_NIL(list)
+
+#ifndef DOXYGEN_IGNORE
+
+#define ML99_cons_IMPL(x, xs) v(ML99_CONS(x, xs))
+#define ML99_nil_IMPL(...) v(ML99_NIL())
+
+#define ML99_isCons_IMPL(list) v(ML99_IS_CONS(list))
+#define ML99_isNil_IMPL(list) v(ML99_IS_NIL(list))
+
+#define ML99_listHead_IMPL(list) ML99_match_IMPL(list, ML99_PRIV_listHead_)
+#define ML99_PRIV_listHead_nil_IMPL(_) ML99_PRIV_EMPTY_LIST_ERROR(listHead)
+#define ML99_PRIV_listHead_cons_IMPL(x, _xs) v(x)
+
+#define ML99_listTail_IMPL(list) ML99_match_IMPL(list, ML99_PRIV_listTail_)
+#define ML99_PRIV_listTail_nil_IMPL(_) ML99_PRIV_EMPTY_LIST_ERROR(listTail)
+#define ML99_PRIV_listTail_cons_IMPL(_x, xs) v(xs)
+
+#define ML99_listLast_IMPL(list) ML99_match_IMPL(list, ML99_PRIV_listLast_)
+#define ML99_PRIV_listLast_nil_IMPL(_) ML99_PRIV_EMPTY_LIST_ERROR(listLast)
+#define ML99_PRIV_listLast_cons_IMPL(x, xs) \
+ ML99_PRIV_IF(ML99_IS_NIL(xs), v(x), ML99_listLast_IMPL(xs))
+
+#define ML99_listInit_IMPL(list) ML99_match_IMPL(list, ML99_PRIV_listInit_)
+#define ML99_PRIV_listInit_nil_IMPL(_) ML99_PRIV_EMPTY_LIST_ERROR(listInit)
+#define ML99_PRIV_listInit_cons_IMPL(x, xs) \
+ ML99_PRIV_IF(ML99_IS_NIL(xs), v(ML99_NIL()), ML99_cons(v(x), ML99_listInit_IMPL(xs)))
+
+// ML99_list_IMPL {
+
+#define ML99_list_IMPL(...) \
+ ML99_PRIV_listProgress_IMPL(ML99_VARIADICS_COUNT(__VA_ARGS__), __VA_ARGS__, ~)
+
+// Last 4 recursion steps unrolled.
+#define ML99_PRIV_listProgress_IMPL(count, ...) \
+ ML99_PRIV_IF( \
+ ML99_NAT_EQ(count, 4), \
+ ML99_PRIV_listDone_4, \
+ ML99_PRIV_IF( \
+ ML99_NAT_EQ(count, 3), \
+ ML99_PRIV_listDone_3, \
+ ML99_PRIV_IF( \
+ ML99_NAT_EQ(count, 2), \
+ ML99_PRIV_listDone_2, \
+ ML99_PRIV_IF( \
+ ML99_NAT_EQ(count, 1), \
+ ML99_PRIV_listDone_1, \
+ ML99_PRIV_IF( \
+ ML99_NAT_EQ(count, 0), \
+ ML99_PRIV_listDone_0, \
+ ML99_PRIV_listProgressAux))))) \
+ (count, __VA_ARGS__)
+
+#define ML99_PRIV_listProgressAux(count, x, ...) \
+ ML99_cons(v(x), ML99_callUneval(ML99_PRIV_listProgress, ML99_DEC(count), __VA_ARGS__))
+
+#define ML99_PRIV_listDone_0(_count, _) v(ML99_NIL())
+#define ML99_PRIV_listDone_1(_count, a, _) v(ML99_CONS(a, ML99_NIL()))
+#define ML99_PRIV_listDone_2(_count, a, b, _) v(ML99_CONS(a, ML99_CONS(b, ML99_NIL())))
+#define ML99_PRIV_listDone_3(_count, a, b, c, _) \
+ v(ML99_CONS(a, ML99_CONS(b, ML99_CONS(c, ML99_NIL()))))
+#define ML99_PRIV_listDone_4(_count, a, b, c, d, _) \
+ v(ML99_CONS(a, ML99_CONS(b, ML99_CONS(c, ML99_CONS(d, ML99_NIL())))))
+// } (ML99_list_IMPL)
+
+// ML99_listFromTuples_IMPL {
+
+#define ML99_listFromTuples_IMPL(f, ...) ML99_PRIV_listFromTuplesAux_IMPL(f, __VA_ARGS__, ~)
+
+#define ML99_PRIV_listFromTuplesAux_IMPL(f, x, ...) \
+ ML99_PRIV_CAT(ML99_PRIV_listFromTuples_, ML99_IS_UNTUPLE(x))(f, x, __VA_ARGS__)
+
+#define ML99_PRIV_listFromTuples_1(_f, x, ...) ML99_PRIV_NOT_TUPLE_ERROR(x)
+#define ML99_PRIV_listFromTuples_0(f, x, ...) \
+ ML99_cons( \
+ ML99_appl_IMPL(f, ML99_UNTUPLE(x)), \
+ ML99_PRIV_IF( \
+ ML99_VARIADICS_IS_SINGLE(__VA_ARGS__), \
+ v(ML99_NIL()), \
+ ML99_callUneval(ML99_PRIV_listFromTuplesAux, f, __VA_ARGS__)))
+// } (ML99_listFromTuples_IMPL)
+
+#define ML99_listFromSeq_IMPL(seq) \
+ ML99_PRIV_CAT(ML99_PRIV_listFromSeq_, ML99_SEQ_IS_EMPTY(seq))(seq)
+#define ML99_PRIV_listFromSeq_1 ML99_nil_IMPL
+#define ML99_PRIV_listFromSeq_0(seq) \
+ ML99_cons(v(ML99_SEQ_GET(0)(seq)), ML99_callUneval(ML99_listFromSeq, ML99_SEQ_TAIL(seq)))
+
+#define ML99_listLen_IMPL(list) ML99_match_IMPL(list, ML99_PRIV_listLen_)
+#define ML99_PRIV_listLen_nil_IMPL(_) v(0)
+#define ML99_PRIV_listLen_cons_IMPL(_x, xs) ML99_inc(ML99_listLen_IMPL(xs))
+
+#define ML99_listAppend_IMPL(list, other) \
+ ML99_matchWithArgs_IMPL(list, ML99_PRIV_listAppend_, other)
+#define ML99_PRIV_listAppend_nil_IMPL(_, other) v(other)
+#define ML99_PRIV_listAppend_cons_IMPL(x, xs, other) \
+ ML99_cons(v(x), ML99_listAppend_IMPL(xs, other))
+
+#define ML99_listAppendItem_IMPL(item, list) ML99_listAppend_IMPL(list, ML99_CONS(item, ML99_NIL()))
+
+#define ML99_listUnwrap_IMPL(list) ML99_match_IMPL(list, ML99_PRIV_listUnwrap_)
+#define ML99_PRIV_listUnwrap_nil_IMPL ML99_empty_IMPL
+#define ML99_PRIV_listUnwrap_cons_IMPL(x, xs) ML99_TERMS(v(x), ML99_listUnwrap_IMPL(xs))
+
+#define ML99_listReverse_IMPL(list) ML99_match_IMPL(list, ML99_PRIV_listReverse_)
+#define ML99_PRIV_listReverse_nil_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listReverse_cons_IMPL(x, xs) ML99_listAppendItem(v(x), ML99_listReverse_IMPL(xs))
+
+#define ML99_listGet_IMPL(i, list) ML99_matchWithArgs_IMPL(list, ML99_PRIV_listGet_, i)
+#define ML99_PRIV_listGet_nil_IMPL(_, i) ML99_PRIV_EMPTY_LIST_ERROR(ML99_listGet)
+#define ML99_PRIV_listGet_cons_IMPL(x, xs, i) \
+ ML99_PRIV_IF(ML99_NAT_EQ(i, 0), v(x), ML99_listGet_IMPL(ML99_DEC(i), xs))
+
+#define ML99_listFoldr_IMPL(f, init, list) \
+ ML99_matchWithArgs_IMPL(list, ML99_PRIV_listFoldr_, f, init)
+#define ML99_PRIV_listFoldr_nil_IMPL(_, _f, acc) v(acc)
+#define ML99_PRIV_listFoldr_cons_IMPL(x, xs, f, acc) \
+ ML99_call(ML99_appl2, v(f, x), ML99_listFoldr_IMPL(f, acc, xs))
+
+#define ML99_listFoldl_IMPL(f, init, list) \
+ ML99_matchWithArgs_IMPL(list, ML99_PRIV_listFoldl_, f, init)
+#define ML99_PRIV_listFoldl_nil_IMPL(_, _f, acc) v(acc)
+#define ML99_PRIV_listFoldl_cons_IMPL(x, xs, f, acc) \
+ ML99_listFoldl(v(f), ML99_appl2_IMPL(f, acc, x), v(xs))
+
+#define ML99_listFoldl1_IMPL(f, list) ML99_matchWithArgs_IMPL(list, ML99_PRIV_listFoldl1_, f)
+#define ML99_PRIV_listFoldl1_nil_IMPL(_, _f) ML99_PRIV_EMPTY_LIST_ERROR(ML99_listFoldl1)
+#define ML99_PRIV_listFoldl1_cons_IMPL(x, xs, f) ML99_listFoldl_IMPL(f, x, xs)
+
+#define ML99_listIntersperse_IMPL(item, list) \
+ ML99_matchWithArgs_IMPL(list, ML99_PRIV_listIntersperse_, item)
+#define ML99_PRIV_listIntersperse_nil_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listIntersperse_cons_IMPL(x, xs, item) \
+ ML99_cons(v(x), ML99_listPrependToAll_IMPL(item, xs))
+
+#define ML99_listPrependToAll_IMPL(item, list) \
+ ML99_matchWithArgs_IMPL(list, ML99_PRIV_listPrependToAll_, item)
+#define ML99_PRIV_listPrependToAll_nil_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listPrependToAll_cons_IMPL(x, xs, item) \
+ ML99_cons(v(item), ML99_cons(v(x), ML99_listPrependToAll_IMPL(item, xs)))
+
+#define ML99_listMap_IMPL(f, list) ML99_matchWithArgs_IMPL(list, ML99_PRIV_listMap_, f)
+#define ML99_PRIV_listMap_nil_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listMap_cons_IMPL(x, xs, f) \
+ ML99_cons(ML99_appl_IMPL(f, x), ML99_listMap_IMPL(f, xs))
+
+#define ML99_listMapI_IMPL(f, list) ML99_PRIV_listMapIAux_IMPL(f, list, 0)
+#define ML99_PRIV_listMapIAux_IMPL(f, list, i) \
+ ML99_matchWithArgs_IMPL(list, ML99_PRIV_listMapI_, f, i)
+#define ML99_PRIV_listMapI_nil_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listMapI_cons_IMPL(x, xs, f, i) \
+ ML99_cons(ML99_appl2_IMPL(f, x, i), ML99_PRIV_listMapIAux_IMPL(f, xs, ML99_INC(i)))
+
+#define ML99_listMapInPlace_IMPL(f, list) \
+ ML99_matchWithArgs_IMPL(list, ML99_PRIV_listMapInPlace_, f)
+#define ML99_PRIV_listMapInPlace_nil_IMPL ML99_empty_IMPL
+#define ML99_PRIV_listMapInPlace_cons_IMPL(x, xs, f) \
+ ML99_TERMS(ML99_appl_IMPL(f, x), ML99_listMapInPlace_IMPL(f, xs))
+
+#define ML99_listMapInPlaceI_IMPL(f, list) ML99_PRIV_listMapInPlaceIAux_IMPL(f, list, 0)
+#define ML99_PRIV_listMapInPlaceIAux_IMPL(f, list, i) \
+ ML99_matchWithArgs_IMPL(list, ML99_PRIV_listMapInPlaceI_, f, i)
+#define ML99_PRIV_listMapInPlaceI_nil_IMPL ML99_empty_IMPL
+#define ML99_PRIV_listMapInPlaceI_cons_IMPL(x, xs, f, i) \
+ ML99_TERMS(ML99_appl2_IMPL(f, x, i), ML99_PRIV_listMapInPlaceIAux_IMPL(f, xs, ML99_INC(i)))
+
+#define ML99_listFor_IMPL(list, f) ML99_listMap_IMPL(f, list)
+
+#define ML99_listMapInitLast_IMPL(f_init, f_last, list) \
+ ML99_listAppendItem( \
+ ML99_appl(v(f_last), ML99_listLast_IMPL(list)), \
+ ML99_listMap(v(f_init), ML99_listInit_IMPL(list)))
+
+#define ML99_listForInitLast_IMPL(list, f_init, f_last) \
+ ML99_listMapInitLast_IMPL(f_init, f_last, list)
+
+// ML99_listFilter_IMPL {
+
+#define ML99_listFilter_IMPL(f, list) ML99_matchWithArgs_IMPL(list, ML99_PRIV_listFilter_, f)
+
+#define ML99_PRIV_listFilter_nil_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listFilter_cons_IMPL(x, xs, f) \
+ ML99_call( \
+ ML99_boolMatchWithArgs, \
+ ML99_appl_IMPL(f, x), \
+ v(ML99_PRIV_listFilter_cons_, x), \
+ ML99_listFilter_IMPL(f, xs))
+
+#define ML99_PRIV_listFilter_cons_1_IMPL(x, rest) v(ML99_CONS(x, rest))
+#define ML99_PRIV_listFilter_cons_0_IMPL(_x, rest) v(rest)
+// } (ML99_listFilter_IMPL)
+
+// ML99_listFilterMap_IMPL {
+
+#define ML99_listFilterMap_IMPL(f, list) ML99_matchWithArgs_IMPL(list, ML99_PRIV_listFilterMap_, f)
+
+#define ML99_PRIV_listFilterMap_nil_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listFilterMap_cons_IMPL(x, xs, f) \
+ ML99_call(ML99_matchWithArgs, ML99_appl_IMPL(f, x), v(ML99_PRIV_listFilterMap_cons_, f, xs))
+
+#define ML99_PRIV_listFilterMap_cons_just_IMPL(y, f, xs) \
+ ML99_cons(v(y), ML99_listFilterMap_IMPL(f, xs))
+#define ML99_PRIV_listFilterMap_cons_nothing_IMPL(_, f, xs) ML99_listFilterMap_IMPL(f, xs)
+// } (ML99_listFilterMap_IMPL)
+
+// ML99_listEq_IMPL {
+
+#define ML99_listEq_IMPL(cmp, list, other) \
+ ML99_matchWithArgs_IMPL(list, ML99_PRIV_listEq_, other, cmp)
+
+#define ML99_PRIV_listEq_nil_IMPL(_, other, _cmp) v(ML99_IS_NIL(other))
+#define ML99_PRIV_listEq_cons_IMPL(x, xs, other, cmp) \
+ ML99_matchWithArgs_IMPL(other, ML99_PRIV_listEq_cons_, x, xs, cmp)
+
+#define ML99_PRIV_listEq_cons_nil_IMPL ML99_false_IMPL
+#define ML99_PRIV_listEq_cons_cons_IMPL(other_x, other_xs, x, xs, cmp) \
+ ML99_call( \
+ ML99_call(ML99_if, ML99_appl2_IMPL(cmp, x, other_x), v(ML99_listEq, ML99_false)), \
+ v(cmp, xs, other_xs))
+// } (ML99_listEq_IMPL)
+
+#define ML99_listContains_IMPL(cmp, item, list) \
+ ML99_matchWithArgs_IMPL(list, ML99_PRIV_listContains_, item, cmp)
+#define ML99_PRIV_listContains_nil_IMPL ML99_false_IMPL
+#define ML99_PRIV_listContains_cons_IMPL(x, xs, item, cmp) \
+ ML99_call( \
+ ML99_call(ML99_if, ML99_appl2_IMPL(cmp, x, item), v(ML99_true, ML99_listContains)), \
+ v(cmp, item, xs))
+
+#define ML99_listTake_IMPL(n, list) ML99_matchWithArgs_IMPL(list, ML99_PRIV_listTake_, n)
+#define ML99_PRIV_listTake_nil_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listTake_cons_IMPL(x, xs, i) \
+ ML99_PRIV_IF( \
+ ML99_NAT_EQ(i, 0), \
+ v(ML99_NIL()), \
+ ML99_cons(v(x), ML99_listTake_IMPL(ML99_DEC(i), xs)))
+
+// ML99_listTakeWhile_IMPL {
+
+#define ML99_listTakeWhile_IMPL(f, list) ML99_matchWithArgs_IMPL(list, ML99_PRIV_listTakeWhile_, f)
+
+#define ML99_PRIV_listTakeWhile_nil_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listTakeWhile_cons_IMPL(x, xs, f) \
+ ML99_call( \
+ ML99_boolMatchWithArgs, \
+ ML99_appl_IMPL(f, x), \
+ v(ML99_PRIV_listTakeWhile_cons_, x, xs, f))
+
+#define ML99_PRIV_listTakeWhile_cons_1_IMPL(x, xs, f) \
+ ML99_cons(v(x), ML99_listTakeWhile_IMPL(f, xs))
+#define ML99_PRIV_listTakeWhile_cons_0_IMPL ML99_nil_IMPL
+// } (ML99_listTakeWhile_IMPL)
+
+#define ML99_listDrop_IMPL(n, list) ML99_matchWithArgs_IMPL(list, ML99_PRIV_listDrop_, n)
+#define ML99_PRIV_listDrop_nil_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listDrop_cons_IMPL(x, xs, i) \
+ ML99_PRIV_IF(ML99_NAT_EQ(i, 0), v(ML99_CONS(x, xs)), ML99_listDrop_IMPL(ML99_DEC(i), xs))
+
+// ML99_listDropWhile_IMPL {
+
+#define ML99_listDropWhile_IMPL(f, list) ML99_matchWithArgs_IMPL(list, ML99_PRIV_listDropWhile_, f)
+
+#define ML99_PRIV_listDropWhile_nil_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listDropWhile_cons_IMPL(x, xs, f) \
+ ML99_call( \
+ ML99_boolMatchWithArgs, \
+ ML99_appl_IMPL(f, x), \
+ v(ML99_PRIV_listDropWhile_cons_, x, xs, f))
+
+#define ML99_PRIV_listDropWhile_cons_0_IMPL(x, xs, _f) v(ML99_CONS(x, xs))
+#define ML99_PRIV_listDropWhile_cons_1_IMPL(_x, xs, f) ML99_listDropWhile_IMPL(f, xs)
+// } (ML99_listDropWhile_IMPL)
+
+// ML99_listZip_IMPL {
+
+#define ML99_listZip_IMPL(list, other) ML99_matchWithArgs_IMPL(list, ML99_PRIV_listZip_, other)
+
+#define ML99_PRIV_listZip_nil_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listZip_cons_IMPL(x, xs, other) \
+ ML99_matchWithArgs_IMPL(other, ML99_PRIV_listZip_cons_, x, xs)
+
+#define ML99_PRIV_listZip_cons_nil_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listZip_cons_cons_IMPL(other_x, other_xs, x, xs) \
+ ML99_cons(v(ML99_TUPLE(x, other_x)), ML99_listZip_IMPL(xs, other_xs))
+// } (ML99_listZip_IMPL)
+
+// ML99_listUnzip_IMPL {
+
+#define ML99_listUnzip_IMPL(list) ML99_match_IMPL(list, ML99_PRIV_listUnzip_)
+
+#define ML99_PRIV_listUnzip_nil_IMPL(_) v(ML99_TUPLE(ML99_NIL(), ML99_NIL()))
+#define ML99_PRIV_listUnzip_cons_IMPL(x, xs) \
+ ML99_call(ML99_PRIV_listUnzipProgress, v(x), ML99_listUnzip_IMPL(xs))
+
+#define ML99_PRIV_listUnzipProgress_IMPL(x, rest) \
+ v(ML99_TUPLE(ML99_PRIV_LIST_UNZIP_EXTEND(x, rest, 0), ML99_PRIV_LIST_UNZIP_EXTEND(x, rest, 1)))
+
+#define ML99_PRIV_LIST_UNZIP_EXTEND(x, rest, i) \
+ ML99_CONS(ML99_TUPLE_GET(i)(x), ML99_TUPLE_GET(i)(rest))
+// } (ML99_listUnzip_IMPL)
+
+#define ML99_listReplicate_IMPL(n, item) \
+ ML99_natMatchWithArgs_IMPL(n, ML99_PRIV_listReplicate_, item)
+#define ML99_PRIV_listReplicate_Z_IMPL ML99_nil_IMPL
+#define ML99_PRIV_listReplicate_S_IMPL(n, item) ML99_cons(v(item), ML99_listReplicate_IMPL(n, item))
+
+// ML99_listPartition_IMPL {
+
+#define ML99_listPartition_IMPL(f, list) \
+ ML99_listFoldr( \
+ ML99_appl_IMPL(ML99_PRIV_listPartitionAux, f), \
+ v(ML99_TUPLE(ML99_NIL(), ML99_NIL())), \
+ v(list))
+
+#define ML99_PRIV_listPartitionAux_IMPL(f, x, acc) \
+ ML99_call( \
+ ML99_boolMatchWithArgs, \
+ ML99_appl_IMPL(f, x), \
+ v(ML99_PRIV_listPartition_, x, ML99_UNTUPLE(acc)))
+
+#define ML99_PRIV_listPartition_1_IMPL(x, fst, snd) v(ML99_TUPLE(ML99_CONS(x, fst), snd))
+#define ML99_PRIV_listPartition_0_IMPL(x, fst, snd) v(ML99_TUPLE(fst, ML99_CONS(x, snd)))
+// } (ML99_listPartition_IMPL)
+
+#define ML99_listAppl_IMPL(f, list) ML99_listFoldl_IMPL(ML99_appl, f, list)
+
+// ML99_listUnwrapCommaSep_IMPL {
+
+#define ML99_listUnwrapCommaSep_IMPL(list) \
+ ML99_PRIV_IF( \
+ ML99_IS_NIL(list), \
+ v(ML99_EMPTY()), \
+ ML99_variadicsTail(ML99_PRIV_listUnwrapCommaSepAux_IMPL(list)))
+
+#define ML99_PRIV_listUnwrapCommaSepAux_IMPL(xs) ML99_match_IMPL(xs, ML99_PRIV_listUnwrapCommaSep_)
+
+#define ML99_PRIV_listUnwrapCommaSep_nil_IMPL ML99_empty_IMPL
+#define ML99_PRIV_listUnwrapCommaSep_cons_IMPL(x, xs) \
+ ML99_TERMS(v(, x), ML99_PRIV_listUnwrapCommaSepAux_IMPL(xs))
+// } (ML99_listUnwrapCommaSep_IMPL)
+
+// clang-format off
+#define ML99_PRIV_EMPTY_LIST_ERROR(f) ML99_fatal(ML99_##f, expected a non-empty list)
+// clang-format on
+
+#define ML99_PRIV_IS_NIL(list) ML99_DETECT_IDENT(ML99_PRIV_IS_NIL_, ML99_CHOICE_TAG(list))
+#define ML99_PRIV_IS_NIL_nil ()
+
+// Arity specifiers {
+
+#define ML99_cons_ARITY 2
+#define ML99_nil_ARITY 1
+#define ML99_isCons_ARITY 1
+#define ML99_isNil_ARITY 1
+#define ML99_listHead_ARITY 1
+#define ML99_listTail_ARITY 1
+#define ML99_listLast_ARITY 1
+#define ML99_listInit_ARITY 1
+#define ML99_list_ARITY 1
+#define ML99_listFromTuples_ARITY 2
+#define ML99_listFromSeq_ARITY 1
+#define ML99_listLen_ARITY 1
+#define ML99_listAppend_ARITY 2
+#define ML99_listAppendItem_ARITY 2
+#define ML99_listUnwrap_ARITY 1
+#define ML99_listUnwrapCommaSep_ARITY 1
+#define ML99_listReverse_ARITY 1
+#define ML99_listGet_ARITY 2
+#define ML99_listFoldr_ARITY 3
+#define ML99_listFoldl_ARITY 3
+#define ML99_listFoldl1_ARITY 2
+#define ML99_listIntersperse_ARITY 2
+#define ML99_listPrependToAll_ARITY 2
+#define ML99_listMap_ARITY 2
+#define ML99_listMapI_ARITY 2
+#define ML99_listMapInPlace_ARITY 2
+#define ML99_listMapInPlaceI_ARITY 2
+#define ML99_listFor_ARITY 2
+#define ML99_listMapInitLast_ARITY 3
+#define ML99_listForInitLast_ARITY 3
+#define ML99_listFilter_ARITY 2
+#define ML99_listFilterMap_ARITY 2
+#define ML99_listEq_ARITY 3
+#define ML99_listContains_ARITY 3
+#define ML99_listTake_ARITY 2
+#define ML99_listTakeWhile_ARITY 2
+#define ML99_listDrop_ARITY 2
+#define ML99_listDropWhile_ARITY 2
+#define ML99_listZip_ARITY 2
+#define ML99_listUnzip_ARITY 1
+#define ML99_listReplicate_ARITY 2
+#define ML99_listPartition_ARITY 2
+#define ML99_listAppl_ARITY 2
+
+#define ML99_PRIV_listPartitionAux_ARITY 3
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_LIST_H
diff --git a/test/external/metalang99/include/metalang99/logical.h b/test/external/metalang99/include/metalang99/logical.h
new file mode 100644
index 0000000..9783944
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/logical.h
@@ -0,0 +1,11 @@
+/**
+ * @file
+ * This module is deprecated and exists only for backwards compatibility.
+ */
+
+#ifndef ML99_LOGICAL_H
+#define ML99_LOGICAL_H
+
+#include <metalang99/bool.h>
+
+#endif // ML99_LOGICAL_H
diff --git a/test/external/metalang99/include/metalang99/maybe.h b/test/external/metalang99/include/metalang99/maybe.h
new file mode 100644
index 0000000..b51c4d2
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/maybe.h
@@ -0,0 +1,143 @@
+/**
+ * @file
+ * An optional value.
+ */
+
+#ifndef ML99_MAYBE_H
+#define ML99_MAYBE_H
+
+#include <metalang99/priv/util.h>
+
+#include <metalang99/bool.h>
+#include <metalang99/choice.h>
+#include <metalang99/ident.h>
+
+/**
+ * Some value @p x.
+ */
+#define ML99_just(x) ML99_call(ML99_just, x)
+
+/**
+ * No value.
+ */
+#define ML99_nothing(...) ML99_callUneval(ML99_nothing, )
+
+/**
+ * `ML99_true()` if @p maybe contains some value, otherwise `ML99_false()`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/maybe.h>
+ *
+ * // 1
+ * ML99_isJust(ML99_just(v(123)))
+ *
+ * // 0
+ * ML99_isJust(ML99_nothing())
+ * @endcode
+ */
+#define ML99_isJust(maybe) ML99_call(ML99_isJust, maybe)
+
+/**
+ * The inverse of #ML99_isJust.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/maybe.h>
+ *
+ * // 1
+ * ML99_isNothing(ML99_nothing())
+ *
+ * // 0
+ * ML99_isNothing(ML99_just(v(123)))
+ * @endcode
+ */
+#define ML99_isNothing(maybe) ML99_call(ML99_isNothing, maybe)
+
+/**
+ * Tests @p maybe and @p other for equality.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/maybe.h>
+ * #include <metalang99/nat.h>
+ *
+ * // 1
+ * ML99_maybeEq(v(ML99_natEq), ML99_just(v(123)), ML99_just(v(123)));
+ *
+ * // 0
+ * ML99_maybeEq(v(ML99_natEq), ML99_just(v(4)), ML99_just(v(6)));
+ *
+ * // 0
+ * ML99_maybeEq(v(ML99_natEq), ML99_just(v(4)), ML99_nothing());
+ * @endcode
+ */
+#define ML99_maybeEq(cmp, maybe, other) ML99_call(ML99_maybeEq, cmp, maybe, other)
+
+/**
+ * Returns the contained value on `ML99_just(x)` or emits a fatal error on `ML99_nothing()`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/maybe.h>
+ *
+ * // 123
+ * ML99_maybeUnwrap(ML99_just(v(123)))
+ *
+ * // Emits a fatal error.
+ * ML99_maybeUnwrap(ML99_nothing())
+ * @endcode
+ */
+#define ML99_maybeUnwrap(maybe) ML99_call(ML99_maybeUnwrap, maybe)
+
+#define ML99_JUST(x) ML99_CHOICE(just, x)
+#define ML99_NOTHING(...) ML99_CHOICE(nothing, ~)
+#define ML99_IS_JUST(maybe) ML99_PRIV_IS_JUST(maybe)
+#define ML99_IS_NOTHING(maybe) ML99_NOT(ML99_IS_JUST(maybe))
+
+#ifndef DOXYGEN_IGNORE
+
+#define ML99_just_IMPL(x) v(ML99_JUST(x))
+#define ML99_nothing_IMPL(...) v(ML99_NOTHING())
+
+#define ML99_isJust_IMPL(maybe) v(ML99_IS_JUST(maybe))
+#define ML99_isNothing_IMPL(maybe) v(ML99_IS_NOTHING(maybe))
+
+// ML99_maybeEq_IMPL {
+
+#define ML99_maybeEq_IMPL(cmp, maybe, other) \
+ ML99_matchWithArgs_IMPL(maybe, ML99_PRIV_maybeEq_, cmp, other)
+
+#define ML99_PRIV_maybeEq_just_IMPL(x, cmp, other) \
+ ML99_matchWithArgs_IMPL(other, ML99_PRIV_maybeEq_just_, cmp, x)
+#define ML99_PRIV_maybeEq_nothing_IMPL(_, _cmp, other) v(ML99_IS_NOTHING(other))
+
+#define ML99_PRIV_maybeEq_just_just_IMPL(y, cmp, x) ML99_appl2_IMPL(cmp, x, y)
+#define ML99_PRIV_maybeEq_just_nothing_IMPL ML99_false_IMPL
+// } (ML99_maybeEq_IMPL)
+
+#define ML99_maybeUnwrap_IMPL(maybe) ML99_match_IMPL(maybe, ML99_PRIV_maybeUnwrap_)
+#define ML99_PRIV_maybeUnwrap_just_IMPL(x) v(x)
+#define ML99_PRIV_maybeUnwrap_nothing_IMPL(_) \
+ ML99_fatal(ML99_maybeUnwrap, expected ML99_just but found ML99_nothing)
+
+#define ML99_PRIV_IS_JUST(maybe) ML99_DETECT_IDENT(ML99_PRIV_IS_JUST_, ML99_CHOICE_TAG(maybe))
+#define ML99_PRIV_IS_JUST_just ()
+
+// Arity specifiers {
+
+#define ML99_just_ARITY 1
+#define ML99_nothing_ARITY 1
+#define ML99_isJust_ARITY 1
+#define ML99_isNothing_ARITY 1
+#define ML99_maybeEq_ARITY 3
+#define ML99_maybeUnwrap_ARITY 1
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_MAYBE_H
diff --git a/test/external/metalang99/include/metalang99/nat.h b/test/external/metalang99/include/metalang99/nat.h
new file mode 100644
index 0000000..6c56076
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/nat.h
@@ -0,0 +1,526 @@
+/**
+ * @file
+ * Natural numbers: [0; 255].
+ *
+ * Most of the time, natural numbers are used for iteration; they are not meant for CPU-bound tasks
+ * such as Fibonacci numbers or factorials.
+ */
+
+#ifndef ML99_NAT_H
+#define ML99_NAT_H
+
+#include <metalang99/priv/bool.h>
+
+#include <metalang99/nat/dec.h>
+#include <metalang99/nat/div.h>
+#include <metalang99/nat/eq.h>
+#include <metalang99/nat/inc.h>
+
+#include <metalang99/lang.h>
+
+/**
+ * \f$x + 1\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 6
+ * ML99_inc(v(5))
+ * @endcode
+ *
+ * @note If @p x is #ML99_NAT_MAX, the result is 0.
+ */
+#define ML99_inc(x) ML99_call(ML99_inc, x)
+
+/**
+ * \f$x - 1\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 4
+ * ML99_dec(v(5))
+ * @endcode
+ *
+ * @note If @p x is 0, the result is #ML99_NAT_MAX.
+ */
+#define ML99_dec(x) ML99_call(ML99_dec, x)
+
+/**
+ * Matches @p x against the two cases: if it is zero or positive.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * #define MATCH_Z_IMPL() v(Billie)
+ * #define MATCH_S_IMPL(x) v(Jean ~ x)
+ *
+ * // Billie
+ * ML99_natMatch(v(0), v(MATCH_))
+ *
+ * // Jean ~ 122
+ * ML99_natMatch(v(123), v(MATCH_))
+ * @endcode
+ *
+ * @note This function calls @p f with #ML99_call, so no partial application occurs, and so
+ * arity specifiers are not needed.
+ */
+#define ML99_natMatch(x, matcher) ML99_call(ML99_natMatch, x, matcher)
+
+/**
+ * The same as #ML99_natMatch but provides additional arguments to all branches.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * #define MATCH_Z_IMPL(x, y, z) v(Billie ~ x y z)
+ * #define MATCH_S_IMPL(n, x, y, z) v(Jean ~ n ~ x y z)
+ *
+ * // Billie ~ 1 2 3
+ * ML99_natMatchWithArgs(v(0), v(MATCH_), v(1, 2, 3))
+ *
+ * // Jean ~ 122 ~ 1 2 3
+ * ML99_natMatchWithArgs(v(123), v(MATCH_), v(1, 2, 3))
+ * @endcode
+ */
+#define ML99_natMatchWithArgs(x, matcher, ...) \
+ ML99_call(ML99_natMatchWithArgs, x, matcher, __VA_ARGS__)
+
+/**
+ * \f$x = y\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 1
+ * ML99_natEq(v(5), v(5))
+ *
+ * // 0
+ * ML99_natEq(v(3), v(8))
+ * @endcode
+ */
+#define ML99_natEq(x, y) ML99_call(ML99_natEq, x, y)
+
+/**
+ * \f$x \neq y\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 0
+ * ML99_natNeq(v(5), v(5))
+ *
+ * // 1
+ * ML99_natNeq(v(3), v(8))
+ * @endcode
+ */
+#define ML99_natNeq(x, y) ML99_call(ML99_natNeq, x, y)
+
+/**
+ * \f$x > y\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 1
+ * ML99_greater(v(8), v(3))
+ *
+ * // 0
+ * ML99_greater(v(3), v(8))
+ * @endcode
+ */
+#define ML99_greater(x, y) ML99_call(ML99_greater, x, y)
+
+/**
+ * \f$x \geq y\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 1
+ * ML99_greaterEq(v(8), v(8))
+ *
+ * // 0
+ * ML99_greaterEq(v(3), v(8))
+ * @endcode
+ */
+#define ML99_greaterEq(x, y) ML99_call(ML99_greaterEq, x, y)
+
+/**
+ * \f$x < y\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 1
+ * ML99_lesser(v(3), v(8))
+ *
+ * // 0
+ * ML99_lesser(v(8), v(3))
+ * @endcode
+ */
+#define ML99_lesser(x, y) ML99_call(ML99_lesser, x, y)
+
+/**
+ * \f$x \leq y\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 1
+ * ML99_lesserEq(v(8), v(8))
+ *
+ * // 0
+ * ML99_lesserEq(v(8), v(3))
+ * @endcode
+ */
+#define ML99_lesserEq(x, y) ML99_call(ML99_lesserEq, x, y)
+
+/**
+ * \f$x + y\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 11
+ * ML99_add(v(5), v(6))
+ * @endcode
+ */
+#define ML99_add(x, y) ML99_call(ML99_add, x, y)
+
+/**
+ * \f$x - y\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 6
+ * ML99_sub(v(11), v(5))
+ * @endcode
+ */
+#define ML99_sub(x, y) ML99_call(ML99_sub, x, y)
+
+/**
+ * \f$x * y\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 12
+ * ML99_mul(v(3), v(4))
+ * @endcode
+ */
+#define ML99_mul(x, y) ML99_call(ML99_mul, x, y)
+
+/**
+ * \f$\frac{x}{y}\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 3
+ * ML99_div(v(12), v(4))
+ * @endcode
+ *
+ * @note A compile-time error if \f$\frac{x}{y}\f$ is not a natural number.
+ */
+#define ML99_div(x, y) ML99_call(ML99_div, x, y)
+
+/**
+ * Like #ML99_div but returns `ML99_nothing()` is @p x is not divisible by @p y,
+ * otherwise `ML99_just(result)`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // ML99_just(3)
+ * ML99_divChecked(v(12), v(4))
+ *
+ * // ML99_nothing()
+ * ML99_divChecked(v(14), v(5))
+ *
+ * // ML99_nothing()
+ * ML99_divChecked(v(1), v(0))
+ * @endcode
+ */
+#define ML99_divChecked(x, y) ML99_call(ML99_divChecked, x, y)
+
+/**
+ * Computes the remainder of division.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 2
+ * ML99_mod(v(8), v(3))
+ * @endcode
+ *
+ * @note A compile-time error if @p y is 0.
+ */
+#define ML99_mod(x, y) ML99_call(ML99_mod, x, y)
+
+/**
+ * \f$x + y + z\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 15
+ * ML99_add3(v(1), v(6), v(8))
+ * @endcode
+ */
+#define ML99_add3(x, y, z) ML99_call(ML99_add3, x, y, z)
+
+/**
+ * \f$x - y - z\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 3
+ * ML99_sub3(v(8), v(2), v(3))
+ * @endcode
+ */
+#define ML99_sub3(x, y, z) ML99_call(ML99_sub3, x, y, z)
+
+/**
+ * \f$x * y * z\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 24
+ * ML99_mul3(v(2), v(3), v(4))
+ * @endcode
+ */
+#define ML99_mul3(x, y, z) ML99_call(ML99_mul3, x, y, z)
+
+/**
+ * \f$\frac{(\frac{x}{y})}{z}\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 5
+ * ML99_div(v(30), v(3), v(2))
+ * @endcode
+ *
+ * @note A compile-time error if \f$\frac{(\frac{x}{y})}{z}\f$ is not a natural number.
+ */
+#define ML99_div3(x, y, z) ML99_call(ML99_div3, x, y, z)
+
+/**
+ * \f$min(x, y)\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 5
+ * ML99_min(v(5), v(7))
+ * @endcode
+ */
+#define ML99_min(x, y) ML99_call(ML99_min, x, y)
+
+/**
+ * \f$max(x, y)\f$
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * // 7
+ * ML99_max(v(5), v(7))
+ * @endcode
+ */
+#define ML99_max(x, y) ML99_call(ML99_max, x, y)
+
+/**
+ * Emits a fatal error if @p x is not a natural number, otherwise results in emptiness.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/nat.h>
+ *
+ * #define F_IMPL(x) ML99_TERMS(ML99_assertIsNat(v(x)), ML99_inc(v(x)))
+ *
+ * // 6
+ * ML99_call(F, v(5))
+ *
+ * // A compile-time number mismatch error.
+ * ML99_call(F, v(blah))
+ * @endcode
+ */
+#define ML99_assertIsNat(x) ML99_call(ML99_assertIsNat, x)
+
+#define ML99_INC(x) ML99_PRIV_INC(x)
+#define ML99_DEC(x) ML99_PRIV_DEC(x)
+#define ML99_NAT_EQ(x, y) ML99_PRIV_NAT_EQ(x, y)
+#define ML99_NAT_NEQ(x, y) ML99_PRIV_NOT(ML99_NAT_EQ(x, y))
+#define ML99_DIV_CHECKED(x, y) ML99_PRIV_DIV_CHECKED(x, y)
+
+/**
+ * The maximum value of a natural number, currently 255.
+ */
+#define ML99_NAT_MAX 255
+
+#ifndef DOXYGEN_IGNORE
+
+// Pattern matching {
+
+#define ML99_natMatch_IMPL(x, matcher) \
+ ML99_PRIV_IF( \
+ ML99_NAT_EQ(x, 0), \
+ ML99_callUneval(matcher##Z, ), \
+ ML99_callUneval(matcher##S, ML99_DEC(x)))
+
+#define ML99_natMatchWithArgs_IMPL(x, matcher, ...) \
+ ML99_PRIV_IF( \
+ ML99_NAT_EQ(x, 0), \
+ ML99_callUneval(matcher##Z, __VA_ARGS__), \
+ ML99_callUneval(matcher##S, ML99_DEC(x), __VA_ARGS__))
+// } (Pattern matching)
+
+// Comparison operators {
+
+#define ML99_natEq_IMPL(x, y) v(ML99_NAT_EQ(x, y))
+#define ML99_natNeq_IMPL(x, y) v(ML99_NAT_NEQ(x, y))
+
+#define ML99_lesser_IMPL(x, y) \
+ ML99_PRIV_IF( \
+ ML99_NAT_EQ(y, 0), \
+ v(ML99_PRIV_FALSE()), \
+ ML99_PRIV_IF( \
+ ML99_NAT_EQ(x, ML99_DEC(y)), \
+ v(ML99_PRIV_TRUE()), \
+ ML99_callUneval(ML99_lesser, x, ML99_DEC(y))))
+
+#define ML99_lesserEq_IMPL(x, y) ML99_greaterEq_IMPL(y, x)
+
+#define ML99_greater_IMPL(x, y) ML99_lesser_IMPL(y, x)
+#define ML99_greaterEq_IMPL(x, y) \
+ ML99_PRIV_IF(ML99_NAT_EQ(x, y), v(ML99_PRIV_TRUE()), ML99_greater_IMPL(x, y))
+// } (Comparison operators)
+
+// Arithmetical operators {
+
+#define ML99_inc_IMPL(x) v(ML99_INC(x))
+#define ML99_dec_IMPL(x) v(ML99_DEC(x))
+
+#define ML99_add_IMPL(x, y) \
+ ML99_PRIV_IF(ML99_NAT_EQ(y, 0), v(x), ML99_callUneval(ML99_add, ML99_INC(x), ML99_DEC(y)))
+#define ML99_sub_IMPL(x, y) \
+ ML99_PRIV_IF(ML99_NAT_EQ(y, 0), v(x), ML99_callUneval(ML99_sub, ML99_DEC(x), ML99_DEC(y)))
+#define ML99_mul_IMPL(x, y) \
+ ML99_PRIV_IF(ML99_NAT_EQ(y, 0), v(0), ML99_add(v(x), ML99_callUneval(ML99_mul, x, ML99_DEC(y))))
+
+#define ML99_add3_IMPL(x, y, z) ML99_add(ML99_add_IMPL(x, y), v(z))
+#define ML99_sub3_IMPL(x, y, z) ML99_sub(ML99_sub_IMPL(x, y), v(z))
+#define ML99_mul3_IMPL(x, y, z) ML99_mul(ML99_mul_IMPL(x, y), v(z))
+#define ML99_div3_IMPL(x, y, z) ML99_div(ML99_div_IMPL(x, y), v(z))
+
+#define ML99_min_IMPL(x, y) ML99_call(ML99_if, ML99_lesser_IMPL(x, y), v(x, y))
+#define ML99_max_IMPL(x, y) ML99_call(ML99_if, ML99_lesser_IMPL(x, y), v(y, x))
+
+#define ML99_divChecked_IMPL(x, y) v(ML99_DIV_CHECKED(x, y))
+
+// ML99_mod_IMPL {
+
+#define ML99_mod_IMPL(x, y) \
+ ML99_PRIV_IF( \
+ ML99_NAT_EQ(y, 0), \
+ ML99_fatal(ML99_mod, modulo by 0), \
+ ML99_PRIV_modAux_IMPL(x, y, 0))
+
+#define ML99_PRIV_modAux_IMPL(x, y, acc) \
+ ML99_PRIV_IF( \
+ ML99_PRIV_OR(ML99_NAT_EQ(x, 0), ML99_IS_JUST(ML99_DIV_CHECKED(x, y))), \
+ v(acc), \
+ ML99_callUneval(ML99_PRIV_modAux, ML99_DEC(x), y, ML99_INC(acc)))
+// } (ML99_mod_IMPL)
+
+// } (Arithmetical operators)
+
+#define ML99_assertIsNat_IMPL(x) \
+ ML99_PRIV_IF( \
+ ML99_PRIV_NAT_EQ(x, x), \
+ v(ML99_PRIV_EMPTY()), \
+ ML99_PRIV_ASSERT_IS_NAT_FATAL(x, ML99_NAT_MAX))
+
+// clang-format off
+#define ML99_PRIV_ASSERT_IS_NAT_FATAL(x, max) ML99_fatal(ML99_assertIsNat, x must be within [0; max])
+// clang-format on
+
+// Arity specifiers {
+
+#define ML99_inc_ARITY 1
+#define ML99_dec_ARITY 1
+#define ML99_natMatch_ARITY 2
+#define ML99_natMatchWithArgs_ARITY 3
+#define ML99_natEq_ARITY 2
+#define ML99_natNeq_ARITY 2
+#define ML99_greater_ARITY 2
+#define ML99_greaterEq_ARITY 2
+#define ML99_lesser_ARITY 2
+#define ML99_lesserEq_ARITY 2
+#define ML99_add_ARITY 2
+#define ML99_sub_ARITY 2
+#define ML99_mul_ARITY 2
+#define ML99_div_ARITY 2
+#define ML99_divChecked_ARITY 2
+#define ML99_mod_ARITY 2
+#define ML99_add3_ARITY 3
+#define ML99_sub3_ARITY 3
+#define ML99_mul3_ARITY 3
+#define ML99_div3_ARITY 3
+#define ML99_min_ARITY 2
+#define ML99_max_ARITY 2
+#define ML99_assertIsNat_ARITY 1
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_NAT_H
diff --git a/test/external/metalang99/include/metalang99/nat/dec.h b/test/external/metalang99/include/metalang99/nat/dec.h
new file mode 100644
index 0000000..f58dba8
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/nat/dec.h
@@ -0,0 +1,264 @@
+#ifndef ML99_NAT_DEC_H
+#define ML99_NAT_DEC_H
+
+#define ML99_PRIV_DEC(x) ML99_PRIV_DEC_AUX(x)
+#define ML99_PRIV_DEC_AUX(x) ML99_PRIV_DEC_##x
+
+#define ML99_PRIV_DEC_0 255
+#define ML99_PRIV_DEC_1 0
+#define ML99_PRIV_DEC_2 1
+#define ML99_PRIV_DEC_3 2
+#define ML99_PRIV_DEC_4 3
+#define ML99_PRIV_DEC_5 4
+#define ML99_PRIV_DEC_6 5
+#define ML99_PRIV_DEC_7 6
+#define ML99_PRIV_DEC_8 7
+#define ML99_PRIV_DEC_9 8
+#define ML99_PRIV_DEC_10 9
+#define ML99_PRIV_DEC_11 10
+#define ML99_PRIV_DEC_12 11
+#define ML99_PRIV_DEC_13 12
+#define ML99_PRIV_DEC_14 13
+#define ML99_PRIV_DEC_15 14
+#define ML99_PRIV_DEC_16 15
+#define ML99_PRIV_DEC_17 16
+#define ML99_PRIV_DEC_18 17
+#define ML99_PRIV_DEC_19 18
+#define ML99_PRIV_DEC_20 19
+#define ML99_PRIV_DEC_21 20
+#define ML99_PRIV_DEC_22 21
+#define ML99_PRIV_DEC_23 22
+#define ML99_PRIV_DEC_24 23
+#define ML99_PRIV_DEC_25 24
+#define ML99_PRIV_DEC_26 25
+#define ML99_PRIV_DEC_27 26
+#define ML99_PRIV_DEC_28 27
+#define ML99_PRIV_DEC_29 28
+#define ML99_PRIV_DEC_30 29
+#define ML99_PRIV_DEC_31 30
+#define ML99_PRIV_DEC_32 31
+#define ML99_PRIV_DEC_33 32
+#define ML99_PRIV_DEC_34 33
+#define ML99_PRIV_DEC_35 34
+#define ML99_PRIV_DEC_36 35
+#define ML99_PRIV_DEC_37 36
+#define ML99_PRIV_DEC_38 37
+#define ML99_PRIV_DEC_39 38
+#define ML99_PRIV_DEC_40 39
+#define ML99_PRIV_DEC_41 40
+#define ML99_PRIV_DEC_42 41
+#define ML99_PRIV_DEC_43 42
+#define ML99_PRIV_DEC_44 43
+#define ML99_PRIV_DEC_45 44
+#define ML99_PRIV_DEC_46 45
+#define ML99_PRIV_DEC_47 46
+#define ML99_PRIV_DEC_48 47
+#define ML99_PRIV_DEC_49 48
+#define ML99_PRIV_DEC_50 49
+#define ML99_PRIV_DEC_51 50
+#define ML99_PRIV_DEC_52 51
+#define ML99_PRIV_DEC_53 52
+#define ML99_PRIV_DEC_54 53
+#define ML99_PRIV_DEC_55 54
+#define ML99_PRIV_DEC_56 55
+#define ML99_PRIV_DEC_57 56
+#define ML99_PRIV_DEC_58 57
+#define ML99_PRIV_DEC_59 58
+#define ML99_PRIV_DEC_60 59
+#define ML99_PRIV_DEC_61 60
+#define ML99_PRIV_DEC_62 61
+#define ML99_PRIV_DEC_63 62
+#define ML99_PRIV_DEC_64 63
+#define ML99_PRIV_DEC_65 64
+#define ML99_PRIV_DEC_66 65
+#define ML99_PRIV_DEC_67 66
+#define ML99_PRIV_DEC_68 67
+#define ML99_PRIV_DEC_69 68
+#define ML99_PRIV_DEC_70 69
+#define ML99_PRIV_DEC_71 70
+#define ML99_PRIV_DEC_72 71
+#define ML99_PRIV_DEC_73 72
+#define ML99_PRIV_DEC_74 73
+#define ML99_PRIV_DEC_75 74
+#define ML99_PRIV_DEC_76 75
+#define ML99_PRIV_DEC_77 76
+#define ML99_PRIV_DEC_78 77
+#define ML99_PRIV_DEC_79 78
+#define ML99_PRIV_DEC_80 79
+#define ML99_PRIV_DEC_81 80
+#define ML99_PRIV_DEC_82 81
+#define ML99_PRIV_DEC_83 82
+#define ML99_PRIV_DEC_84 83
+#define ML99_PRIV_DEC_85 84
+#define ML99_PRIV_DEC_86 85
+#define ML99_PRIV_DEC_87 86
+#define ML99_PRIV_DEC_88 87
+#define ML99_PRIV_DEC_89 88
+#define ML99_PRIV_DEC_90 89
+#define ML99_PRIV_DEC_91 90
+#define ML99_PRIV_DEC_92 91
+#define ML99_PRIV_DEC_93 92
+#define ML99_PRIV_DEC_94 93
+#define ML99_PRIV_DEC_95 94
+#define ML99_PRIV_DEC_96 95
+#define ML99_PRIV_DEC_97 96
+#define ML99_PRIV_DEC_98 97
+#define ML99_PRIV_DEC_99 98
+#define ML99_PRIV_DEC_100 99
+#define ML99_PRIV_DEC_101 100
+#define ML99_PRIV_DEC_102 101
+#define ML99_PRIV_DEC_103 102
+#define ML99_PRIV_DEC_104 103
+#define ML99_PRIV_DEC_105 104
+#define ML99_PRIV_DEC_106 105
+#define ML99_PRIV_DEC_107 106
+#define ML99_PRIV_DEC_108 107
+#define ML99_PRIV_DEC_109 108
+#define ML99_PRIV_DEC_110 109
+#define ML99_PRIV_DEC_111 110
+#define ML99_PRIV_DEC_112 111
+#define ML99_PRIV_DEC_113 112
+#define ML99_PRIV_DEC_114 113
+#define ML99_PRIV_DEC_115 114
+#define ML99_PRIV_DEC_116 115
+#define ML99_PRIV_DEC_117 116
+#define ML99_PRIV_DEC_118 117
+#define ML99_PRIV_DEC_119 118
+#define ML99_PRIV_DEC_120 119
+#define ML99_PRIV_DEC_121 120
+#define ML99_PRIV_DEC_122 121
+#define ML99_PRIV_DEC_123 122
+#define ML99_PRIV_DEC_124 123
+#define ML99_PRIV_DEC_125 124
+#define ML99_PRIV_DEC_126 125
+#define ML99_PRIV_DEC_127 126
+#define ML99_PRIV_DEC_128 127
+#define ML99_PRIV_DEC_129 128
+#define ML99_PRIV_DEC_130 129
+#define ML99_PRIV_DEC_131 130
+#define ML99_PRIV_DEC_132 131
+#define ML99_PRIV_DEC_133 132
+#define ML99_PRIV_DEC_134 133
+#define ML99_PRIV_DEC_135 134
+#define ML99_PRIV_DEC_136 135
+#define ML99_PRIV_DEC_137 136
+#define ML99_PRIV_DEC_138 137
+#define ML99_PRIV_DEC_139 138
+#define ML99_PRIV_DEC_140 139
+#define ML99_PRIV_DEC_141 140
+#define ML99_PRIV_DEC_142 141
+#define ML99_PRIV_DEC_143 142
+#define ML99_PRIV_DEC_144 143
+#define ML99_PRIV_DEC_145 144
+#define ML99_PRIV_DEC_146 145
+#define ML99_PRIV_DEC_147 146
+#define ML99_PRIV_DEC_148 147
+#define ML99_PRIV_DEC_149 148
+#define ML99_PRIV_DEC_150 149
+#define ML99_PRIV_DEC_151 150
+#define ML99_PRIV_DEC_152 151
+#define ML99_PRIV_DEC_153 152
+#define ML99_PRIV_DEC_154 153
+#define ML99_PRIV_DEC_155 154
+#define ML99_PRIV_DEC_156 155
+#define ML99_PRIV_DEC_157 156
+#define ML99_PRIV_DEC_158 157
+#define ML99_PRIV_DEC_159 158
+#define ML99_PRIV_DEC_160 159
+#define ML99_PRIV_DEC_161 160
+#define ML99_PRIV_DEC_162 161
+#define ML99_PRIV_DEC_163 162
+#define ML99_PRIV_DEC_164 163
+#define ML99_PRIV_DEC_165 164
+#define ML99_PRIV_DEC_166 165
+#define ML99_PRIV_DEC_167 166
+#define ML99_PRIV_DEC_168 167
+#define ML99_PRIV_DEC_169 168
+#define ML99_PRIV_DEC_170 169
+#define ML99_PRIV_DEC_171 170
+#define ML99_PRIV_DEC_172 171
+#define ML99_PRIV_DEC_173 172
+#define ML99_PRIV_DEC_174 173
+#define ML99_PRIV_DEC_175 174
+#define ML99_PRIV_DEC_176 175
+#define ML99_PRIV_DEC_177 176
+#define ML99_PRIV_DEC_178 177
+#define ML99_PRIV_DEC_179 178
+#define ML99_PRIV_DEC_180 179
+#define ML99_PRIV_DEC_181 180
+#define ML99_PRIV_DEC_182 181
+#define ML99_PRIV_DEC_183 182
+#define ML99_PRIV_DEC_184 183
+#define ML99_PRIV_DEC_185 184
+#define ML99_PRIV_DEC_186 185
+#define ML99_PRIV_DEC_187 186
+#define ML99_PRIV_DEC_188 187
+#define ML99_PRIV_DEC_189 188
+#define ML99_PRIV_DEC_190 189
+#define ML99_PRIV_DEC_191 190
+#define ML99_PRIV_DEC_192 191
+#define ML99_PRIV_DEC_193 192
+#define ML99_PRIV_DEC_194 193
+#define ML99_PRIV_DEC_195 194
+#define ML99_PRIV_DEC_196 195
+#define ML99_PRIV_DEC_197 196
+#define ML99_PRIV_DEC_198 197
+#define ML99_PRIV_DEC_199 198
+#define ML99_PRIV_DEC_200 199
+#define ML99_PRIV_DEC_201 200
+#define ML99_PRIV_DEC_202 201
+#define ML99_PRIV_DEC_203 202
+#define ML99_PRIV_DEC_204 203
+#define ML99_PRIV_DEC_205 204
+#define ML99_PRIV_DEC_206 205
+#define ML99_PRIV_DEC_207 206
+#define ML99_PRIV_DEC_208 207
+#define ML99_PRIV_DEC_209 208
+#define ML99_PRIV_DEC_210 209
+#define ML99_PRIV_DEC_211 210
+#define ML99_PRIV_DEC_212 211
+#define ML99_PRIV_DEC_213 212
+#define ML99_PRIV_DEC_214 213
+#define ML99_PRIV_DEC_215 214
+#define ML99_PRIV_DEC_216 215
+#define ML99_PRIV_DEC_217 216
+#define ML99_PRIV_DEC_218 217
+#define ML99_PRIV_DEC_219 218
+#define ML99_PRIV_DEC_220 219
+#define ML99_PRIV_DEC_221 220
+#define ML99_PRIV_DEC_222 221
+#define ML99_PRIV_DEC_223 222
+#define ML99_PRIV_DEC_224 223
+#define ML99_PRIV_DEC_225 224
+#define ML99_PRIV_DEC_226 225
+#define ML99_PRIV_DEC_227 226
+#define ML99_PRIV_DEC_228 227
+#define ML99_PRIV_DEC_229 228
+#define ML99_PRIV_DEC_230 229
+#define ML99_PRIV_DEC_231 230
+#define ML99_PRIV_DEC_232 231
+#define ML99_PRIV_DEC_233 232
+#define ML99_PRIV_DEC_234 233
+#define ML99_PRIV_DEC_235 234
+#define ML99_PRIV_DEC_236 235
+#define ML99_PRIV_DEC_237 236
+#define ML99_PRIV_DEC_238 237
+#define ML99_PRIV_DEC_239 238
+#define ML99_PRIV_DEC_240 239
+#define ML99_PRIV_DEC_241 240
+#define ML99_PRIV_DEC_242 241
+#define ML99_PRIV_DEC_243 242
+#define ML99_PRIV_DEC_244 243
+#define ML99_PRIV_DEC_245 244
+#define ML99_PRIV_DEC_246 245
+#define ML99_PRIV_DEC_247 246
+#define ML99_PRIV_DEC_248 247
+#define ML99_PRIV_DEC_249 248
+#define ML99_PRIV_DEC_250 249
+#define ML99_PRIV_DEC_251 250
+#define ML99_PRIV_DEC_252 251
+#define ML99_PRIV_DEC_253 252
+#define ML99_PRIV_DEC_254 253
+#define ML99_PRIV_DEC_255 254
+
+#endif // ML99_NAT_DEC_H
diff --git a/test/external/metalang99/include/metalang99/nat/div.h b/test/external/metalang99/include/metalang99/nat/div.h
new file mode 100644
index 0000000..ebd0b13
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/nat/div.h
@@ -0,0 +1,1172 @@
+#ifndef ML99_NAT_DIV_H
+#define ML99_NAT_DIV_H
+
+#include <metalang99/priv/bool.h>
+#include <metalang99/priv/util.h>
+
+#include <metalang99/maybe.h>
+#include <metalang99/tuple.h>
+
+#define ML99_div_IMPL(x, y) \
+ ML99_matchWithArgs_IMPL(ML99_PRIV_DIV_CHECKED(x, y), ML99_PRIV_DIV_, x, y)
+#define ML99_PRIV_DIV_nothing_IMPL(_, x, y) ML99_fatal(ML99_div, x is not divisible by y)
+#define ML99_PRIV_DIV_just_IMPL(n, _x, _y) v(n)
+
+#define ML99_PRIV_DIV_CHECKED(x, y) \
+ ML99_PRIV_IF( \
+ ML99_PRIV_NAT_EQ(y, 1), \
+ ML99_JUST(x), \
+ ML99_PRIV_IF( \
+ ML99_PRIV_NAT_EQ(x, y), \
+ ML99_JUST(1), \
+ ML99_UNTUPLE(ML99_PRIV_SND(ML99_PRIV_DIV_##x##_##y, (ML99_NOTHING())))))
+
+#define ML99_PRIV_DIV_4_2 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_6_2 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_6_3 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_8_2 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_8_4 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_9_3 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_10_2 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_10_5 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_12_2 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_12_3 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_12_4 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_12_6 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_14_2 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_14_7 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_15_3 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_15_5 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_16_2 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_16_4 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_16_8 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_18_2 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_18_3 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_18_6 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_18_9 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_20_2 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_20_4 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_20_5 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_20_10 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_21_3 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_21_7 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_22_2 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_22_11 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_24_2 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_24_3 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_24_4 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_24_6 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_24_8 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_24_12 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_25_5 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_26_2 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_26_13 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_27_3 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_27_9 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_28_2 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_28_4 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_28_7 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_28_14 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_30_2 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_30_3 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_30_5 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_30_6 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_30_10 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_30_15 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_32_2 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_32_4 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_32_8 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_32_16 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_33_3 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_33_11 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_34_2 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_34_17 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_35_5 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_35_7 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_36_2 ~, (ML99_JUST(18))
+#define ML99_PRIV_DIV_36_3 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_36_4 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_36_6 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_36_9 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_36_12 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_36_18 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_38_2 ~, (ML99_JUST(19))
+#define ML99_PRIV_DIV_38_19 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_39_3 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_39_13 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_40_2 ~, (ML99_JUST(20))
+#define ML99_PRIV_DIV_40_4 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_40_5 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_40_8 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_40_10 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_40_20 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_42_2 ~, (ML99_JUST(21))
+#define ML99_PRIV_DIV_42_3 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_42_6 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_42_7 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_42_14 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_42_21 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_44_2 ~, (ML99_JUST(22))
+#define ML99_PRIV_DIV_44_4 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_44_11 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_44_22 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_45_3 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_45_5 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_45_9 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_45_15 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_46_2 ~, (ML99_JUST(23))
+#define ML99_PRIV_DIV_46_23 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_48_2 ~, (ML99_JUST(24))
+#define ML99_PRIV_DIV_48_3 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_48_4 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_48_6 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_48_8 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_48_12 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_48_16 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_48_24 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_49_7 ~, (ML99_JUST(7))
+
+#define ML99_PRIV_DIV_50_2 ~, (ML99_JUST(25))
+#define ML99_PRIV_DIV_50_5 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_50_10 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_50_25 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_51_3 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_51_17 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_52_2 ~, (ML99_JUST(26))
+#define ML99_PRIV_DIV_52_4 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_52_13 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_52_26 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_54_2 ~, (ML99_JUST(27))
+#define ML99_PRIV_DIV_54_3 ~, (ML99_JUST(18))
+#define ML99_PRIV_DIV_54_6 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_54_9 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_54_18 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_54_27 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_55_5 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_55_11 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_56_2 ~, (ML99_JUST(28))
+#define ML99_PRIV_DIV_56_4 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_56_7 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_56_8 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_56_14 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_56_28 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_57_3 ~, (ML99_JUST(19))
+#define ML99_PRIV_DIV_57_19 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_58_2 ~, (ML99_JUST(29))
+#define ML99_PRIV_DIV_58_29 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_60_2 ~, (ML99_JUST(30))
+#define ML99_PRIV_DIV_60_3 ~, (ML99_JUST(20))
+#define ML99_PRIV_DIV_60_4 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_60_5 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_60_6 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_60_10 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_60_12 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_60_15 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_60_20 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_60_30 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_62_2 ~, (ML99_JUST(31))
+#define ML99_PRIV_DIV_62_31 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_63_3 ~, (ML99_JUST(21))
+#define ML99_PRIV_DIV_63_7 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_63_9 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_63_21 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_64_2 ~, (ML99_JUST(32))
+#define ML99_PRIV_DIV_64_4 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_64_8 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_64_16 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_64_32 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_65_5 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_65_13 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_66_2 ~, (ML99_JUST(33))
+#define ML99_PRIV_DIV_66_3 ~, (ML99_JUST(22))
+#define ML99_PRIV_DIV_66_6 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_66_11 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_66_22 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_66_33 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_68_2 ~, (ML99_JUST(34))
+#define ML99_PRIV_DIV_68_4 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_68_17 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_68_34 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_69_3 ~, (ML99_JUST(23))
+#define ML99_PRIV_DIV_69_23 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_70_2 ~, (ML99_JUST(35))
+#define ML99_PRIV_DIV_70_5 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_70_7 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_70_10 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_70_14 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_70_35 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_72_2 ~, (ML99_JUST(36))
+#define ML99_PRIV_DIV_72_3 ~, (ML99_JUST(24))
+#define ML99_PRIV_DIV_72_4 ~, (ML99_JUST(18))
+#define ML99_PRIV_DIV_72_6 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_72_8 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_72_9 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_72_12 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_72_18 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_72_24 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_72_36 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_74_2 ~, (ML99_JUST(37))
+#define ML99_PRIV_DIV_74_37 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_75_3 ~, (ML99_JUST(25))
+#define ML99_PRIV_DIV_75_5 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_75_15 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_75_25 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_76_2 ~, (ML99_JUST(38))
+#define ML99_PRIV_DIV_76_4 ~, (ML99_JUST(19))
+#define ML99_PRIV_DIV_76_19 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_76_38 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_77_7 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_77_11 ~, (ML99_JUST(7))
+
+#define ML99_PRIV_DIV_78_2 ~, (ML99_JUST(39))
+#define ML99_PRIV_DIV_78_3 ~, (ML99_JUST(26))
+#define ML99_PRIV_DIV_78_6 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_78_13 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_78_26 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_78_39 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_80_2 ~, (ML99_JUST(40))
+#define ML99_PRIV_DIV_80_4 ~, (ML99_JUST(20))
+#define ML99_PRIV_DIV_80_5 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_80_8 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_80_10 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_80_16 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_80_20 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_80_40 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_81_3 ~, (ML99_JUST(27))
+#define ML99_PRIV_DIV_81_9 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_81_27 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_82_2 ~, (ML99_JUST(41))
+#define ML99_PRIV_DIV_82_41 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_84_2 ~, (ML99_JUST(42))
+#define ML99_PRIV_DIV_84_3 ~, (ML99_JUST(28))
+#define ML99_PRIV_DIV_84_4 ~, (ML99_JUST(21))
+#define ML99_PRIV_DIV_84_6 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_84_7 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_84_12 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_84_14 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_84_21 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_84_28 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_84_42 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_85_5 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_85_17 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_86_2 ~, (ML99_JUST(43))
+#define ML99_PRIV_DIV_86_43 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_87_3 ~, (ML99_JUST(29))
+#define ML99_PRIV_DIV_87_29 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_88_2 ~, (ML99_JUST(44))
+#define ML99_PRIV_DIV_88_4 ~, (ML99_JUST(22))
+#define ML99_PRIV_DIV_88_8 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_88_11 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_88_22 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_88_44 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_90_2 ~, (ML99_JUST(45))
+#define ML99_PRIV_DIV_90_3 ~, (ML99_JUST(30))
+#define ML99_PRIV_DIV_90_5 ~, (ML99_JUST(18))
+#define ML99_PRIV_DIV_90_6 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_90_9 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_90_10 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_90_15 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_90_18 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_90_30 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_90_45 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_91_7 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_91_13 ~, (ML99_JUST(7))
+
+#define ML99_PRIV_DIV_92_2 ~, (ML99_JUST(46))
+#define ML99_PRIV_DIV_92_4 ~, (ML99_JUST(23))
+#define ML99_PRIV_DIV_92_23 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_92_46 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_93_3 ~, (ML99_JUST(31))
+#define ML99_PRIV_DIV_93_31 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_94_2 ~, (ML99_JUST(47))
+#define ML99_PRIV_DIV_94_47 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_95_5 ~, (ML99_JUST(19))
+#define ML99_PRIV_DIV_95_19 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_96_2 ~, (ML99_JUST(48))
+#define ML99_PRIV_DIV_96_3 ~, (ML99_JUST(32))
+#define ML99_PRIV_DIV_96_4 ~, (ML99_JUST(24))
+#define ML99_PRIV_DIV_96_6 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_96_8 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_96_12 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_96_16 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_96_24 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_96_32 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_96_48 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_98_2 ~, (ML99_JUST(49))
+#define ML99_PRIV_DIV_98_7 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_98_14 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_98_49 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_99_3 ~, (ML99_JUST(33))
+#define ML99_PRIV_DIV_99_9 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_99_11 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_99_33 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_100_2 ~, (ML99_JUST(50))
+#define ML99_PRIV_DIV_100_4 ~, (ML99_JUST(25))
+#define ML99_PRIV_DIV_100_5 ~, (ML99_JUST(20))
+#define ML99_PRIV_DIV_100_10 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_100_20 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_100_25 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_100_50 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_102_2 ~, (ML99_JUST(51))
+#define ML99_PRIV_DIV_102_3 ~, (ML99_JUST(34))
+#define ML99_PRIV_DIV_102_6 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_102_17 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_102_34 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_102_51 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_104_2 ~, (ML99_JUST(52))
+#define ML99_PRIV_DIV_104_4 ~, (ML99_JUST(26))
+#define ML99_PRIV_DIV_104_8 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_104_13 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_104_26 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_104_52 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_105_3 ~, (ML99_JUST(35))
+#define ML99_PRIV_DIV_105_5 ~, (ML99_JUST(21))
+#define ML99_PRIV_DIV_105_7 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_105_15 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_105_21 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_105_35 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_106_2 ~, (ML99_JUST(53))
+#define ML99_PRIV_DIV_106_53 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_108_2 ~, (ML99_JUST(54))
+#define ML99_PRIV_DIV_108_3 ~, (ML99_JUST(36))
+#define ML99_PRIV_DIV_108_4 ~, (ML99_JUST(27))
+#define ML99_PRIV_DIV_108_6 ~, (ML99_JUST(18))
+#define ML99_PRIV_DIV_108_9 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_108_12 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_108_18 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_108_27 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_108_36 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_108_54 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_110_2 ~, (ML99_JUST(55))
+#define ML99_PRIV_DIV_110_5 ~, (ML99_JUST(22))
+#define ML99_PRIV_DIV_110_10 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_110_11 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_110_22 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_110_55 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_111_3 ~, (ML99_JUST(37))
+#define ML99_PRIV_DIV_111_37 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_112_2 ~, (ML99_JUST(56))
+#define ML99_PRIV_DIV_112_4 ~, (ML99_JUST(28))
+#define ML99_PRIV_DIV_112_7 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_112_8 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_112_14 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_112_16 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_112_28 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_112_56 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_114_2 ~, (ML99_JUST(57))
+#define ML99_PRIV_DIV_114_3 ~, (ML99_JUST(38))
+#define ML99_PRIV_DIV_114_6 ~, (ML99_JUST(19))
+#define ML99_PRIV_DIV_114_19 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_114_38 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_114_57 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_115_5 ~, (ML99_JUST(23))
+#define ML99_PRIV_DIV_115_23 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_116_2 ~, (ML99_JUST(58))
+#define ML99_PRIV_DIV_116_4 ~, (ML99_JUST(29))
+#define ML99_PRIV_DIV_116_29 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_116_58 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_117_3 ~, (ML99_JUST(39))
+#define ML99_PRIV_DIV_117_9 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_117_13 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_117_39 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_118_2 ~, (ML99_JUST(59))
+#define ML99_PRIV_DIV_118_59 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_119_7 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_119_17 ~, (ML99_JUST(7))
+
+#define ML99_PRIV_DIV_120_2 ~, (ML99_JUST(60))
+#define ML99_PRIV_DIV_120_3 ~, (ML99_JUST(40))
+#define ML99_PRIV_DIV_120_4 ~, (ML99_JUST(30))
+#define ML99_PRIV_DIV_120_5 ~, (ML99_JUST(24))
+#define ML99_PRIV_DIV_120_6 ~, (ML99_JUST(20))
+#define ML99_PRIV_DIV_120_8 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_120_10 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_120_12 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_120_15 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_120_20 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_120_24 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_120_30 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_120_40 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_120_60 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_121_11 ~, (ML99_JUST(11))
+
+#define ML99_PRIV_DIV_122_2 ~, (ML99_JUST(61))
+#define ML99_PRIV_DIV_122_61 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_123_3 ~, (ML99_JUST(41))
+#define ML99_PRIV_DIV_123_41 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_124_2 ~, (ML99_JUST(62))
+#define ML99_PRIV_DIV_124_4 ~, (ML99_JUST(31))
+#define ML99_PRIV_DIV_124_31 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_124_62 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_125_5 ~, (ML99_JUST(25))
+#define ML99_PRIV_DIV_125_25 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_126_2 ~, (ML99_JUST(63))
+#define ML99_PRIV_DIV_126_3 ~, (ML99_JUST(42))
+#define ML99_PRIV_DIV_126_6 ~, (ML99_JUST(21))
+#define ML99_PRIV_DIV_126_7 ~, (ML99_JUST(18))
+#define ML99_PRIV_DIV_126_9 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_126_14 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_126_18 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_126_21 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_126_42 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_126_63 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_128_2 ~, (ML99_JUST(64))
+#define ML99_PRIV_DIV_128_4 ~, (ML99_JUST(32))
+#define ML99_PRIV_DIV_128_8 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_128_16 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_128_32 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_128_64 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_129_3 ~, (ML99_JUST(43))
+#define ML99_PRIV_DIV_129_43 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_130_2 ~, (ML99_JUST(65))
+#define ML99_PRIV_DIV_130_5 ~, (ML99_JUST(26))
+#define ML99_PRIV_DIV_130_10 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_130_13 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_130_26 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_130_65 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_132_2 ~, (ML99_JUST(66))
+#define ML99_PRIV_DIV_132_3 ~, (ML99_JUST(44))
+#define ML99_PRIV_DIV_132_4 ~, (ML99_JUST(33))
+#define ML99_PRIV_DIV_132_6 ~, (ML99_JUST(22))
+#define ML99_PRIV_DIV_132_11 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_132_12 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_132_22 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_132_33 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_132_44 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_132_66 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_133_7 ~, (ML99_JUST(19))
+#define ML99_PRIV_DIV_133_19 ~, (ML99_JUST(7))
+
+#define ML99_PRIV_DIV_134_2 ~, (ML99_JUST(67))
+#define ML99_PRIV_DIV_134_67 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_135_3 ~, (ML99_JUST(45))
+#define ML99_PRIV_DIV_135_5 ~, (ML99_JUST(27))
+#define ML99_PRIV_DIV_135_9 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_135_15 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_135_27 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_135_45 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_136_2 ~, (ML99_JUST(68))
+#define ML99_PRIV_DIV_136_4 ~, (ML99_JUST(34))
+#define ML99_PRIV_DIV_136_8 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_136_17 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_136_34 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_136_68 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_138_2 ~, (ML99_JUST(69))
+#define ML99_PRIV_DIV_138_3 ~, (ML99_JUST(46))
+#define ML99_PRIV_DIV_138_6 ~, (ML99_JUST(23))
+#define ML99_PRIV_DIV_138_23 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_138_46 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_138_69 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_140_2 ~, (ML99_JUST(70))
+#define ML99_PRIV_DIV_140_4 ~, (ML99_JUST(35))
+#define ML99_PRIV_DIV_140_5 ~, (ML99_JUST(28))
+#define ML99_PRIV_DIV_140_7 ~, (ML99_JUST(20))
+#define ML99_PRIV_DIV_140_10 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_140_14 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_140_20 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_140_28 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_140_35 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_140_70 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_141_3 ~, (ML99_JUST(47))
+#define ML99_PRIV_DIV_141_47 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_142_2 ~, (ML99_JUST(71))
+#define ML99_PRIV_DIV_142_71 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_143_11 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_143_13 ~, (ML99_JUST(11))
+
+#define ML99_PRIV_DIV_144_2 ~, (ML99_JUST(72))
+#define ML99_PRIV_DIV_144_3 ~, (ML99_JUST(48))
+#define ML99_PRIV_DIV_144_4 ~, (ML99_JUST(36))
+#define ML99_PRIV_DIV_144_6 ~, (ML99_JUST(24))
+#define ML99_PRIV_DIV_144_8 ~, (ML99_JUST(18))
+#define ML99_PRIV_DIV_144_9 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_144_12 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_144_16 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_144_18 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_144_24 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_144_36 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_144_48 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_144_72 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_145_5 ~, (ML99_JUST(29))
+#define ML99_PRIV_DIV_145_29 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_146_2 ~, (ML99_JUST(73))
+#define ML99_PRIV_DIV_146_73 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_147_3 ~, (ML99_JUST(49))
+#define ML99_PRIV_DIV_147_7 ~, (ML99_JUST(21))
+#define ML99_PRIV_DIV_147_21 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_147_49 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_148_2 ~, (ML99_JUST(74))
+#define ML99_PRIV_DIV_148_4 ~, (ML99_JUST(37))
+#define ML99_PRIV_DIV_148_37 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_148_74 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_150_2 ~, (ML99_JUST(75))
+#define ML99_PRIV_DIV_150_3 ~, (ML99_JUST(50))
+#define ML99_PRIV_DIV_150_5 ~, (ML99_JUST(30))
+#define ML99_PRIV_DIV_150_6 ~, (ML99_JUST(25))
+#define ML99_PRIV_DIV_150_10 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_150_15 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_150_25 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_150_30 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_150_50 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_150_75 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_152_2 ~, (ML99_JUST(76))
+#define ML99_PRIV_DIV_152_4 ~, (ML99_JUST(38))
+#define ML99_PRIV_DIV_152_8 ~, (ML99_JUST(19))
+#define ML99_PRIV_DIV_152_19 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_152_38 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_152_76 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_153_3 ~, (ML99_JUST(51))
+#define ML99_PRIV_DIV_153_9 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_153_17 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_153_51 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_154_2 ~, (ML99_JUST(77))
+#define ML99_PRIV_DIV_154_7 ~, (ML99_JUST(22))
+#define ML99_PRIV_DIV_154_11 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_154_14 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_154_22 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_154_77 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_155_5 ~, (ML99_JUST(31))
+#define ML99_PRIV_DIV_155_31 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_156_2 ~, (ML99_JUST(78))
+#define ML99_PRIV_DIV_156_3 ~, (ML99_JUST(52))
+#define ML99_PRIV_DIV_156_4 ~, (ML99_JUST(39))
+#define ML99_PRIV_DIV_156_6 ~, (ML99_JUST(26))
+#define ML99_PRIV_DIV_156_12 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_156_13 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_156_26 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_156_39 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_156_52 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_156_78 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_158_2 ~, (ML99_JUST(79))
+#define ML99_PRIV_DIV_158_79 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_159_3 ~, (ML99_JUST(53))
+#define ML99_PRIV_DIV_159_53 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_160_2 ~, (ML99_JUST(80))
+#define ML99_PRIV_DIV_160_4 ~, (ML99_JUST(40))
+#define ML99_PRIV_DIV_160_5 ~, (ML99_JUST(32))
+#define ML99_PRIV_DIV_160_8 ~, (ML99_JUST(20))
+#define ML99_PRIV_DIV_160_10 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_160_16 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_160_20 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_160_32 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_160_40 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_160_80 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_161_7 ~, (ML99_JUST(23))
+#define ML99_PRIV_DIV_161_23 ~, (ML99_JUST(7))
+
+#define ML99_PRIV_DIV_162_2 ~, (ML99_JUST(81))
+#define ML99_PRIV_DIV_162_3 ~, (ML99_JUST(54))
+#define ML99_PRIV_DIV_162_6 ~, (ML99_JUST(27))
+#define ML99_PRIV_DIV_162_9 ~, (ML99_JUST(18))
+#define ML99_PRIV_DIV_162_18 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_162_27 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_162_54 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_162_81 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_164_2 ~, (ML99_JUST(82))
+#define ML99_PRIV_DIV_164_4 ~, (ML99_JUST(41))
+#define ML99_PRIV_DIV_164_41 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_164_82 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_165_3 ~, (ML99_JUST(55))
+#define ML99_PRIV_DIV_165_5 ~, (ML99_JUST(33))
+#define ML99_PRIV_DIV_165_11 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_165_15 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_165_33 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_165_55 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_166_2 ~, (ML99_JUST(83))
+#define ML99_PRIV_DIV_166_83 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_168_2 ~, (ML99_JUST(84))
+#define ML99_PRIV_DIV_168_3 ~, (ML99_JUST(56))
+#define ML99_PRIV_DIV_168_4 ~, (ML99_JUST(42))
+#define ML99_PRIV_DIV_168_6 ~, (ML99_JUST(28))
+#define ML99_PRIV_DIV_168_7 ~, (ML99_JUST(24))
+#define ML99_PRIV_DIV_168_8 ~, (ML99_JUST(21))
+#define ML99_PRIV_DIV_168_12 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_168_14 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_168_21 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_168_24 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_168_28 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_168_42 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_168_56 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_168_84 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_169_13 ~, (ML99_JUST(13))
+
+#define ML99_PRIV_DIV_170_2 ~, (ML99_JUST(85))
+#define ML99_PRIV_DIV_170_5 ~, (ML99_JUST(34))
+#define ML99_PRIV_DIV_170_10 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_170_17 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_170_34 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_170_85 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_171_3 ~, (ML99_JUST(57))
+#define ML99_PRIV_DIV_171_9 ~, (ML99_JUST(19))
+#define ML99_PRIV_DIV_171_19 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_171_57 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_172_2 ~, (ML99_JUST(86))
+#define ML99_PRIV_DIV_172_4 ~, (ML99_JUST(43))
+#define ML99_PRIV_DIV_172_43 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_172_86 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_174_2 ~, (ML99_JUST(87))
+#define ML99_PRIV_DIV_174_3 ~, (ML99_JUST(58))
+#define ML99_PRIV_DIV_174_6 ~, (ML99_JUST(29))
+#define ML99_PRIV_DIV_174_29 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_174_58 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_174_87 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_175_5 ~, (ML99_JUST(35))
+#define ML99_PRIV_DIV_175_7 ~, (ML99_JUST(25))
+#define ML99_PRIV_DIV_175_25 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_175_35 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_176_2 ~, (ML99_JUST(88))
+#define ML99_PRIV_DIV_176_4 ~, (ML99_JUST(44))
+#define ML99_PRIV_DIV_176_8 ~, (ML99_JUST(22))
+#define ML99_PRIV_DIV_176_11 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_176_16 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_176_22 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_176_44 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_176_88 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_177_3 ~, (ML99_JUST(59))
+#define ML99_PRIV_DIV_177_59 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_178_2 ~, (ML99_JUST(89))
+#define ML99_PRIV_DIV_178_89 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_180_2 ~, (ML99_JUST(90))
+#define ML99_PRIV_DIV_180_3 ~, (ML99_JUST(60))
+#define ML99_PRIV_DIV_180_4 ~, (ML99_JUST(45))
+#define ML99_PRIV_DIV_180_5 ~, (ML99_JUST(36))
+#define ML99_PRIV_DIV_180_6 ~, (ML99_JUST(30))
+#define ML99_PRIV_DIV_180_9 ~, (ML99_JUST(20))
+#define ML99_PRIV_DIV_180_10 ~, (ML99_JUST(18))
+#define ML99_PRIV_DIV_180_12 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_180_15 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_180_18 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_180_20 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_180_30 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_180_36 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_180_45 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_180_60 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_180_90 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_182_2 ~, (ML99_JUST(91))
+#define ML99_PRIV_DIV_182_7 ~, (ML99_JUST(26))
+#define ML99_PRIV_DIV_182_13 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_182_14 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_182_26 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_182_91 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_183_3 ~, (ML99_JUST(61))
+#define ML99_PRIV_DIV_183_61 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_184_2 ~, (ML99_JUST(92))
+#define ML99_PRIV_DIV_184_4 ~, (ML99_JUST(46))
+#define ML99_PRIV_DIV_184_8 ~, (ML99_JUST(23))
+#define ML99_PRIV_DIV_184_23 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_184_46 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_184_92 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_185_5 ~, (ML99_JUST(37))
+#define ML99_PRIV_DIV_185_37 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_186_2 ~, (ML99_JUST(93))
+#define ML99_PRIV_DIV_186_3 ~, (ML99_JUST(62))
+#define ML99_PRIV_DIV_186_6 ~, (ML99_JUST(31))
+#define ML99_PRIV_DIV_186_31 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_186_62 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_186_93 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_187_11 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_187_17 ~, (ML99_JUST(11))
+
+#define ML99_PRIV_DIV_188_2 ~, (ML99_JUST(94))
+#define ML99_PRIV_DIV_188_4 ~, (ML99_JUST(47))
+#define ML99_PRIV_DIV_188_47 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_188_94 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_189_3 ~, (ML99_JUST(63))
+#define ML99_PRIV_DIV_189_7 ~, (ML99_JUST(27))
+#define ML99_PRIV_DIV_189_9 ~, (ML99_JUST(21))
+#define ML99_PRIV_DIV_189_21 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_189_27 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_189_63 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_190_2 ~, (ML99_JUST(95))
+#define ML99_PRIV_DIV_190_5 ~, (ML99_JUST(38))
+#define ML99_PRIV_DIV_190_10 ~, (ML99_JUST(19))
+#define ML99_PRIV_DIV_190_19 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_190_38 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_190_95 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_192_2 ~, (ML99_JUST(96))
+#define ML99_PRIV_DIV_192_3 ~, (ML99_JUST(64))
+#define ML99_PRIV_DIV_192_4 ~, (ML99_JUST(48))
+#define ML99_PRIV_DIV_192_6 ~, (ML99_JUST(32))
+#define ML99_PRIV_DIV_192_8 ~, (ML99_JUST(24))
+#define ML99_PRIV_DIV_192_12 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_192_16 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_192_24 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_192_32 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_192_48 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_192_64 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_192_96 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_194_2 ~, (ML99_JUST(97))
+#define ML99_PRIV_DIV_194_97 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_195_3 ~, (ML99_JUST(65))
+#define ML99_PRIV_DIV_195_5 ~, (ML99_JUST(39))
+#define ML99_PRIV_DIV_195_13 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_195_15 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_195_39 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_195_65 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_196_2 ~, (ML99_JUST(98))
+#define ML99_PRIV_DIV_196_4 ~, (ML99_JUST(49))
+#define ML99_PRIV_DIV_196_7 ~, (ML99_JUST(28))
+#define ML99_PRIV_DIV_196_14 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_196_28 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_196_49 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_196_98 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_198_2 ~, (ML99_JUST(99))
+#define ML99_PRIV_DIV_198_3 ~, (ML99_JUST(66))
+#define ML99_PRIV_DIV_198_6 ~, (ML99_JUST(33))
+#define ML99_PRIV_DIV_198_9 ~, (ML99_JUST(22))
+#define ML99_PRIV_DIV_198_11 ~, (ML99_JUST(18))
+#define ML99_PRIV_DIV_198_18 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_198_22 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_198_33 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_198_66 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_198_99 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_200_2 ~, (ML99_JUST(100))
+#define ML99_PRIV_DIV_200_4 ~, (ML99_JUST(50))
+#define ML99_PRIV_DIV_200_5 ~, (ML99_JUST(40))
+#define ML99_PRIV_DIV_200_8 ~, (ML99_JUST(25))
+#define ML99_PRIV_DIV_200_10 ~, (ML99_JUST(20))
+#define ML99_PRIV_DIV_200_20 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_200_25 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_200_40 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_200_50 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_200_100 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_201_3 ~, (ML99_JUST(67))
+#define ML99_PRIV_DIV_201_67 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_202_2 ~, (ML99_JUST(101))
+#define ML99_PRIV_DIV_202_101 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_203_7 ~, (ML99_JUST(29))
+#define ML99_PRIV_DIV_203_29 ~, (ML99_JUST(7))
+
+#define ML99_PRIV_DIV_204_2 ~, (ML99_JUST(102))
+#define ML99_PRIV_DIV_204_3 ~, (ML99_JUST(68))
+#define ML99_PRIV_DIV_204_4 ~, (ML99_JUST(51))
+#define ML99_PRIV_DIV_204_6 ~, (ML99_JUST(34))
+#define ML99_PRIV_DIV_204_12 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_204_17 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_204_34 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_204_51 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_204_68 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_204_102 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_205_5 ~, (ML99_JUST(41))
+#define ML99_PRIV_DIV_205_41 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_206_2 ~, (ML99_JUST(103))
+#define ML99_PRIV_DIV_206_103 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_207_3 ~, (ML99_JUST(69))
+#define ML99_PRIV_DIV_207_9 ~, (ML99_JUST(23))
+#define ML99_PRIV_DIV_207_23 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_207_69 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_208_2 ~, (ML99_JUST(104))
+#define ML99_PRIV_DIV_208_4 ~, (ML99_JUST(52))
+#define ML99_PRIV_DIV_208_8 ~, (ML99_JUST(26))
+#define ML99_PRIV_DIV_208_13 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_208_16 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_208_26 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_208_52 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_208_104 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_209_11 ~, (ML99_JUST(19))
+#define ML99_PRIV_DIV_209_19 ~, (ML99_JUST(11))
+
+#define ML99_PRIV_DIV_210_2 ~, (ML99_JUST(105))
+#define ML99_PRIV_DIV_210_3 ~, (ML99_JUST(70))
+#define ML99_PRIV_DIV_210_5 ~, (ML99_JUST(42))
+#define ML99_PRIV_DIV_210_6 ~, (ML99_JUST(35))
+#define ML99_PRIV_DIV_210_7 ~, (ML99_JUST(30))
+#define ML99_PRIV_DIV_210_10 ~, (ML99_JUST(21))
+#define ML99_PRIV_DIV_210_14 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_210_15 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_210_21 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_210_30 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_210_35 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_210_42 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_210_70 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_210_105 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_212_2 ~, (ML99_JUST(106))
+#define ML99_PRIV_DIV_212_4 ~, (ML99_JUST(53))
+#define ML99_PRIV_DIV_212_53 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_212_106 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_213_3 ~, (ML99_JUST(71))
+#define ML99_PRIV_DIV_213_71 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_214_2 ~, (ML99_JUST(107))
+#define ML99_PRIV_DIV_214_107 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_215_5 ~, (ML99_JUST(43))
+#define ML99_PRIV_DIV_215_43 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_216_2 ~, (ML99_JUST(108))
+#define ML99_PRIV_DIV_216_3 ~, (ML99_JUST(72))
+#define ML99_PRIV_DIV_216_4 ~, (ML99_JUST(54))
+#define ML99_PRIV_DIV_216_6 ~, (ML99_JUST(36))
+#define ML99_PRIV_DIV_216_8 ~, (ML99_JUST(27))
+#define ML99_PRIV_DIV_216_9 ~, (ML99_JUST(24))
+#define ML99_PRIV_DIV_216_12 ~, (ML99_JUST(18))
+#define ML99_PRIV_DIV_216_18 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_216_24 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_216_27 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_216_36 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_216_54 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_216_72 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_216_108 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_217_7 ~, (ML99_JUST(31))
+#define ML99_PRIV_DIV_217_31 ~, (ML99_JUST(7))
+
+#define ML99_PRIV_DIV_218_2 ~, (ML99_JUST(109))
+#define ML99_PRIV_DIV_218_109 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_219_3 ~, (ML99_JUST(73))
+#define ML99_PRIV_DIV_219_73 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_220_2 ~, (ML99_JUST(110))
+#define ML99_PRIV_DIV_220_4 ~, (ML99_JUST(55))
+#define ML99_PRIV_DIV_220_5 ~, (ML99_JUST(44))
+#define ML99_PRIV_DIV_220_10 ~, (ML99_JUST(22))
+#define ML99_PRIV_DIV_220_11 ~, (ML99_JUST(20))
+#define ML99_PRIV_DIV_220_20 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_220_22 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_220_44 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_220_55 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_220_110 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_221_13 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_221_17 ~, (ML99_JUST(13))
+
+#define ML99_PRIV_DIV_222_2 ~, (ML99_JUST(111))
+#define ML99_PRIV_DIV_222_3 ~, (ML99_JUST(74))
+#define ML99_PRIV_DIV_222_6 ~, (ML99_JUST(37))
+#define ML99_PRIV_DIV_222_37 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_222_74 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_222_111 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_224_2 ~, (ML99_JUST(112))
+#define ML99_PRIV_DIV_224_4 ~, (ML99_JUST(56))
+#define ML99_PRIV_DIV_224_7 ~, (ML99_JUST(32))
+#define ML99_PRIV_DIV_224_8 ~, (ML99_JUST(28))
+#define ML99_PRIV_DIV_224_14 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_224_16 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_224_28 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_224_32 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_224_56 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_224_112 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_225_3 ~, (ML99_JUST(75))
+#define ML99_PRIV_DIV_225_5 ~, (ML99_JUST(45))
+#define ML99_PRIV_DIV_225_9 ~, (ML99_JUST(25))
+#define ML99_PRIV_DIV_225_15 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_225_25 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_225_45 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_225_75 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_226_2 ~, (ML99_JUST(113))
+#define ML99_PRIV_DIV_226_113 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_228_2 ~, (ML99_JUST(114))
+#define ML99_PRIV_DIV_228_3 ~, (ML99_JUST(76))
+#define ML99_PRIV_DIV_228_4 ~, (ML99_JUST(57))
+#define ML99_PRIV_DIV_228_6 ~, (ML99_JUST(38))
+#define ML99_PRIV_DIV_228_12 ~, (ML99_JUST(19))
+#define ML99_PRIV_DIV_228_19 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_228_38 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_228_57 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_228_76 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_228_114 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_230_2 ~, (ML99_JUST(115))
+#define ML99_PRIV_DIV_230_5 ~, (ML99_JUST(46))
+#define ML99_PRIV_DIV_230_10 ~, (ML99_JUST(23))
+#define ML99_PRIV_DIV_230_23 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_230_46 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_230_115 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_231_3 ~, (ML99_JUST(77))
+#define ML99_PRIV_DIV_231_7 ~, (ML99_JUST(33))
+#define ML99_PRIV_DIV_231_11 ~, (ML99_JUST(21))
+#define ML99_PRIV_DIV_231_21 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_231_33 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_231_77 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_232_2 ~, (ML99_JUST(116))
+#define ML99_PRIV_DIV_232_4 ~, (ML99_JUST(58))
+#define ML99_PRIV_DIV_232_8 ~, (ML99_JUST(29))
+#define ML99_PRIV_DIV_232_29 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_232_58 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_232_116 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_234_2 ~, (ML99_JUST(117))
+#define ML99_PRIV_DIV_234_3 ~, (ML99_JUST(78))
+#define ML99_PRIV_DIV_234_6 ~, (ML99_JUST(39))
+#define ML99_PRIV_DIV_234_9 ~, (ML99_JUST(26))
+#define ML99_PRIV_DIV_234_13 ~, (ML99_JUST(18))
+#define ML99_PRIV_DIV_234_18 ~, (ML99_JUST(13))
+#define ML99_PRIV_DIV_234_26 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_234_39 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_234_78 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_234_117 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_235_5 ~, (ML99_JUST(47))
+#define ML99_PRIV_DIV_235_47 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_236_2 ~, (ML99_JUST(118))
+#define ML99_PRIV_DIV_236_4 ~, (ML99_JUST(59))
+#define ML99_PRIV_DIV_236_59 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_236_118 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_237_3 ~, (ML99_JUST(79))
+#define ML99_PRIV_DIV_237_79 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_238_2 ~, (ML99_JUST(119))
+#define ML99_PRIV_DIV_238_7 ~, (ML99_JUST(34))
+#define ML99_PRIV_DIV_238_14 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_238_17 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_238_34 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_238_119 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_240_2 ~, (ML99_JUST(120))
+#define ML99_PRIV_DIV_240_3 ~, (ML99_JUST(80))
+#define ML99_PRIV_DIV_240_4 ~, (ML99_JUST(60))
+#define ML99_PRIV_DIV_240_5 ~, (ML99_JUST(48))
+#define ML99_PRIV_DIV_240_6 ~, (ML99_JUST(40))
+#define ML99_PRIV_DIV_240_8 ~, (ML99_JUST(30))
+#define ML99_PRIV_DIV_240_10 ~, (ML99_JUST(24))
+#define ML99_PRIV_DIV_240_12 ~, (ML99_JUST(20))
+#define ML99_PRIV_DIV_240_15 ~, (ML99_JUST(16))
+#define ML99_PRIV_DIV_240_16 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_240_20 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_240_24 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_240_30 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_240_40 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_240_48 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_240_60 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_240_80 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_240_120 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_242_2 ~, (ML99_JUST(121))
+#define ML99_PRIV_DIV_242_11 ~, (ML99_JUST(22))
+#define ML99_PRIV_DIV_242_22 ~, (ML99_JUST(11))
+#define ML99_PRIV_DIV_242_121 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_243_3 ~, (ML99_JUST(81))
+#define ML99_PRIV_DIV_243_9 ~, (ML99_JUST(27))
+#define ML99_PRIV_DIV_243_27 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_243_81 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_244_2 ~, (ML99_JUST(122))
+#define ML99_PRIV_DIV_244_4 ~, (ML99_JUST(61))
+#define ML99_PRIV_DIV_244_61 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_244_122 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_245_5 ~, (ML99_JUST(49))
+#define ML99_PRIV_DIV_245_7 ~, (ML99_JUST(35))
+#define ML99_PRIV_DIV_245_35 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_245_49 ~, (ML99_JUST(5))
+
+#define ML99_PRIV_DIV_246_2 ~, (ML99_JUST(123))
+#define ML99_PRIV_DIV_246_3 ~, (ML99_JUST(82))
+#define ML99_PRIV_DIV_246_6 ~, (ML99_JUST(41))
+#define ML99_PRIV_DIV_246_41 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_246_82 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_246_123 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_247_13 ~, (ML99_JUST(19))
+#define ML99_PRIV_DIV_247_19 ~, (ML99_JUST(13))
+
+#define ML99_PRIV_DIV_248_2 ~, (ML99_JUST(124))
+#define ML99_PRIV_DIV_248_4 ~, (ML99_JUST(62))
+#define ML99_PRIV_DIV_248_8 ~, (ML99_JUST(31))
+#define ML99_PRIV_DIV_248_31 ~, (ML99_JUST(8))
+#define ML99_PRIV_DIV_248_62 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_248_124 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_249_3 ~, (ML99_JUST(83))
+#define ML99_PRIV_DIV_249_83 ~, (ML99_JUST(3))
+
+#define ML99_PRIV_DIV_250_2 ~, (ML99_JUST(125))
+#define ML99_PRIV_DIV_250_5 ~, (ML99_JUST(50))
+#define ML99_PRIV_DIV_250_10 ~, (ML99_JUST(25))
+#define ML99_PRIV_DIV_250_25 ~, (ML99_JUST(10))
+#define ML99_PRIV_DIV_250_50 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_250_125 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_252_2 ~, (ML99_JUST(126))
+#define ML99_PRIV_DIV_252_3 ~, (ML99_JUST(84))
+#define ML99_PRIV_DIV_252_4 ~, (ML99_JUST(63))
+#define ML99_PRIV_DIV_252_6 ~, (ML99_JUST(42))
+#define ML99_PRIV_DIV_252_7 ~, (ML99_JUST(36))
+#define ML99_PRIV_DIV_252_9 ~, (ML99_JUST(28))
+#define ML99_PRIV_DIV_252_12 ~, (ML99_JUST(21))
+#define ML99_PRIV_DIV_252_14 ~, (ML99_JUST(18))
+#define ML99_PRIV_DIV_252_18 ~, (ML99_JUST(14))
+#define ML99_PRIV_DIV_252_21 ~, (ML99_JUST(12))
+#define ML99_PRIV_DIV_252_28 ~, (ML99_JUST(9))
+#define ML99_PRIV_DIV_252_36 ~, (ML99_JUST(7))
+#define ML99_PRIV_DIV_252_42 ~, (ML99_JUST(6))
+#define ML99_PRIV_DIV_252_63 ~, (ML99_JUST(4))
+#define ML99_PRIV_DIV_252_84 ~, (ML99_JUST(3))
+#define ML99_PRIV_DIV_252_126 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_253_11 ~, (ML99_JUST(23))
+#define ML99_PRIV_DIV_253_23 ~, (ML99_JUST(11))
+
+#define ML99_PRIV_DIV_254_2 ~, (ML99_JUST(127))
+#define ML99_PRIV_DIV_254_127 ~, (ML99_JUST(2))
+
+#define ML99_PRIV_DIV_255_3 ~, (ML99_JUST(85))
+#define ML99_PRIV_DIV_255_5 ~, (ML99_JUST(51))
+#define ML99_PRIV_DIV_255_15 ~, (ML99_JUST(17))
+#define ML99_PRIV_DIV_255_17 ~, (ML99_JUST(15))
+#define ML99_PRIV_DIV_255_51 ~, (ML99_JUST(5))
+#define ML99_PRIV_DIV_255_85 ~, (ML99_JUST(3))
+
+#endif // ML99_NAT_DIV_H
diff --git a/test/external/metalang99/include/metalang99/nat/eq.h b/test/external/metalang99/include/metalang99/nat/eq.h
new file mode 100644
index 0000000..d4164dd
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/nat/eq.h
@@ -0,0 +1,266 @@
+#ifndef ML99_NAT_EQ_H
+#define ML99_NAT_EQ_H
+
+#include <metalang99/priv/tuple.h>
+
+#define ML99_PRIV_NAT_EQ(x, y) ML99_PRIV_NAT_EQ_AUX(x, y)
+#define ML99_PRIV_NAT_EQ_AUX(x, y) ML99_PRIV_IS_TUPLE_FAST(ML99_PRIV_NAT_EQ_##x##_##y)
+
+#define ML99_PRIV_NAT_EQ_0_0 ()
+#define ML99_PRIV_NAT_EQ_1_1 ()
+#define ML99_PRIV_NAT_EQ_2_2 ()
+#define ML99_PRIV_NAT_EQ_3_3 ()
+#define ML99_PRIV_NAT_EQ_4_4 ()
+#define ML99_PRIV_NAT_EQ_5_5 ()
+#define ML99_PRIV_NAT_EQ_6_6 ()
+#define ML99_PRIV_NAT_EQ_7_7 ()
+#define ML99_PRIV_NAT_EQ_8_8 ()
+#define ML99_PRIV_NAT_EQ_9_9 ()
+#define ML99_PRIV_NAT_EQ_10_10 ()
+#define ML99_PRIV_NAT_EQ_11_11 ()
+#define ML99_PRIV_NAT_EQ_12_12 ()
+#define ML99_PRIV_NAT_EQ_13_13 ()
+#define ML99_PRIV_NAT_EQ_14_14 ()
+#define ML99_PRIV_NAT_EQ_15_15 ()
+#define ML99_PRIV_NAT_EQ_16_16 ()
+#define ML99_PRIV_NAT_EQ_17_17 ()
+#define ML99_PRIV_NAT_EQ_18_18 ()
+#define ML99_PRIV_NAT_EQ_19_19 ()
+#define ML99_PRIV_NAT_EQ_20_20 ()
+#define ML99_PRIV_NAT_EQ_21_21 ()
+#define ML99_PRIV_NAT_EQ_22_22 ()
+#define ML99_PRIV_NAT_EQ_23_23 ()
+#define ML99_PRIV_NAT_EQ_24_24 ()
+#define ML99_PRIV_NAT_EQ_25_25 ()
+#define ML99_PRIV_NAT_EQ_26_26 ()
+#define ML99_PRIV_NAT_EQ_27_27 ()
+#define ML99_PRIV_NAT_EQ_28_28 ()
+#define ML99_PRIV_NAT_EQ_29_29 ()
+#define ML99_PRIV_NAT_EQ_30_30 ()
+#define ML99_PRIV_NAT_EQ_31_31 ()
+#define ML99_PRIV_NAT_EQ_32_32 ()
+#define ML99_PRIV_NAT_EQ_33_33 ()
+#define ML99_PRIV_NAT_EQ_34_34 ()
+#define ML99_PRIV_NAT_EQ_35_35 ()
+#define ML99_PRIV_NAT_EQ_36_36 ()
+#define ML99_PRIV_NAT_EQ_37_37 ()
+#define ML99_PRIV_NAT_EQ_38_38 ()
+#define ML99_PRIV_NAT_EQ_39_39 ()
+#define ML99_PRIV_NAT_EQ_40_40 ()
+#define ML99_PRIV_NAT_EQ_41_41 ()
+#define ML99_PRIV_NAT_EQ_42_42 ()
+#define ML99_PRIV_NAT_EQ_43_43 ()
+#define ML99_PRIV_NAT_EQ_44_44 ()
+#define ML99_PRIV_NAT_EQ_45_45 ()
+#define ML99_PRIV_NAT_EQ_46_46 ()
+#define ML99_PRIV_NAT_EQ_47_47 ()
+#define ML99_PRIV_NAT_EQ_48_48 ()
+#define ML99_PRIV_NAT_EQ_49_49 ()
+#define ML99_PRIV_NAT_EQ_50_50 ()
+#define ML99_PRIV_NAT_EQ_51_51 ()
+#define ML99_PRIV_NAT_EQ_52_52 ()
+#define ML99_PRIV_NAT_EQ_53_53 ()
+#define ML99_PRIV_NAT_EQ_54_54 ()
+#define ML99_PRIV_NAT_EQ_55_55 ()
+#define ML99_PRIV_NAT_EQ_56_56 ()
+#define ML99_PRIV_NAT_EQ_57_57 ()
+#define ML99_PRIV_NAT_EQ_58_58 ()
+#define ML99_PRIV_NAT_EQ_59_59 ()
+#define ML99_PRIV_NAT_EQ_60_60 ()
+#define ML99_PRIV_NAT_EQ_61_61 ()
+#define ML99_PRIV_NAT_EQ_62_62 ()
+#define ML99_PRIV_NAT_EQ_63_63 ()
+#define ML99_PRIV_NAT_EQ_64_64 ()
+#define ML99_PRIV_NAT_EQ_65_65 ()
+#define ML99_PRIV_NAT_EQ_66_66 ()
+#define ML99_PRIV_NAT_EQ_67_67 ()
+#define ML99_PRIV_NAT_EQ_68_68 ()
+#define ML99_PRIV_NAT_EQ_69_69 ()
+#define ML99_PRIV_NAT_EQ_70_70 ()
+#define ML99_PRIV_NAT_EQ_71_71 ()
+#define ML99_PRIV_NAT_EQ_72_72 ()
+#define ML99_PRIV_NAT_EQ_73_73 ()
+#define ML99_PRIV_NAT_EQ_74_74 ()
+#define ML99_PRIV_NAT_EQ_75_75 ()
+#define ML99_PRIV_NAT_EQ_76_76 ()
+#define ML99_PRIV_NAT_EQ_77_77 ()
+#define ML99_PRIV_NAT_EQ_78_78 ()
+#define ML99_PRIV_NAT_EQ_79_79 ()
+#define ML99_PRIV_NAT_EQ_80_80 ()
+#define ML99_PRIV_NAT_EQ_81_81 ()
+#define ML99_PRIV_NAT_EQ_82_82 ()
+#define ML99_PRIV_NAT_EQ_83_83 ()
+#define ML99_PRIV_NAT_EQ_84_84 ()
+#define ML99_PRIV_NAT_EQ_85_85 ()
+#define ML99_PRIV_NAT_EQ_86_86 ()
+#define ML99_PRIV_NAT_EQ_87_87 ()
+#define ML99_PRIV_NAT_EQ_88_88 ()
+#define ML99_PRIV_NAT_EQ_89_89 ()
+#define ML99_PRIV_NAT_EQ_90_90 ()
+#define ML99_PRIV_NAT_EQ_91_91 ()
+#define ML99_PRIV_NAT_EQ_92_92 ()
+#define ML99_PRIV_NAT_EQ_93_93 ()
+#define ML99_PRIV_NAT_EQ_94_94 ()
+#define ML99_PRIV_NAT_EQ_95_95 ()
+#define ML99_PRIV_NAT_EQ_96_96 ()
+#define ML99_PRIV_NAT_EQ_97_97 ()
+#define ML99_PRIV_NAT_EQ_98_98 ()
+#define ML99_PRIV_NAT_EQ_99_99 ()
+#define ML99_PRIV_NAT_EQ_100_100 ()
+#define ML99_PRIV_NAT_EQ_101_101 ()
+#define ML99_PRIV_NAT_EQ_102_102 ()
+#define ML99_PRIV_NAT_EQ_103_103 ()
+#define ML99_PRIV_NAT_EQ_104_104 ()
+#define ML99_PRIV_NAT_EQ_105_105 ()
+#define ML99_PRIV_NAT_EQ_106_106 ()
+#define ML99_PRIV_NAT_EQ_107_107 ()
+#define ML99_PRIV_NAT_EQ_108_108 ()
+#define ML99_PRIV_NAT_EQ_109_109 ()
+#define ML99_PRIV_NAT_EQ_110_110 ()
+#define ML99_PRIV_NAT_EQ_111_111 ()
+#define ML99_PRIV_NAT_EQ_112_112 ()
+#define ML99_PRIV_NAT_EQ_113_113 ()
+#define ML99_PRIV_NAT_EQ_114_114 ()
+#define ML99_PRIV_NAT_EQ_115_115 ()
+#define ML99_PRIV_NAT_EQ_116_116 ()
+#define ML99_PRIV_NAT_EQ_117_117 ()
+#define ML99_PRIV_NAT_EQ_118_118 ()
+#define ML99_PRIV_NAT_EQ_119_119 ()
+#define ML99_PRIV_NAT_EQ_120_120 ()
+#define ML99_PRIV_NAT_EQ_121_121 ()
+#define ML99_PRIV_NAT_EQ_122_122 ()
+#define ML99_PRIV_NAT_EQ_123_123 ()
+#define ML99_PRIV_NAT_EQ_124_124 ()
+#define ML99_PRIV_NAT_EQ_125_125 ()
+#define ML99_PRIV_NAT_EQ_126_126 ()
+#define ML99_PRIV_NAT_EQ_127_127 ()
+#define ML99_PRIV_NAT_EQ_128_128 ()
+#define ML99_PRIV_NAT_EQ_129_129 ()
+#define ML99_PRIV_NAT_EQ_130_130 ()
+#define ML99_PRIV_NAT_EQ_131_131 ()
+#define ML99_PRIV_NAT_EQ_132_132 ()
+#define ML99_PRIV_NAT_EQ_133_133 ()
+#define ML99_PRIV_NAT_EQ_134_134 ()
+#define ML99_PRIV_NAT_EQ_135_135 ()
+#define ML99_PRIV_NAT_EQ_136_136 ()
+#define ML99_PRIV_NAT_EQ_137_137 ()
+#define ML99_PRIV_NAT_EQ_138_138 ()
+#define ML99_PRIV_NAT_EQ_139_139 ()
+#define ML99_PRIV_NAT_EQ_140_140 ()
+#define ML99_PRIV_NAT_EQ_141_141 ()
+#define ML99_PRIV_NAT_EQ_142_142 ()
+#define ML99_PRIV_NAT_EQ_143_143 ()
+#define ML99_PRIV_NAT_EQ_144_144 ()
+#define ML99_PRIV_NAT_EQ_145_145 ()
+#define ML99_PRIV_NAT_EQ_146_146 ()
+#define ML99_PRIV_NAT_EQ_147_147 ()
+#define ML99_PRIV_NAT_EQ_148_148 ()
+#define ML99_PRIV_NAT_EQ_149_149 ()
+#define ML99_PRIV_NAT_EQ_150_150 ()
+#define ML99_PRIV_NAT_EQ_151_151 ()
+#define ML99_PRIV_NAT_EQ_152_152 ()
+#define ML99_PRIV_NAT_EQ_153_153 ()
+#define ML99_PRIV_NAT_EQ_154_154 ()
+#define ML99_PRIV_NAT_EQ_155_155 ()
+#define ML99_PRIV_NAT_EQ_156_156 ()
+#define ML99_PRIV_NAT_EQ_157_157 ()
+#define ML99_PRIV_NAT_EQ_158_158 ()
+#define ML99_PRIV_NAT_EQ_159_159 ()
+#define ML99_PRIV_NAT_EQ_160_160 ()
+#define ML99_PRIV_NAT_EQ_161_161 ()
+#define ML99_PRIV_NAT_EQ_162_162 ()
+#define ML99_PRIV_NAT_EQ_163_163 ()
+#define ML99_PRIV_NAT_EQ_164_164 ()
+#define ML99_PRIV_NAT_EQ_165_165 ()
+#define ML99_PRIV_NAT_EQ_166_166 ()
+#define ML99_PRIV_NAT_EQ_167_167 ()
+#define ML99_PRIV_NAT_EQ_168_168 ()
+#define ML99_PRIV_NAT_EQ_169_169 ()
+#define ML99_PRIV_NAT_EQ_170_170 ()
+#define ML99_PRIV_NAT_EQ_171_171 ()
+#define ML99_PRIV_NAT_EQ_172_172 ()
+#define ML99_PRIV_NAT_EQ_173_173 ()
+#define ML99_PRIV_NAT_EQ_174_174 ()
+#define ML99_PRIV_NAT_EQ_175_175 ()
+#define ML99_PRIV_NAT_EQ_176_176 ()
+#define ML99_PRIV_NAT_EQ_177_177 ()
+#define ML99_PRIV_NAT_EQ_178_178 ()
+#define ML99_PRIV_NAT_EQ_179_179 ()
+#define ML99_PRIV_NAT_EQ_180_180 ()
+#define ML99_PRIV_NAT_EQ_181_181 ()
+#define ML99_PRIV_NAT_EQ_182_182 ()
+#define ML99_PRIV_NAT_EQ_183_183 ()
+#define ML99_PRIV_NAT_EQ_184_184 ()
+#define ML99_PRIV_NAT_EQ_185_185 ()
+#define ML99_PRIV_NAT_EQ_186_186 ()
+#define ML99_PRIV_NAT_EQ_187_187 ()
+#define ML99_PRIV_NAT_EQ_188_188 ()
+#define ML99_PRIV_NAT_EQ_189_189 ()
+#define ML99_PRIV_NAT_EQ_190_190 ()
+#define ML99_PRIV_NAT_EQ_191_191 ()
+#define ML99_PRIV_NAT_EQ_192_192 ()
+#define ML99_PRIV_NAT_EQ_193_193 ()
+#define ML99_PRIV_NAT_EQ_194_194 ()
+#define ML99_PRIV_NAT_EQ_195_195 ()
+#define ML99_PRIV_NAT_EQ_196_196 ()
+#define ML99_PRIV_NAT_EQ_197_197 ()
+#define ML99_PRIV_NAT_EQ_198_198 ()
+#define ML99_PRIV_NAT_EQ_199_199 ()
+#define ML99_PRIV_NAT_EQ_200_200 ()
+#define ML99_PRIV_NAT_EQ_201_201 ()
+#define ML99_PRIV_NAT_EQ_202_202 ()
+#define ML99_PRIV_NAT_EQ_203_203 ()
+#define ML99_PRIV_NAT_EQ_204_204 ()
+#define ML99_PRIV_NAT_EQ_205_205 ()
+#define ML99_PRIV_NAT_EQ_206_206 ()
+#define ML99_PRIV_NAT_EQ_207_207 ()
+#define ML99_PRIV_NAT_EQ_208_208 ()
+#define ML99_PRIV_NAT_EQ_209_209 ()
+#define ML99_PRIV_NAT_EQ_210_210 ()
+#define ML99_PRIV_NAT_EQ_211_211 ()
+#define ML99_PRIV_NAT_EQ_212_212 ()
+#define ML99_PRIV_NAT_EQ_213_213 ()
+#define ML99_PRIV_NAT_EQ_214_214 ()
+#define ML99_PRIV_NAT_EQ_215_215 ()
+#define ML99_PRIV_NAT_EQ_216_216 ()
+#define ML99_PRIV_NAT_EQ_217_217 ()
+#define ML99_PRIV_NAT_EQ_218_218 ()
+#define ML99_PRIV_NAT_EQ_219_219 ()
+#define ML99_PRIV_NAT_EQ_220_220 ()
+#define ML99_PRIV_NAT_EQ_221_221 ()
+#define ML99_PRIV_NAT_EQ_222_222 ()
+#define ML99_PRIV_NAT_EQ_223_223 ()
+#define ML99_PRIV_NAT_EQ_224_224 ()
+#define ML99_PRIV_NAT_EQ_225_225 ()
+#define ML99_PRIV_NAT_EQ_226_226 ()
+#define ML99_PRIV_NAT_EQ_227_227 ()
+#define ML99_PRIV_NAT_EQ_228_228 ()
+#define ML99_PRIV_NAT_EQ_229_229 ()
+#define ML99_PRIV_NAT_EQ_230_230 ()
+#define ML99_PRIV_NAT_EQ_231_231 ()
+#define ML99_PRIV_NAT_EQ_232_232 ()
+#define ML99_PRIV_NAT_EQ_233_233 ()
+#define ML99_PRIV_NAT_EQ_234_234 ()
+#define ML99_PRIV_NAT_EQ_235_235 ()
+#define ML99_PRIV_NAT_EQ_236_236 ()
+#define ML99_PRIV_NAT_EQ_237_237 ()
+#define ML99_PRIV_NAT_EQ_238_238 ()
+#define ML99_PRIV_NAT_EQ_239_239 ()
+#define ML99_PRIV_NAT_EQ_240_240 ()
+#define ML99_PRIV_NAT_EQ_241_241 ()
+#define ML99_PRIV_NAT_EQ_242_242 ()
+#define ML99_PRIV_NAT_EQ_243_243 ()
+#define ML99_PRIV_NAT_EQ_244_244 ()
+#define ML99_PRIV_NAT_EQ_245_245 ()
+#define ML99_PRIV_NAT_EQ_246_246 ()
+#define ML99_PRIV_NAT_EQ_247_247 ()
+#define ML99_PRIV_NAT_EQ_248_248 ()
+#define ML99_PRIV_NAT_EQ_249_249 ()
+#define ML99_PRIV_NAT_EQ_250_250 ()
+#define ML99_PRIV_NAT_EQ_251_251 ()
+#define ML99_PRIV_NAT_EQ_252_252 ()
+#define ML99_PRIV_NAT_EQ_253_253 ()
+#define ML99_PRIV_NAT_EQ_254_254 ()
+#define ML99_PRIV_NAT_EQ_255_255 ()
+
+#endif // ML99_NAT_EQ_H
diff --git a/test/external/metalang99/include/metalang99/nat/inc.h b/test/external/metalang99/include/metalang99/nat/inc.h
new file mode 100644
index 0000000..1543900
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/nat/inc.h
@@ -0,0 +1,264 @@
+#ifndef ML99_NAT_INC_H
+#define ML99_NAT_INC_H
+
+#define ML99_PRIV_INC(x) ML99_PRIV_INC_AUX(x)
+#define ML99_PRIV_INC_AUX(x) ML99_PRIV_INC_##x
+
+#define ML99_PRIV_INC_0 1
+#define ML99_PRIV_INC_1 2
+#define ML99_PRIV_INC_2 3
+#define ML99_PRIV_INC_3 4
+#define ML99_PRIV_INC_4 5
+#define ML99_PRIV_INC_5 6
+#define ML99_PRIV_INC_6 7
+#define ML99_PRIV_INC_7 8
+#define ML99_PRIV_INC_8 9
+#define ML99_PRIV_INC_9 10
+#define ML99_PRIV_INC_10 11
+#define ML99_PRIV_INC_11 12
+#define ML99_PRIV_INC_12 13
+#define ML99_PRIV_INC_13 14
+#define ML99_PRIV_INC_14 15
+#define ML99_PRIV_INC_15 16
+#define ML99_PRIV_INC_16 17
+#define ML99_PRIV_INC_17 18
+#define ML99_PRIV_INC_18 19
+#define ML99_PRIV_INC_19 20
+#define ML99_PRIV_INC_20 21
+#define ML99_PRIV_INC_21 22
+#define ML99_PRIV_INC_22 23
+#define ML99_PRIV_INC_23 24
+#define ML99_PRIV_INC_24 25
+#define ML99_PRIV_INC_25 26
+#define ML99_PRIV_INC_26 27
+#define ML99_PRIV_INC_27 28
+#define ML99_PRIV_INC_28 29
+#define ML99_PRIV_INC_29 30
+#define ML99_PRIV_INC_30 31
+#define ML99_PRIV_INC_31 32
+#define ML99_PRIV_INC_32 33
+#define ML99_PRIV_INC_33 34
+#define ML99_PRIV_INC_34 35
+#define ML99_PRIV_INC_35 36
+#define ML99_PRIV_INC_36 37
+#define ML99_PRIV_INC_37 38
+#define ML99_PRIV_INC_38 39
+#define ML99_PRIV_INC_39 40
+#define ML99_PRIV_INC_40 41
+#define ML99_PRIV_INC_41 42
+#define ML99_PRIV_INC_42 43
+#define ML99_PRIV_INC_43 44
+#define ML99_PRIV_INC_44 45
+#define ML99_PRIV_INC_45 46
+#define ML99_PRIV_INC_46 47
+#define ML99_PRIV_INC_47 48
+#define ML99_PRIV_INC_48 49
+#define ML99_PRIV_INC_49 50
+#define ML99_PRIV_INC_50 51
+#define ML99_PRIV_INC_51 52
+#define ML99_PRIV_INC_52 53
+#define ML99_PRIV_INC_53 54
+#define ML99_PRIV_INC_54 55
+#define ML99_PRIV_INC_55 56
+#define ML99_PRIV_INC_56 57
+#define ML99_PRIV_INC_57 58
+#define ML99_PRIV_INC_58 59
+#define ML99_PRIV_INC_59 60
+#define ML99_PRIV_INC_60 61
+#define ML99_PRIV_INC_61 62
+#define ML99_PRIV_INC_62 63
+#define ML99_PRIV_INC_63 64
+#define ML99_PRIV_INC_64 65
+#define ML99_PRIV_INC_65 66
+#define ML99_PRIV_INC_66 67
+#define ML99_PRIV_INC_67 68
+#define ML99_PRIV_INC_68 69
+#define ML99_PRIV_INC_69 70
+#define ML99_PRIV_INC_70 71
+#define ML99_PRIV_INC_71 72
+#define ML99_PRIV_INC_72 73
+#define ML99_PRIV_INC_73 74
+#define ML99_PRIV_INC_74 75
+#define ML99_PRIV_INC_75 76
+#define ML99_PRIV_INC_76 77
+#define ML99_PRIV_INC_77 78
+#define ML99_PRIV_INC_78 79
+#define ML99_PRIV_INC_79 80
+#define ML99_PRIV_INC_80 81
+#define ML99_PRIV_INC_81 82
+#define ML99_PRIV_INC_82 83
+#define ML99_PRIV_INC_83 84
+#define ML99_PRIV_INC_84 85
+#define ML99_PRIV_INC_85 86
+#define ML99_PRIV_INC_86 87
+#define ML99_PRIV_INC_87 88
+#define ML99_PRIV_INC_88 89
+#define ML99_PRIV_INC_89 90
+#define ML99_PRIV_INC_90 91
+#define ML99_PRIV_INC_91 92
+#define ML99_PRIV_INC_92 93
+#define ML99_PRIV_INC_93 94
+#define ML99_PRIV_INC_94 95
+#define ML99_PRIV_INC_95 96
+#define ML99_PRIV_INC_96 97
+#define ML99_PRIV_INC_97 98
+#define ML99_PRIV_INC_98 99
+#define ML99_PRIV_INC_99 100
+#define ML99_PRIV_INC_100 101
+#define ML99_PRIV_INC_101 102
+#define ML99_PRIV_INC_102 103
+#define ML99_PRIV_INC_103 104
+#define ML99_PRIV_INC_104 105
+#define ML99_PRIV_INC_105 106
+#define ML99_PRIV_INC_106 107
+#define ML99_PRIV_INC_107 108
+#define ML99_PRIV_INC_108 109
+#define ML99_PRIV_INC_109 110
+#define ML99_PRIV_INC_110 111
+#define ML99_PRIV_INC_111 112
+#define ML99_PRIV_INC_112 113
+#define ML99_PRIV_INC_113 114
+#define ML99_PRIV_INC_114 115
+#define ML99_PRIV_INC_115 116
+#define ML99_PRIV_INC_116 117
+#define ML99_PRIV_INC_117 118
+#define ML99_PRIV_INC_118 119
+#define ML99_PRIV_INC_119 120
+#define ML99_PRIV_INC_120 121
+#define ML99_PRIV_INC_121 122
+#define ML99_PRIV_INC_122 123
+#define ML99_PRIV_INC_123 124
+#define ML99_PRIV_INC_124 125
+#define ML99_PRIV_INC_125 126
+#define ML99_PRIV_INC_126 127
+#define ML99_PRIV_INC_127 128
+#define ML99_PRIV_INC_128 129
+#define ML99_PRIV_INC_129 130
+#define ML99_PRIV_INC_130 131
+#define ML99_PRIV_INC_131 132
+#define ML99_PRIV_INC_132 133
+#define ML99_PRIV_INC_133 134
+#define ML99_PRIV_INC_134 135
+#define ML99_PRIV_INC_135 136
+#define ML99_PRIV_INC_136 137
+#define ML99_PRIV_INC_137 138
+#define ML99_PRIV_INC_138 139
+#define ML99_PRIV_INC_139 140
+#define ML99_PRIV_INC_140 141
+#define ML99_PRIV_INC_141 142
+#define ML99_PRIV_INC_142 143
+#define ML99_PRIV_INC_143 144
+#define ML99_PRIV_INC_144 145
+#define ML99_PRIV_INC_145 146
+#define ML99_PRIV_INC_146 147
+#define ML99_PRIV_INC_147 148
+#define ML99_PRIV_INC_148 149
+#define ML99_PRIV_INC_149 150
+#define ML99_PRIV_INC_150 151
+#define ML99_PRIV_INC_151 152
+#define ML99_PRIV_INC_152 153
+#define ML99_PRIV_INC_153 154
+#define ML99_PRIV_INC_154 155
+#define ML99_PRIV_INC_155 156
+#define ML99_PRIV_INC_156 157
+#define ML99_PRIV_INC_157 158
+#define ML99_PRIV_INC_158 159
+#define ML99_PRIV_INC_159 160
+#define ML99_PRIV_INC_160 161
+#define ML99_PRIV_INC_161 162
+#define ML99_PRIV_INC_162 163
+#define ML99_PRIV_INC_163 164
+#define ML99_PRIV_INC_164 165
+#define ML99_PRIV_INC_165 166
+#define ML99_PRIV_INC_166 167
+#define ML99_PRIV_INC_167 168
+#define ML99_PRIV_INC_168 169
+#define ML99_PRIV_INC_169 170
+#define ML99_PRIV_INC_170 171
+#define ML99_PRIV_INC_171 172
+#define ML99_PRIV_INC_172 173
+#define ML99_PRIV_INC_173 174
+#define ML99_PRIV_INC_174 175
+#define ML99_PRIV_INC_175 176
+#define ML99_PRIV_INC_176 177
+#define ML99_PRIV_INC_177 178
+#define ML99_PRIV_INC_178 179
+#define ML99_PRIV_INC_179 180
+#define ML99_PRIV_INC_180 181
+#define ML99_PRIV_INC_181 182
+#define ML99_PRIV_INC_182 183
+#define ML99_PRIV_INC_183 184
+#define ML99_PRIV_INC_184 185
+#define ML99_PRIV_INC_185 186
+#define ML99_PRIV_INC_186 187
+#define ML99_PRIV_INC_187 188
+#define ML99_PRIV_INC_188 189
+#define ML99_PRIV_INC_189 190
+#define ML99_PRIV_INC_190 191
+#define ML99_PRIV_INC_191 192
+#define ML99_PRIV_INC_192 193
+#define ML99_PRIV_INC_193 194
+#define ML99_PRIV_INC_194 195
+#define ML99_PRIV_INC_195 196
+#define ML99_PRIV_INC_196 197
+#define ML99_PRIV_INC_197 198
+#define ML99_PRIV_INC_198 199
+#define ML99_PRIV_INC_199 200
+#define ML99_PRIV_INC_200 201
+#define ML99_PRIV_INC_201 202
+#define ML99_PRIV_INC_202 203
+#define ML99_PRIV_INC_203 204
+#define ML99_PRIV_INC_204 205
+#define ML99_PRIV_INC_205 206
+#define ML99_PRIV_INC_206 207
+#define ML99_PRIV_INC_207 208
+#define ML99_PRIV_INC_208 209
+#define ML99_PRIV_INC_209 210
+#define ML99_PRIV_INC_210 211
+#define ML99_PRIV_INC_211 212
+#define ML99_PRIV_INC_212 213
+#define ML99_PRIV_INC_213 214
+#define ML99_PRIV_INC_214 215
+#define ML99_PRIV_INC_215 216
+#define ML99_PRIV_INC_216 217
+#define ML99_PRIV_INC_217 218
+#define ML99_PRIV_INC_218 219
+#define ML99_PRIV_INC_219 220
+#define ML99_PRIV_INC_220 221
+#define ML99_PRIV_INC_221 222
+#define ML99_PRIV_INC_222 223
+#define ML99_PRIV_INC_223 224
+#define ML99_PRIV_INC_224 225
+#define ML99_PRIV_INC_225 226
+#define ML99_PRIV_INC_226 227
+#define ML99_PRIV_INC_227 228
+#define ML99_PRIV_INC_228 229
+#define ML99_PRIV_INC_229 230
+#define ML99_PRIV_INC_230 231
+#define ML99_PRIV_INC_231 232
+#define ML99_PRIV_INC_232 233
+#define ML99_PRIV_INC_233 234
+#define ML99_PRIV_INC_234 235
+#define ML99_PRIV_INC_235 236
+#define ML99_PRIV_INC_236 237
+#define ML99_PRIV_INC_237 238
+#define ML99_PRIV_INC_238 239
+#define ML99_PRIV_INC_239 240
+#define ML99_PRIV_INC_240 241
+#define ML99_PRIV_INC_241 242
+#define ML99_PRIV_INC_242 243
+#define ML99_PRIV_INC_243 244
+#define ML99_PRIV_INC_244 245
+#define ML99_PRIV_INC_245 246
+#define ML99_PRIV_INC_246 247
+#define ML99_PRIV_INC_247 248
+#define ML99_PRIV_INC_248 249
+#define ML99_PRIV_INC_249 250
+#define ML99_PRIV_INC_250 251
+#define ML99_PRIV_INC_251 252
+#define ML99_PRIV_INC_252 253
+#define ML99_PRIV_INC_253 254
+#define ML99_PRIV_INC_254 255
+#define ML99_PRIV_INC_255 0
+
+#endif // ML99_NAT_INC_H
diff --git a/test/external/metalang99/include/metalang99/priv/bool.h b/test/external/metalang99/include/metalang99/priv/bool.h
new file mode 100644
index 0000000..d0b19d2
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/priv/bool.h
@@ -0,0 +1,46 @@
+#ifndef ML99_PRIV_BOOL_H
+#define ML99_PRIV_BOOL_H
+
+#define ML99_PRIV_TRUE(...) 1
+#define ML99_PRIV_FALSE(...) 0
+
+#define ML99_PRIV_NOT(b) ML99_PRIV_LOGICAL_OVERLOAD_SINGLE(ML99_PRIV_NOT_, b)
+#define ML99_PRIV_NOT_0 1
+#define ML99_PRIV_NOT_1 0
+
+#define ML99_PRIV_AND(x, y) ML99_PRIV_LOGICAL_OVERLOAD(ML99_PRIV_AND_, x, y)
+#define ML99_PRIV_AND_00 0
+#define ML99_PRIV_AND_01 0
+#define ML99_PRIV_AND_10 0
+#define ML99_PRIV_AND_11 1
+
+#define ML99_PRIV_OR(x, y) ML99_PRIV_LOGICAL_OVERLOAD(ML99_PRIV_OR_, x, y)
+#define ML99_PRIV_OR_00 0
+#define ML99_PRIV_OR_01 1
+#define ML99_PRIV_OR_10 1
+#define ML99_PRIV_OR_11 1
+
+#define ML99_PRIV_OR3(a, b, c) ML99_PRIV_OR(a, ML99_PRIV_OR(b, c))
+#define ML99_PRIV_OR4(a, b, c, d) ML99_PRIV_OR3(a, b, ML99_PRIV_OR(c, d))
+
+#define ML99_PRIV_XOR(x, y) ML99_PRIV_LOGICAL_OVERLOAD(ML99_PRIV_XOR_, x, y)
+#define ML99_PRIV_XOR_00 0
+#define ML99_PRIV_XOR_01 1
+#define ML99_PRIV_XOR_10 1
+#define ML99_PRIV_XOR_11 0
+
+#define ML99_PRIV_BOOL_EQ(x, y) ML99_PRIV_LOGICAL_OVERLOAD(ML99_PRIV_BOOL_EQ_, x, y)
+#define ML99_PRIV_BOOL_EQ_00 1
+#define ML99_PRIV_BOOL_EQ_01 0
+#define ML99_PRIV_BOOL_EQ_10 0
+#define ML99_PRIV_BOOL_EQ_11 1
+
+#define ML99_PRIV_LOGICAL_OVERLOAD(op, x, y) op##x##y
+#define ML99_PRIV_LOGICAL_OVERLOAD_SINGLE(op, b) op##b
+
+#define ML99_PRIV_IF(cond, x, y) ML99_PRIV_IF_OVERLOAD(cond)(x, y)
+#define ML99_PRIV_IF_OVERLOAD(cond) ML99_PRIV_IF_##cond
+#define ML99_PRIV_IF_0(_x, y) y
+#define ML99_PRIV_IF_1(x, _y) x
+
+#endif // ML99_PRIV_BOOL_H
diff --git a/test/external/metalang99/include/metalang99/priv/compiler_specific.h b/test/external/metalang99/include/metalang99/priv/compiler_specific.h
new file mode 100644
index 0000000..c334e21
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/priv/compiler_specific.h
@@ -0,0 +1,69 @@
+#ifndef ML99_PRIV_COMPILER_SPECIFIC_H
+#define ML99_PRIV_COMPILER_SPECIFIC_H
+
+#define ML99_PRIV_C11_VERSION 201112L
+
+// GCC 4.6 Release Series: <https://gcc.gnu.org/gcc-4.6/changes.html>.
+#define ML99_PRIV_IS_GCC_4_6_OR_HIGHER ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ >= 5))
+
+#ifdef __GNUC__
+#define ML99_PRIV_COMPILER_ATTR_UNUSED __attribute__((unused))
+#else
+#define ML99_PRIV_COMPILER_ATTR_UNUSED
+#endif
+
+// ML99_PRIV_C11_STATIC_ASSERT_AVAILABLE {
+
+#if __STDC__ && __STDC_VERSION__ >= ML99_PRIV_C11_VERSION
+
+#define ML99_PRIV_C11_STATIC_ASSERT_AVAILABLE
+
+/*
+ * On MSVC, `__STDC__` expands to 0 if the `\Za` option was not specified, but the thing is that it
+ * nevertheless supports C11's `_Static_assert`.
+ *
+ * MSVC Standard predefined macros:
+ * <https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros#standard-predefined-macros>.
+ */
+#elif defined(_MSC_VER) && __STDC_VERSION__ >= ML99_PRIV_C11_VERSION
+#define ML99_PRIV_C11_STATIC_ASSERT_AVAILABLE
+#endif
+// } (ML99_PRIV_C11_STATIC_ASSERT_AVAILABLE)
+
+// ML99_PRIV_EMIT_ERROR {
+
+#ifdef ML99_PRIV_C11_STATIC_ASSERT_AVAILABLE
+#define ML99_PRIV_EMIT_ERROR ML99_PRIV_STATIC_ASSERT_ERROR
+#elif defined(__clang__)
+
+#if __has_extension(c_static_assert)
+#define ML99_PRIV_EMIT_ERROR ML99_PRIV_STATIC_ASSERT_ERROR
+#endif
+
+#elif defined(__GNUC__)
+
+#if ML99_PRIV_IS_GCC_4_6_OR_HIGHER
+#define ML99_PRIV_EMIT_ERROR ML99_PRIV_STATIC_ASSERT_ERROR
+#else
+
+// GCC Common Function Attributes:
+// <https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html>.
+#define ML99_PRIV_EMIT_ERROR(message) \
+ void __attribute__((constructor, error(message))) ML99_CAT(ml99_error_, __LINE__)(void) { \
+ ML99_CAT(ml99_error_, __LINE__)(); \
+ }
+
+#endif
+
+#endif
+
+#if !defined(ML99_PRIV_EMIT_ERROR) && !defined(ML99_ALLOW_POOR_DIAGNOSTICS)
+#error Your compiler doesn't support decent diagnostic messages. \
+You'll have to search for Metalang99 errors in a preprocessed-only file (-E) by yourself. \
+Define ML99_ALLOW_POOR_DIAGNOSTICS to suppress this error.
+#endif
+
+#define ML99_PRIV_STATIC_ASSERT_ERROR(message) _Static_assert(0, message)
+// } (ML99_PRIV_EMIT_ERROR)
+
+#endif // ML99_PRIV_COMPILER_SPECIFIC_H
diff --git a/test/external/metalang99/include/metalang99/priv/tuple.h b/test/external/metalang99/include/metalang99/priv/tuple.h
new file mode 100644
index 0000000..ea2fd19
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/priv/tuple.h
@@ -0,0 +1,33 @@
+#ifndef ML99_PRIV_TUPLE_H
+#define ML99_PRIV_TUPLE_H
+
+#include <metalang99/priv/bool.h>
+#include <metalang99/priv/util.h>
+
+#define ML99_PRIV_IS_TUPLE(x) ML99_PRIV_NOT(ML99_PRIV_IS_UNTUPLE(x))
+#define ML99_PRIV_IS_TUPLE_FAST(x) ML99_PRIV_NOT(ML99_PRIV_IS_UNTUPLE_FAST(x))
+
+#define ML99_PRIV_IS_UNTUPLE(x) \
+ ML99_PRIV_IF( \
+ ML99_PRIV_IS_DOUBLE_TUPLE_BEGINNING(x), \
+ ML99_PRIV_TRUE, \
+ ML99_PRIV_IS_UNTUPLE_FAST) \
+ (x)
+
+#define ML99_PRIV_IS_UNTUPLE_FAST(x) ML99_PRIV_SND(ML99_PRIV_IS_UNTUPLE_FAST_TEST x, 1)
+#define ML99_PRIV_IS_UNTUPLE_FAST_TEST(...) ~, 0
+
+#define ML99_PRIV_UNTUPLE(x) ML99_PRIV_EXPAND x
+
+/**
+ * Checks whether @p x takes the form `(...) (...) ...`.
+ *
+ * This often happens when you miss a comma between items:
+ * - `v(123) v(456)`
+ * - `(Foo, int) (Bar, int)` (as in Datatype99)
+ * - etc.
+ */
+#define ML99_PRIV_IS_DOUBLE_TUPLE_BEGINNING(x) \
+ ML99_PRIV_CONTAINS_COMMA(ML99_PRIV_EXPAND(ML99_PRIV_COMMA ML99_PRIV_EMPTY x))
+
+#endif // ML99_PRIV_TUPLE_H
diff --git a/test/external/metalang99/include/metalang99/priv/util.h b/test/external/metalang99/include/metalang99/priv/util.h
new file mode 100644
index 0000000..80a5bc4
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/priv/util.h
@@ -0,0 +1,27 @@
+#ifndef ML99_PRIV_UTIL_H
+#define ML99_PRIV_UTIL_H
+
+#define ML99_PRIV_CAT(x, y) ML99_PRIV_PRIMITIVE_CAT(x, y)
+#define ML99_PRIV_PRIMITIVE_CAT(x, y) x##y
+
+#define ML99_PRIV_CAT3(x, y, z) ML99_PRIV_PRIMITIVE_CAT3(x, y, z)
+#define ML99_PRIV_PRIMITIVE_CAT3(x, y, z) x##y##z
+
+#define ML99_PRIV_EXPAND(...) __VA_ARGS__
+#define ML99_PRIV_EMPTY(...)
+#define ML99_PRIV_COMMA(...) ,
+
+#define ML99_PRIV_HEAD(...) ML99_PRIV_HEAD_AUX(__VA_ARGS__, ~)
+#define ML99_PRIV_HEAD_AUX(x, ...) x
+
+#define ML99_PRIV_TAIL(...) ML99_PRIV_TAIL_AUX(__VA_ARGS__)
+#define ML99_PRIV_TAIL_AUX(_x, ...) __VA_ARGS__
+
+#define ML99_PRIV_SND(...) ML99_PRIV_SND_AUX(__VA_ARGS__, ~)
+#define ML99_PRIV_SND_AUX(_x, y, ...) y
+
+#define ML99_PRIV_CONTAINS_COMMA(...) ML99_PRIV_X_AS_COMMA(__VA_ARGS__, ML99_PRIV_COMMA(), ~)
+#define ML99_PRIV_X_AS_COMMA(_head, x, ...) ML99_PRIV_CONTAINS_COMMA_RESULT(x, 0, 1, ~)
+#define ML99_PRIV_CONTAINS_COMMA_RESULT(x, _, result, ...) result
+
+#endif // ML99_PRIV_UTIL_H
diff --git a/test/external/metalang99/include/metalang99/seq.h b/test/external/metalang99/include/metalang99/seq.h
new file mode 100644
index 0000000..be2efae
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/seq.h
@@ -0,0 +1,204 @@
+/**
+ * @file
+ * Sequences: `(x)(y)(z)`.
+ *
+ * A sequence is represented as `(...) (...) ...`. For example, these are sequences:
+ * - `(~, ~, ~)`
+ * - `(1)(2)(3)`
+ * - `(+, -, *, /)(123)(~)`
+ *
+ * Sequences can represent syntax like `X(...) Y(...) Z(...)`, where `X`, `Y`, and `Z` expand to a
+ * [tuple](tuple.html), thereby forming a sequence. A perfect example is
+ * [Interface99](https://github.com/hirrolot/interface99), which allows a user to define a software
+ * interface via a number of `vfunc(...)` macro invocations:
+ *
+ * @code
+ * #define Shape_IFACE \
+ * vfunc( int, perim, const VSelf) \
+ * vfunc(void, scale, VSelf, int factor)
+ *
+ * interface(Shape);
+ * @endcode
+ *
+ * With `vfunc` being defined as follows (simplified):
+ *
+ * @code
+ * #define vfunc(ret_ty, name, ...) (ret_ty, name, __VA_ARGS__)
+ * @endcode
+ *
+ * @note Sequences are more time and space-efficient than lists, but export less functionality; if a
+ * needed function is missed, invoking #ML99_listFromSeq and then manipulating with the resulting
+ * Cons-list might be helpful.
+ */
+
+#ifndef ML99_SEQ_H
+#define ML99_SEQ_H
+
+#include <metalang99/nat/inc.h>
+#include <metalang99/priv/tuple.h>
+#include <metalang99/priv/util.h>
+
+#include <metalang99/lang.h>
+
+/**
+ * True iff @p seq contains no elements (which means an empty preprocessing lexeme).
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/seq.h>
+ *
+ * // 1
+ * ML99_seqIsEmpty(v())
+ *
+ * // 0
+ * ML99_seqIsEmpty(v((~)(~)(~)))
+ * @endcode
+ */
+#define ML99_seqIsEmpty(seq) ML99_call(ML99_seqIsEmpty, seq)
+
+/**
+ * Expands to a metafunction extracting the @p i -indexed element of @p seq.
+ *
+ * @p i can range from 0 to 7, inclusively.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/seq.h>
+ *
+ * // 2
+ * ML99_seqGet(1)(v((1)(2)(3)))
+ * @endcode
+ */
+#define ML99_seqGet(i) ML99_PRIV_CAT(ML99_PRIV_seqGet_, i)
+
+/**
+ * Extracts the tail of @p seq.
+ *
+ * @p seq must contain at least one element. If @p seq contains **only** one element, the result is
+ * `ML99_empty()`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/seq.h>
+ *
+ * // (2)(3)
+ * ML99_seqTail(v((1)(2)(3)))
+ * @endcode
+ */
+#define ML99_seqTail(seq) ML99_call(ML99_seqTail, seq)
+
+/**
+ * Applies @p f to each element in @p seq.
+ *
+ * The result is `ML99_appl(f, x1) ... ML99_appl(f, xN)`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/seq.h>
+ *
+ * #define F_IMPL(x) v(@x)
+ * #define F_ARITY 1
+ *
+ * // @x @y @z
+ * ML99_seqForEach(v(F), v((x)(y)(z)))
+ * @endcode
+ */
+#define ML99_seqForEach(f, seq) ML99_call(ML99_seqForEach, f, seq)
+
+/**
+ * Applies @p f to each element in @p seq with an index.
+ *
+ * The result is `ML99_appl2(f, 0, x1) ... ML99_appl2(f, N - 1, xN)`.
+ *
+ * @code
+ * #include <metalang99/seq.h>
+ *
+ * #define F_IMPL(i, x) v(@x##i)
+ * #define F_ARITY 2
+ *
+ * // @x0 @y1 @z2
+ * ML99_seqForEachI(v(F), v((x)(y)(z)))
+ * @endcode
+ */
+#define ML99_seqForEachI(f, seq) ML99_call(ML99_seqForEachI, f, seq)
+
+#define ML99_SEQ_IS_EMPTY(seq) ML99_PRIV_NOT(ML99_PRIV_CONTAINS_COMMA(ML99_PRIV_COMMA seq))
+#define ML99_SEQ_GET(i) ML99_PRIV_CAT(ML99_PRIV_SEQ_GET_, i)
+#define ML99_SEQ_TAIL(seq) ML99_PRIV_TAIL(ML99_PRIV_COMMA seq)
+
+#ifndef DOXYGEN_IGNORE
+
+#define ML99_seqIsEmpty_IMPL(seq) v(ML99_SEQ_IS_EMPTY(seq))
+
+#define ML99_PRIV_seqGet_0(seq) ML99_call(ML99_PRIV_seqGet_0, seq)
+#define ML99_PRIV_seqGet_1(seq) ML99_call(ML99_PRIV_seqGet_1, seq)
+#define ML99_PRIV_seqGet_2(seq) ML99_call(ML99_PRIV_seqGet_2, seq)
+#define ML99_PRIV_seqGet_3(seq) ML99_call(ML99_PRIV_seqGet_3, seq)
+#define ML99_PRIV_seqGet_4(seq) ML99_call(ML99_PRIV_seqGet_4, seq)
+#define ML99_PRIV_seqGet_5(seq) ML99_call(ML99_PRIV_seqGet_5, seq)
+#define ML99_PRIV_seqGet_6(seq) ML99_call(ML99_PRIV_seqGet_6, seq)
+#define ML99_PRIV_seqGet_7(seq) ML99_call(ML99_PRIV_seqGet_7, seq)
+
+#define ML99_PRIV_seqGet_0_IMPL(seq) v(ML99_SEQ_GET(0)(seq))
+#define ML99_PRIV_seqGet_1_IMPL(seq) v(ML99_SEQ_GET(1)(seq))
+#define ML99_PRIV_seqGet_2_IMPL(seq) v(ML99_SEQ_GET(2)(seq))
+#define ML99_PRIV_seqGet_3_IMPL(seq) v(ML99_SEQ_GET(3)(seq))
+#define ML99_PRIV_seqGet_4_IMPL(seq) v(ML99_SEQ_GET(4)(seq))
+#define ML99_PRIV_seqGet_5_IMPL(seq) v(ML99_SEQ_GET(5)(seq))
+#define ML99_PRIV_seqGet_6_IMPL(seq) v(ML99_SEQ_GET(6)(seq))
+#define ML99_PRIV_seqGet_7_IMPL(seq) v(ML99_SEQ_GET(7)(seq))
+
+#define ML99_PRIV_SEQ_GET_0(seq) ML99_PRIV_UNTUPLE(ML99_PRIV_HEAD(ML99_PRIV_SEQ_SEPARATE seq))
+#define ML99_PRIV_SEQ_GET_1(seq) ML99_PRIV_SEQ_GET_0(ML99_SEQ_TAIL(seq))
+#define ML99_PRIV_SEQ_GET_2(seq) ML99_PRIV_SEQ_GET_1(ML99_SEQ_TAIL(seq))
+#define ML99_PRIV_SEQ_GET_3(seq) ML99_PRIV_SEQ_GET_2(ML99_SEQ_TAIL(seq))
+#define ML99_PRIV_SEQ_GET_4(seq) ML99_PRIV_SEQ_GET_3(ML99_SEQ_TAIL(seq))
+#define ML99_PRIV_SEQ_GET_5(seq) ML99_PRIV_SEQ_GET_4(ML99_SEQ_TAIL(seq))
+#define ML99_PRIV_SEQ_GET_6(seq) ML99_PRIV_SEQ_GET_5(ML99_SEQ_TAIL(seq))
+#define ML99_PRIV_SEQ_GET_7(seq) ML99_PRIV_SEQ_GET_6(ML99_SEQ_TAIL(seq))
+
+#define ML99_PRIV_SEQ_SEPARATE(...) (__VA_ARGS__),
+
+#define ML99_seqTail_IMPL(seq) v(ML99_SEQ_TAIL(seq))
+
+#define ML99_seqForEach_IMPL(f, seq) \
+ ML99_PRIV_CAT(ML99_PRIV_seqForEach_, ML99_SEQ_IS_EMPTY(seq))(f, seq)
+#define ML99_PRIV_seqForEach_1(...) v(ML99_PRIV_EMPTY())
+#define ML99_PRIV_seqForEach_0(f, seq) \
+ ML99_TERMS( \
+ ML99_appl_IMPL(f, ML99_SEQ_GET(0)(seq)), \
+ ML99_callUneval(ML99_seqForEach, f, ML99_SEQ_TAIL(seq)))
+
+#define ML99_seqForEachI_IMPL(f, seq) ML99_PRIV_seqForEachIAux_IMPL(f, 0, seq)
+#define ML99_PRIV_seqForEachIAux_IMPL(f, i, seq) \
+ ML99_PRIV_CAT(ML99_PRIV_seqForEachI_, ML99_SEQ_IS_EMPTY(seq))(f, i, seq)
+#define ML99_PRIV_seqForEachI_1(...) v(ML99_PRIV_EMPTY())
+#define ML99_PRIV_seqForEachI_0(f, i, seq) \
+ ML99_TERMS( \
+ ML99_appl2_IMPL(f, i, ML99_SEQ_GET(0)(seq)), \
+ ML99_callUneval(ML99_PRIV_seqForEachIAux, f, ML99_PRIV_INC(i), ML99_SEQ_TAIL(seq)))
+
+// Arity specifiers {
+
+#define ML99_seqIsEmpty_ARITY 1
+#define ML99_seqTail_ARITY 1
+#define ML99_seqForEach_ARITY 2
+#define ML99_seqForEachI_ARITY 2
+
+#define ML99_PRIV_seqGet_0_ARITY 1
+#define ML99_PRIV_seqGet_1_ARITY 1
+#define ML99_PRIV_seqGet_2_ARITY 1
+#define ML99_PRIV_seqGet_3_ARITY 1
+#define ML99_PRIV_seqGet_4_ARITY 1
+#define ML99_PRIV_seqGet_5_ARITY 1
+#define ML99_PRIV_seqGet_6_ARITY 1
+#define ML99_PRIV_seqGet_7_ARITY 1
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_SEQ_H
diff --git a/test/external/metalang99/include/metalang99/stmt.h b/test/external/metalang99/include/metalang99/stmt.h
new file mode 100644
index 0000000..54bb28f
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/stmt.h
@@ -0,0 +1,167 @@
+/**
+ * @file
+ * Statement chaining.
+ *
+ * This module exports a bunch of so-called _statement chaining macros_: they expect a statement
+ * right after their invocation, and moreover, an invocation of such a macro with a statement
+ * afterwards altogether form a single statement.
+ *
+ * How can this be helpful? Imagine you are writing a macro with the following syntax:
+ *
+ * @code
+ * MY_MACRO(...) { bla bla bla }
+ * @endcode
+ *
+ * Then `MY_MACRO` must expand to a _statement prefix_, i.e., something that expects a statement
+ * after itself. One possible solution is to make `MY_MACRO` expand to a sequence of statement
+ * chaining macros like this:
+ *
+ * @code
+ * #define MY_MACRO(...) \
+ * ML99_INTRODUCE_VAR_TO_STMT(int x = 5) \
+ * ML99_CHAIN_EXPR_STMT(printf("%d\n", x)) \
+ * // and so on...
+ * @endcode
+ *
+ * Here #ML99_INTRODUCE_VAR_TO_STMT accepts the statement formed by #ML99_CHAIN_EXPR_STMT, which, in
+ * turn, accepts the next statement and so on, until a caller of `MY_MACRO` specifies the final
+ * statement, thus completing the chain.
+ *
+ * @see https://www.chiark.greenend.org.uk/~sgtatham/mp/ for a more involved explanation.
+ */
+
+#ifndef ML99_STMT_H
+#define ML99_STMT_H
+
+#include <metalang99/util.h>
+
+/**
+ * A statement chaining macro that introduces several variable definitions to a statement right
+ * after its invocation.
+ *
+ * Variable definitions must be specified as in the first clause of the for-loop.
+ *
+ * Top-level `break`/`continue` inside a user-provided statement are prohibited.
+ *
+ * # Example
+ *
+ * @code
+ * #include <metalang99/stmt.h>
+ *
+ * for (int i = 0; i < 10; i++)
+ * ML99_INTRODUCE_VAR_TO_STMT(double x = 5.0, y = 7.0)
+ * if (i % 2 == 0)
+ * printf("i = %d, x = %f, y = %f\n", i, x, y);
+ * @endcode
+ */
+#define ML99_INTRODUCE_VAR_TO_STMT(...) ML99_PRIV_INTRODUCE_VAR_TO_STMT_INNER(__VA_ARGS__)
+
+/**
+ * The same as #ML99_INTRODUCE_VAR_TO_STMT but deals with a single non-`NULL` pointer.
+ *
+ * In comparison with #ML99_INTRODUCE_VAR_TO_STMT, this macro generates a little less code. It
+ * introduces a pointer to @p ty identified by @p name and initialized to @p init.
+ *
+ * Top-level `break`/`continue` inside a user-provided statement are prohibited.
+ *
+ * # Example
+ *
+ * @code
+ * #include <metalang99/stmt.h>
+ *
+ * double x = 5.0, y = 7.0;
+ *
+ * for (int i = 0; i < 10; i++)
+ * ML99_INTRODUCE_NON_NULL_PTR_TO_STMT(double, x_ptr, &x)
+ * ML99_INTRODUCE_NON_NULL_PTR_TO_STMT(double, y_ptr, &y)
+ * printf("i = %d, x = %f, y = %f\n", i, *x_ptr, *y_ptr);
+ * @endcode
+ *
+ * @note Unlike #ML99_INTRODUCE_VAR_TO_STMT, the generated pointer is guaranteed to be used at least
+ * once, meaning that you do not need to suppress the unused variable warning.
+ * @note @p init is guaranteed to be executed only once.
+ */
+#define ML99_INTRODUCE_NON_NULL_PTR_TO_STMT(ty, name, init) \
+ ML99_PRIV_SHADOWS(for (ty *name = (init); name != 0; name = 0))
+
+/**
+ * A statement chaining macro that executes an expression statement derived from @p expr right
+ * before the next statement.
+ *
+ * Top-level `break`/`continue` inside a user-provided statement are prohibited.
+ *
+ * # Example
+ *
+ * @code
+ * #include <metalang99/stmt.h>
+ *
+ * int x;
+ *
+ * for(;;)
+ * ML99_CHAIN_EXPR_STMT(x = 5)
+ * ML99_CHAIN_EXPR_STMT(printf("%d\n", x))
+ * puts("abc");
+ * @endcode
+ */
+#define ML99_CHAIN_EXPR_STMT(expr) \
+ ML99_PRIV_SHADOWS(for (int ml99_priv_expr_stmt_break = ((expr), 0); \
+ ml99_priv_expr_stmt_break != 1; \
+ ml99_priv_expr_stmt_break = 1))
+
+/**
+ * The same as #ML99_CHAIN_EXPR_STMT but executes @p expr **after** the next statement.
+ */
+#define ML99_CHAIN_EXPR_STMT_AFTER(expr) \
+ ML99_PRIV_SHADOWS(for (int ml99_priv_expr_stmt_after_break = 0; \
+ ml99_priv_expr_stmt_after_break != 1; \
+ ((expr), ml99_priv_expr_stmt_after_break = 1)))
+
+/**
+ * A statement chaining macro that suppresses the "unused X" warning right before a statement after
+ * its invocation.
+ *
+ * Top-level `break`/`continue` inside a user-provided statement are prohibited.
+ *
+ * # Example
+ *
+ * @code
+ * #include <metalang99/stmt.h>
+ *
+ * int x, y;
+ *
+ * for(;;)
+ * ML99_SUPPRESS_UNUSED_BEFORE_STMT(x)
+ * ML99_SUPPRESS_UNUSED_BEFORE_STMT(y)
+ * puts("abc");
+ * @endcode
+ *
+ * @deprecated Use `ML99_CHAIN_EXPR_STMT((void)expr)` instead.
+ */
+#define ML99_SUPPRESS_UNUSED_BEFORE_STMT(expr) ML99_CHAIN_EXPR_STMT((void)expr)
+
+#ifndef DOXYGEN_IGNORE
+
+// See <https://github.com/hirrolot/metalang99/issues/25>.
+#ifdef __cplusplus
+#define ML99_PRIV_INTRODUCE_VAR_TO_STMT_INNER(...) \
+ ML99_PRIV_SHADOWS(for (__VA_ARGS__, \
+ *ml99_priv_break_arr[] = {0, 0}, \
+ **ml99_priv_break = &ml99_priv_break_arr[0]; \
+ ml99_priv_break == &ml99_priv_break_arr[0]; \
+ ml99_priv_break++))
+#else
+#define ML99_PRIV_INTRODUCE_VAR_TO_STMT_INNER(...) \
+ ML99_PRIV_SHADOWS(for (__VA_ARGS__, *ml99_priv_break = (void *)0; \
+ ml99_priv_break != (void *)1; \
+ ml99_priv_break = (void *)1))
+#endif
+
+#define ML99_PRIV_SHADOWS(...) \
+ ML99_CLANG_PRAGMA("clang diagnostic push") \
+ ML99_CLANG_PRAGMA("clang diagnostic ignored \"-Wshadow\"") \
+ __VA_ARGS__ \
+ ML99_CLANG_PRAGMA("clang diagnostic pop")
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_STMT_H
diff --git a/test/external/metalang99/include/metalang99/tuple.h b/test/external/metalang99/include/metalang99/tuple.h
new file mode 100644
index 0000000..da92298
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/tuple.h
@@ -0,0 +1,371 @@
+/**
+ * @file
+ * Tuples: `(x, y, z)`.
+ *
+ * A tuple is represented as `(x1, ..., xN)`. Tuples are a convenient way to deal with product
+ * types. For example:
+ *
+ * [[examples/rectangle.c](https://github.com/hirrolot/metalang99/blob/master/examples/rectangle.c)]
+ * @include rectangle.c
+ *
+ * @note Tuples are more time and space-efficient than lists, but export less functionality; if a
+ * needed function is missed, invoking #ML99_list and then manipulating with the resulting Cons-list
+ * might be helpful.
+ */
+
+#ifndef ML99_TUPLE_H
+#define ML99_TUPLE_H
+
+#include <metalang99/priv/bool.h>
+#include <metalang99/priv/tuple.h>
+#include <metalang99/priv/util.h>
+
+#include <metalang99/lang.h>
+#include <metalang99/variadics.h>
+
+/**
+ * Transforms a sequence of arguments into `(...)`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/tuple.h>
+ *
+ * // (1, 2, 3)
+ * ML99_tuple(v(1, 2, 3))
+ * @endcode
+ */
+#define ML99_tuple(...) ML99_call(ML99_tuple, __VA_ARGS__)
+
+/**
+ * Transforms a sequence of arguments into `(v(...))`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/tuple.h>
+ *
+ * // (v(1, 2, 3))
+ * ML99_tupleEval(v(1, 2, 3))
+ * @endcode
+ *
+ * @deprecated I have seen no single use case over time. Please, [open an
+ * issue](https://github.com/hirrolot/metalang99/issues/new/choose) if you need this function.
+ */
+#define ML99_tupleEval(...) ML99_call(ML99_tupleEval, __VA_ARGS__)
+
+/**
+ * Untuples the tuple @p x, leaving the result unevaluated.
+ *
+ * If @p x is not a tuple, it emits a fatal error.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/tuple.h>
+ *
+ * // 1, 2, 3
+ * ML99_untuple(v((1, 2, 3)))
+ * @endcode
+ */
+#define ML99_untuple(x) ML99_call(ML99_untuple, x)
+
+/**
+ * The same as #ML99_untuple.
+ *
+ * @deprecated Use #ML99_untuple instead.
+ */
+#define ML99_untupleChecked(x) ML99_call(ML99_untupleChecked, x)
+
+/**
+ * Untuples the tuple @p x and evaluates the result.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/tuple.h>
+ *
+ * // 1, 2, 3
+ * ML99_untupleEval(v((v(1, 2, 3))))
+ * @endcode
+ *
+ * @deprecated For the same reason as #ML99_tupleEval.
+ */
+#define ML99_untupleEval(x) ML99_call(ML99_untupleEval, x)
+
+/**
+ * Tests whether @p x is inside parentheses or not.
+ *
+ * The preconditions are the same as of #ML99_isUntuple.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/tuple.h>
+ *
+ * // 0
+ * ML99_isTuple(v(123))
+ *
+ * // 1
+ * ML99_isTuple(v((123)))
+ * @endcode
+ */
+#define ML99_isTuple(x) ML99_call(ML99_isTuple, x)
+
+/**
+ * The inverse of #ML99_isTuple.
+ *
+ * @p x must be either of these forms:
+ * - `(...)` (reported as non-untupled)
+ * - `(...) (...) ...` (reported as untupled)
+ * - anything else not beginning with `(...)` (reported as untupled)
+ *
+ * For example (respectively):
+ * - `(~, ~, ~)` (non-untupled)
+ * - `(~, ~, ~) (~, ~, ~)` or `(~, ~, ~) (~, ~, ~) abc` (untupled)
+ * - `123` or `123 (~, ~, ~)` (untupled)
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/tuple.h>
+ *
+ * // 1
+ * ML99_isUntuple(v(123))
+ *
+ * // 0
+ * ML99_isUntuple(v((123)))
+ *
+ * // 1
+ * ML99_isUntuple(v((123) (456) (789)))
+ * @endcode
+ */
+#define ML99_isUntuple(x) ML99_call(ML99_isUntuple, x)
+
+/**
+ * Computes the count of items in the tuple @p x.
+ *
+ * At most 63 items can be contained in @p x.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/tuple.h>
+ *
+ * // 3
+ * ML99_tupleCount(v((~, ~, ~)))
+ *
+ * // 1
+ * ML99_tupleCount(v(()))
+ * @endcode
+ */
+#define ML99_tupleCount(x) ML99_call(ML99_tupleCount, x)
+
+/**
+ * Tells if the tuple @p x contains only one item or not.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/tuple.h>
+ *
+ * // 1
+ * ML99_tupleIsSingle(v((~)))
+ *
+ * // 0
+ * ML99_tupleIsSingle(v((~, ~, ~)))
+ * @endcode
+ */
+#define ML99_tupleIsSingle(x) ML99_call(ML99_tupleIsSingle, x)
+
+/**
+ * Expands to a metafunction extracting the @p i -indexed element of a tuple.
+ *
+ * @p i can range from 0 to 7, inclusively.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/tuple.h>
+ *
+ * // 2
+ * ML99_tupleGet(1)(v((1, 2, 3)))
+ * @endcode
+ */
+#define ML99_tupleGet(i) ML99_PRIV_CAT(ML99_PRIV_tupleGet_, i)
+
+/**
+ * Extracts the tuple's tail.
+ *
+ * @p x must contain at least two elements.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/tuple.h>
+ *
+ * // 2, 3
+ * ML99_tupleTail(v((1, 2, 3)))
+ * @endcode
+ */
+#define ML99_tupleTail(x) ML99_call(ML99_tupleTail, x)
+
+/**
+ * Appends provided variadic arguments to the tuple @p x.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/tuple.h>
+ *
+ * // (1, 2, 3)
+ * ML99_tupleAppend(ML99_tuple(v(1)), v(2, 3))
+ * @endcode
+ */
+#define ML99_tupleAppend(x, ...) ML99_call(ML99_tupleAppend, x, __VA_ARGS__)
+
+/**
+ * Prepends provided variadic arguments to the tuple @p x.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/tuple.h>
+ *
+ * // (1, 2, 3)
+ * ML99_tuplePrepend(ML99_tuple(v(3)), v(1, 2))
+ * @endcode
+ */
+#define ML99_tuplePrepend(x, ...) ML99_call(ML99_tuplePrepend, x, __VA_ARGS__)
+
+/**
+ * A shortcut for `ML99_variadicsForEach(f, ML99_untuple(x))`.
+ */
+#define ML99_tupleForEach(f, x) ML99_call(ML99_tupleForEach, f, x)
+
+/**
+ * A shortcut for `ML99_variadicsForEachI(f, ML99_untuple(x))`.
+ */
+#define ML99_tupleForEachI(f, x) ML99_call(ML99_tupleForEachI, f, x)
+
+/**
+ * Emits a fatal error if @p x is not a tuple, otherwise results in emptiness.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/tuple.h>
+ *
+ * #define F_IMPL(x) ML99_TERMS(ML99_assertIsTuple(v(x)), ML99_untuple(v(x)))
+ *
+ * // 1, 2, 3
+ * ML99_call(F, v((1, 2, 3)))
+ *
+ * // A compile-time tuple mismatch error.
+ * ML99_call(F, v(123))
+ * @endcode
+ */
+#define ML99_assertIsTuple(x) ML99_call(ML99_assertIsTuple, x)
+
+#define ML99_TUPLE(...) (__VA_ARGS__)
+#define ML99_UNTUPLE(x) ML99_PRIV_EXPAND x
+#define ML99_IS_TUPLE(x) ML99_PRIV_IS_TUPLE(x)
+#define ML99_IS_UNTUPLE(x) ML99_PRIV_IS_UNTUPLE(x)
+#define ML99_TUPLE_COUNT(x) ML99_VARIADICS_COUNT(ML99_UNTUPLE(x))
+#define ML99_TUPLE_IS_SINGLE(x) ML99_VARIADICS_IS_SINGLE(ML99_UNTUPLE(x))
+#define ML99_TUPLE_GET(i) ML99_PRIV_CAT(ML99_PRIV_TUPLE_GET_, i)
+#define ML99_TUPLE_TAIL(x) ML99_VARIADICS_TAIL(ML99_UNTUPLE(x))
+#define ML99_TUPLE_APPEND(x, ...) (ML99_UNTUPLE(x), __VA_ARGS__)
+#define ML99_TUPLE_PREPEND(x, ...) (__VA_ARGS__, ML99_UNTUPLE(x))
+
+#ifndef DOXYGEN_IGNORE
+
+#define ML99_tuple_IMPL(...) v(ML99_TUPLE(__VA_ARGS__))
+#define ML99_tupleEval_IMPL(...) v((v(__VA_ARGS__)))
+#define ML99_untuple_IMPL(x) \
+ ML99_PRIV_IF(ML99_IS_TUPLE(x), ML99_PRIV_UNTUPLE_TERM, ML99_PRIV_NOT_TUPLE_ERROR)(x)
+#define ML99_untupleChecked_IMPL(x) ML99_untuple_IMPL(x)
+#define ML99_untupleEval_IMPL(x) ML99_PRIV_EXPAND x
+#define ML99_isTuple_IMPL(x) v(ML99_IS_TUPLE(x))
+#define ML99_isUntuple_IMPL(x) v(ML99_IS_UNTUPLE(x))
+#define ML99_tupleCount_IMPL(x) v(ML99_TUPLE_COUNT(x))
+#define ML99_tupleIsSingle_IMPL(x) v(ML99_TUPLE_IS_SINGLE(x))
+
+#define ML99_PRIV_UNTUPLE_TERM(x) v(ML99_UNTUPLE(x))
+
+#define ML99_PRIV_tupleGet_0(x) ML99_call(ML99_PRIV_tupleGet_0, x)
+#define ML99_PRIV_tupleGet_1(x) ML99_call(ML99_PRIV_tupleGet_1, x)
+#define ML99_PRIV_tupleGet_2(x) ML99_call(ML99_PRIV_tupleGet_2, x)
+#define ML99_PRIV_tupleGet_3(x) ML99_call(ML99_PRIV_tupleGet_3, x)
+#define ML99_PRIV_tupleGet_4(x) ML99_call(ML99_PRIV_tupleGet_4, x)
+#define ML99_PRIV_tupleGet_5(x) ML99_call(ML99_PRIV_tupleGet_5, x)
+#define ML99_PRIV_tupleGet_6(x) ML99_call(ML99_PRIV_tupleGet_6, x)
+#define ML99_PRIV_tupleGet_7(x) ML99_call(ML99_PRIV_tupleGet_7, x)
+
+#define ML99_PRIV_tupleGet_0_IMPL(x) v(ML99_TUPLE_GET(0)(x))
+#define ML99_PRIV_tupleGet_1_IMPL(x) v(ML99_TUPLE_GET(1)(x))
+#define ML99_PRIV_tupleGet_2_IMPL(x) v(ML99_TUPLE_GET(2)(x))
+#define ML99_PRIV_tupleGet_3_IMPL(x) v(ML99_TUPLE_GET(3)(x))
+#define ML99_PRIV_tupleGet_4_IMPL(x) v(ML99_TUPLE_GET(4)(x))
+#define ML99_PRIV_tupleGet_5_IMPL(x) v(ML99_TUPLE_GET(5)(x))
+#define ML99_PRIV_tupleGet_6_IMPL(x) v(ML99_TUPLE_GET(6)(x))
+#define ML99_PRIV_tupleGet_7_IMPL(x) v(ML99_TUPLE_GET(7)(x))
+
+#define ML99_PRIV_TUPLE_GET_0(x) ML99_VARIADICS_GET(0)(ML99_UNTUPLE(x))
+#define ML99_PRIV_TUPLE_GET_1(x) ML99_VARIADICS_GET(1)(ML99_UNTUPLE(x))
+#define ML99_PRIV_TUPLE_GET_2(x) ML99_VARIADICS_GET(2)(ML99_UNTUPLE(x))
+#define ML99_PRIV_TUPLE_GET_3(x) ML99_VARIADICS_GET(3)(ML99_UNTUPLE(x))
+#define ML99_PRIV_TUPLE_GET_4(x) ML99_VARIADICS_GET(4)(ML99_UNTUPLE(x))
+#define ML99_PRIV_TUPLE_GET_5(x) ML99_VARIADICS_GET(5)(ML99_UNTUPLE(x))
+#define ML99_PRIV_TUPLE_GET_6(x) ML99_VARIADICS_GET(6)(ML99_UNTUPLE(x))
+#define ML99_PRIV_TUPLE_GET_7(x) ML99_VARIADICS_GET(7)(ML99_UNTUPLE(x))
+
+#define ML99_tupleTail_IMPL(x) v(ML99_TUPLE_TAIL(x))
+
+#define ML99_tupleAppend_IMPL(x, ...) v(ML99_TUPLE_APPEND(x, __VA_ARGS__))
+#define ML99_tuplePrepend_IMPL(x, ...) v(ML99_TUPLE_PREPEND(x, __VA_ARGS__))
+#define ML99_tupleForEach_IMPL(f, x) ML99_variadicsForEach_IMPL(f, ML99_UNTUPLE(x))
+#define ML99_tupleForEachI_IMPL(f, x) ML99_variadicsForEachI_IMPL(f, ML99_UNTUPLE(x))
+
+#define ML99_assertIsTuple_IMPL(x) \
+ ML99_PRIV_IF(ML99_IS_UNTUPLE(x), ML99_PRIV_NOT_TUPLE_ERROR(x), v(ML99_PRIV_EMPTY()))
+
+// clang-format off
+#define ML99_PRIV_NOT_TUPLE_ERROR(x) \
+ ML99_PRIV_IF( \
+ ML99_PRIV_IS_DOUBLE_TUPLE_BEGINNING(x), \
+ ML99_fatal(ML99_assertIsTuple, x must be (x1, ..., xN), did you miss a comma?), \
+ ML99_fatal(ML99_assertIsTuple, x must be (x1, ..., xN)))
+// clang-format on
+
+// Arity specifiers {
+
+#define ML99_tuple_ARITY 1
+#define ML99_tupleEval_ARITY 1
+#define ML99_untuple_ARITY 1
+#define ML99_untupleChecked_ARITY 1
+#define ML99_untupleEval_ARITY 1
+#define ML99_isTuple_ARITY 1
+#define ML99_isUntuple_ARITY 1
+#define ML99_tupleCount_ARITY 1
+#define ML99_tupleIsSingle_ARITY 1
+#define ML99_tupleTail_ARITY 1
+#define ML99_tupleAppend_ARITY 2
+#define ML99_tuplePrepend_ARITY 2
+#define ML99_tupleForEach_ARITY 2
+#define ML99_tupleForEachI_ARITY 2
+#define ML99_assertIsTuple_ARITY 1
+
+#define ML99_PRIV_tupleGet_0_ARITY 1
+#define ML99_PRIV_tupleGet_1_ARITY 1
+#define ML99_PRIV_tupleGet_2_ARITY 1
+#define ML99_PRIV_tupleGet_3_ARITY 1
+#define ML99_PRIV_tupleGet_4_ARITY 1
+#define ML99_PRIV_tupleGet_5_ARITY 1
+#define ML99_PRIV_tupleGet_6_ARITY 1
+#define ML99_PRIV_tupleGet_7_ARITY 1
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_TUPLE_H
diff --git a/test/external/metalang99/include/metalang99/util.h b/test/external/metalang99/include/metalang99/util.h
new file mode 100644
index 0000000..b4be573
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/util.h
@@ -0,0 +1,444 @@
+/**
+ * @file
+ * Utilitary stuff.
+ */
+
+#ifndef ML99_UTIL_H
+#define ML99_UTIL_H
+
+#include <metalang99/priv/util.h>
+
+#include <metalang99/ident.h> // For backwards compatibility.
+#include <metalang99/lang.h>
+
+/**
+ * Concatenates @p a with @p b and evaluates the result.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * #define ABC123 v(Billie Jean)
+ *
+ * // Billie Jean
+ * ML99_catEval(v(ABC), v(123))
+ *
+ * // ERROR: 123ABC is not a valid Metalang99 term.
+ * ML99_catEval(v(123), v(ABC))
+ * @endcode
+ *
+ * @deprecated I have seen no single use case over time. Please, [open an
+ * issue](https://github.com/hirrolot/metalang99/issues/new/choose) if you need this function.
+ */
+#define ML99_catEval(a, b) ML99_call(ML99_catEval, a, b)
+
+/**
+ * Concatenates @p a with @p b, leaving the result unevaluated.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * #define ABC123 Billie Jean
+ *
+ * // Billie Jean
+ * ML99_cat(v(ABC), v(123))
+ *
+ * // 123ABC
+ * ML99_cat(v(123), v(ABC))
+ * @endcode
+ */
+#define ML99_cat(a, b) ML99_call(ML99_cat, a, b)
+
+/**
+ * The same as #ML99_cat but deals with 3 parameters.
+ */
+#define ML99_cat3(a, b, c) ML99_call(ML99_cat3, a, b, c)
+
+/**
+ * The same as #ML99_cat but deals with 4 parameters.
+ */
+#define ML99_cat4(a, b, c, d) ML99_call(ML99_cat4, a, b, c, d)
+
+/**
+ * Stringifies provided arguments.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * // "Billie Jean"
+ * ML99_stringify(v(Billie Jean))
+ * @endcode
+ */
+#define ML99_stringify(...) ML99_call(ML99_stringify, __VA_ARGS__)
+
+/**
+ * Evaluates to nothing.
+ */
+#define ML99_empty(...) ML99_callUneval(ML99_empty, )
+
+/**
+ * Evaluates to its arguments.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * // 1, 2, 3
+ * ML99_id(v(1, 2, 3))
+ * @endcode
+ */
+#define ML99_id(...) ML99_call(ML99_id, __VA_ARGS__)
+
+/**
+ * Evaluates to @p x, skipping @p a.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * // 123
+ * ML99_const(v(123), v(5))
+ * @endcode
+ */
+#define ML99_const(x, a) ML99_call(ML99_const, x, a)
+
+/**
+ * Reverses the order of arguments of the binary function @p f.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * // ABC123
+ * ML99_appl2(ML99_flip(v(ML99_catUnevaluated)), v(123), v(ABC))
+ * @endcode
+ */
+#define ML99_flip(f) ML99_call(ML99_flip, f)
+
+/**
+ * Accepts terms and evaluates them with the space-separator.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * // 1 2 3
+ * ML99_uncomma(ML99_QUOTE(v(1), v(2), v(3)))
+ * @endcode
+ */
+#define ML99_uncomma(...) ML99_call(ML99_uncomma, __VA_ARGS__)
+
+/**
+ * Turns @p f into a Metalang99-compliant metafunction with the arity of 1, which can be then called
+ * by #ML99_appl.
+ *
+ * @p f can be any C function or function-like macro.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ * #include <metalang99/variadics.h>
+ *
+ * #define F(x) @x
+ *
+ * // @1 @2 @3
+ * ML99_variadicsForEach(ML99_reify(v(F)), v(1, 2, 3))
+ * @endcode
+ *
+ * Without #ML99_reify, you would need to write some additional boilerplate:
+ *
+ * @code
+ * #define F_IMPL(x) v(@x)
+ * #define F_ARITY 1
+ * @endcode
+ */
+#define ML99_reify(f) ML99_call(ML99_reify, f)
+
+/**
+ * Indicates not yet implemented functionality of the macro @p f.
+ *
+ * #ML99_todo is the same as #ML99_unimplemented except that the former conveys an intent that the
+ * functionality is to be implemented later but #ML99_unimplemented makes no such claims.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * // A not-yet implemented error.
+ * ML99_todo(v(F))
+ * @endcode
+ *
+ * @see [Rust's std::todo\!](https://doc.rust-lang.org/core/macro.todo.html) (thanks for the idea!)
+ */
+#define ML99_todo(f) ML99_call(ML99_todo, f)
+
+/**
+ * The same as #ML99_todo but emits a caller-supplied message.
+ *
+ * @p message must be a string literal.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * // A not-yet-implemented error.
+ * ML99_todoWithMsg(v(F), v("your message"))
+ * @endcode
+ */
+#define ML99_todoWithMsg(f, message) ML99_call(ML99_todoWithMsg, f, message)
+
+/**
+ * Indicates unimplemented functionality of the macro @p f.
+ *
+ * #ML99_unimplemented is the same as #ML99_todo except that the latter conveys an intent that the
+ * functionality is to be implemented later but #ML99_unimplemented makes no such claims.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * // A not-implemented error.
+ * ML99_unimplemented(v(F))
+ * @endcode
+ *
+ * @see [Rust's std::unimplemented\!](https://doc.rust-lang.org/core/macro.unimplemented.html)
+ * (thanks for the idea!)
+ */
+#define ML99_unimplemented(f) ML99_call(ML99_unimplemented, f)
+
+/**
+ * The same as #ML99_unimplemented but emits a caller-supplied message.
+ *
+ * @p message must be a string literal.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * // A not-implemented error.
+ * ML99_unimplementedWithMsg(v(F), v("your message"))
+ * @endcode
+ */
+#define ML99_unimplementedWithMsg(f, message) ML99_call(ML99_unimplementedWithMsg, f, message)
+
+#ifdef __COUNTER__
+
+/**
+ * Generates a unique identifier @p id in the namespace @p prefix.
+ *
+ * Let `FOO` be the name of an enclosing macro. Then `FOO_` must be specified for @p prefix, and @p
+ * id should be given any meaningful name (this makes debugging easier).
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * #define FOO(...) FOO_NAMED(ML99_GEN_SYM(FOO_, x), __VA_ARGS__)
+ * #define FOO_NAMED(x_sym, ...) \
+ * do { int x_sym = 5; __VA_ARGS__ } while (0)
+ *
+ * // `x` here will not conflict with the `x` inside `FOO`.
+ * FOO({
+ * int x = 7;
+ * printf("x is %d\n", x); // x is 7
+ * });
+ * @endcode
+ *
+ * @note Two identical calls to #ML99_GEN_SYM will yield different identifiers, therefore, to refer
+ * to the result later, you must save it in an auxiliary macro's parameter, as shown in the example
+ * above.
+ * @note #ML99_GEN_SYM is defined only if `__COUNTER__` is defined, which must be a macro yielding
+ * integral literals starting from 0 incremented by 1 each time it is called. Currently, it is
+ * supported at least by Clang, GCC, TCC, and MSVC.
+ * @see https://en.wikipedia.org/wiki/Hygienic_macro
+ */
+#define ML99_GEN_SYM(prefix, id) ML99_CAT4(prefix, id, _, __COUNTER__)
+
+#endif // __COUNTER__
+
+/**
+ * Forces a caller to put a trailing semicolon.
+ *
+ * It is useful when defining macros, to make them formatted as complete statements.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * #define MY_MACRO(fn_name, val_ty, val) \
+ * inline static val_ty fn_name(void) { return val; } \
+ * ML99_TRAILING_SEMICOLON()
+ *
+ * // Defines a function that always returns 0.
+ * MY_MACRO(zero, int, 0);
+ * @endcode
+ *
+ * @note #ML99_TRAILING_SEMICOLON is to be used outside of functions: unlike the `do { ... } while
+ * (0)` idiom, this macro expands to a C declaration.
+ */
+#define ML99_TRAILING_SEMICOLON(...) struct ml99_priv_trailing_semicolon
+
+/**
+ * Concatenates @p a with @p b as-is, without expanding them.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * // This macro will not be expanded.
+ * #define ABC 7
+ *
+ * // ABC123
+ * ML99_CAT_PRIMITIVE(ABC, 123)
+ * @endcode
+ */
+#define ML99_CAT_PRIMITIVE(a, b) a##b
+
+/**
+ * The same as #ML99_CAT_PRIMITIVE but deals with 3 parameters.
+ */
+#define ML99_CAT3_PRIMITIVE(a, b, c) a##b##c
+
+/**
+ * The same as #ML99_CAT_PRIMITIVE but deals with 4 parameters.
+ */
+#define ML99_CAT4_PRIMITIVE(a, b, c, d) a##b##c##d
+
+/**
+ * Stringifies @p x as-is, without expanding it.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/util.h>
+ *
+ * // This macro will not be expanded.
+ * #define ABC 7
+ *
+ * // "ABC"
+ * ML99_STRINGIFY_PRIMITIVE(ABC)
+ * @endcode
+ */
+#define ML99_STRINGIFY_PRIMITIVE(...) #__VA_ARGS__
+
+/**
+ * Expands to an opening parenthesis (`(`).
+ *
+ * This is helpful when you want to delay macro arguments passing: just type `BAR ML99_LPAREN()
+ * initial args...` at the end of some macro `FOO` and complete the invocation of `BAR` with
+ * `the rest of args...)` in future.
+ *
+ * This macro consumes all its arguments.
+ *
+ * @deprecated This macro results in code that is difficult to reason about.
+ */
+#define ML99_LPAREN(...) (
+
+/**
+ * The same as #ML99_LPAREN but emits a closing parenthesis.
+ *
+ * @deprecated For the same reason as #ML99_LPAREN.
+ */
+#define ML99_RPAREN(...) )
+
+/**
+ * Expands to a single comma, consuming all arguments.
+ */
+#define ML99_COMMA(...) ,
+
+/**
+ * If you are compiling on GCC, this macro expands to `_Pragma(str)`, otherwise to emptiness.
+ */
+#define ML99_GCC_PRAGMA(str) ML99_PRIV_GCC_PRAGMA(str)
+
+/**
+ * The same as #ML99_GCC_PRAGMA but for Clang.
+ */
+#define ML99_CLANG_PRAGMA(str) ML99_PRIV_CLANG_PRAGMA(str)
+
+#define ML99_CAT(a, b) ML99_CAT_PRIMITIVE(a, b)
+#define ML99_CAT3(a, b, c) ML99_CAT3_PRIMITIVE(a, b, c)
+#define ML99_CAT4(a, b, c, d) ML99_CAT4_PRIMITIVE(a, b, c, d)
+#define ML99_STRINGIFY(...) ML99_STRINGIFY_PRIMITIVE(__VA_ARGS__)
+#define ML99_EMPTY(...)
+#define ML99_ID(...) __VA_ARGS__
+
+#ifndef DOXYGEN_IGNORE
+
+#define ML99_catEval_IMPL(a, b) a##b
+#define ML99_cat_IMPL(a, b) v(a##b)
+#define ML99_cat3_IMPL(a, b, c) v(a##b##c)
+#define ML99_cat4_IMPL(a, b, c, d) v(a##b##c##d)
+#define ML99_stringify_IMPL(...) v(ML99_STRINGIFY(__VA_ARGS__))
+#define ML99_empty_IMPL(...) v(ML99_EMPTY())
+#define ML99_id_IMPL(...) v(ML99_ID(__VA_ARGS__))
+#define ML99_const_IMPL(x, _a) v(x)
+#define ML99_flip_IMPL(f) ML99_appl_IMPL(ML99_PRIV_flip, f)
+#define ML99_PRIV_flip_IMPL(f, a, b) ML99_appl2_IMPL(f, b, a)
+#define ML99_uncomma_IMPL(...) __VA_ARGS__
+
+#define ML99_reify_IMPL(f) ML99_appl_IMPL(ML99_PRIV_reify, f)
+#define ML99_PRIV_reify_IMPL(f, ...) v(f(__VA_ARGS__))
+
+// clang-format off
+#define ML99_todo_IMPL(f) ML99_fatal(f, not yet implemented)
+#define ML99_todoWithMsg_IMPL(f, message) ML99_fatal(f, not yet implemented: message)
+
+#define ML99_unimplemented_IMPL(f) ML99_fatal(f, not implemented)
+#define ML99_unimplementedWithMsg_IMPL(f, message) ML99_fatal(f, not implemented: message)
+// clang-format on
+
+#if defined(__GNUC__) && !defined(__clang__)
+#define ML99_PRIV_GCC_PRAGMA(str) _Pragma(str)
+#else
+#define ML99_PRIV_GCC_PRAGMA(str)
+#endif
+
+#if defined(__clang__)
+#define ML99_PRIV_CLANG_PRAGMA(str) _Pragma(str)
+#else
+#define ML99_PRIV_CLANG_PRAGMA(str)
+#endif
+
+// Arity specifiers {
+
+#define ML99_catEval_ARITY 2
+#define ML99_cat_ARITY 2
+#define ML99_cat3_ARITY 3
+#define ML99_cat4_ARITY 4
+#define ML99_stringify_ARITY 1
+#define ML99_empty_ARITY 1
+#define ML99_id_ARITY 1
+#define ML99_const_ARITY 2
+#define ML99_flip_ARITY 1
+#define ML99_uncomma_ARITY 1
+#define ML99_reify_ARITY 1
+#define ML99_todo_ARITY 1
+#define ML99_todoWithMsg_ARITY 2
+#define ML99_unimplemented_ARITY 1
+#define ML99_unimplementedWithMsg_ARITY 2
+
+#define ML99_PRIV_flip_ARITY 3
+#define ML99_PRIV_reify_ARITY 2
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_UTIL_H
diff --git a/test/external/metalang99/include/metalang99/variadics.h b/test/external/metalang99/include/metalang99/variadics.h
new file mode 100644
index 0000000..59b52c4
--- /dev/null
+++ b/test/external/metalang99/include/metalang99/variadics.h
@@ -0,0 +1,274 @@
+/**
+ * @file
+ * Variadic arguments: `x, y, z`.
+ *
+ * @note Variadics are more time and space-efficient than lists, but export less functionality; if a
+ * needed function is missed, invoking #ML99_list and then manipulating with the resulting Cons-list
+ * might be helpful.
+ */
+
+#ifndef ML99_VARIADICS_H
+#define ML99_VARIADICS_H
+
+#include <metalang99/nat/inc.h>
+#include <metalang99/priv/util.h>
+
+#include <metalang99/lang.h>
+
+/**
+ * Computes a count of its arguments.
+ *
+ * At most 63 arguments are acceptable.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/variadics.h>
+ *
+ * // 3
+ * ML99_variadicsCount(v(~, ~, ~))
+ *
+ * // 1
+ * ML99_variadicsCount()
+ * @endcode
+ */
+#define ML99_variadicsCount(...) ML99_call(ML99_variadicsCount, __VA_ARGS__)
+
+/**
+ * Tells if it received only one argument or not.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/variadics.h>
+ *
+ * // 1
+ * ML99_variadicsIsSingle(v(~))
+ *
+ * // 0
+ * ML99_variadicsIsSingle(v(~, ~, ~))
+ * @endcode
+ */
+#define ML99_variadicsIsSingle(...) ML99_call(ML99_variadicsIsSingle, __VA_ARGS__)
+
+/**
+ * Expands to a metafunction extracting the @p i -indexed argument.
+ *
+ * @p i can range from 0 to 7, inclusively.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/variadics.h>
+ *
+ * // 2
+ * ML99_variadicsGet(1)(v(1, 2, 3))
+ * @endcode
+ */
+#define ML99_variadicsGet(i) ML99_PRIV_CAT(ML99_PRIV_variadicsGet_, i)
+
+/**
+ * Extracts the tail of its arguments.
+ *
+ * At least two arguments must be specified.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/variadics.h>
+ *
+ * // 2, 3
+ * ML99_variadicsTail(v(1, 2, 3))
+ * @endcode
+ */
+#define ML99_variadicsTail(...) ML99_call(ML99_variadicsTail, __VA_ARGS__)
+
+/**
+ * Applies @p f to each argument.
+ *
+ * The result is `ML99_appl(f, x1) ... ML99_appl(f, xN)`.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/variadics.h>
+ *
+ * #define F_IMPL(x) v(@x)
+ * #define F_ARITY 1
+ *
+ * // @x @y @z
+ * ML99_variadicsForEach(v(F), v(x, y, z))
+ * @endcode
+ */
+#define ML99_variadicsForEach(f, ...) ML99_call(ML99_variadicsForEach, f, __VA_ARGS__)
+
+/**
+ * Applies @p f to each argument with an index.
+ *
+ * The result is `ML99_appl2(f, x1, 0) ... ML99_appl2(f, xN, N - 1)`.
+ *
+ * @code
+ * #include <metalang99/variadics.h>
+ *
+ * #define F_IMPL(x, i) v(@x##i)
+ * #define F_ARITY 2
+ *
+ * // @x0 @y1 @z2
+ * ML99_variadicsForEachI(v(F), v(x, y, z))
+ * @endcode
+ */
+#define ML99_variadicsForEachI(f, ...) ML99_call(ML99_variadicsForEachI, f, __VA_ARGS__)
+
+/**
+ * Overloads @p f on a number of arguments.
+ *
+ * This function counts the number of provided arguments, appends it to @p f and calls the resulting
+ * macro identifier with provided arguments.
+ *
+ * At most 63 variadic arguments are acceptable.
+ *
+ * # Examples
+ *
+ * @code
+ * #include <metalang99/variadics.h>
+ *
+ * #define X(...) ML99_OVERLOAD(X_, __VA_ARGS__)
+ * #define X_1(a) Billie & a
+ * #define X_2(a, b) Jean & a & b
+ *
+ * // Billie & 4
+ * X(4)
+ *
+ * // Jean & 5 & 6
+ * X(5, 6)
+ * @endcode
+ *
+ * @note @p f need not be postfixed with `_IMPL`. It is literally invoked as `ML99_CAT(f,
+ * ML99_VARIADICS_COUNT(...))(...)`.
+ */
+#define ML99_OVERLOAD(f, ...) ML99_PRIV_CAT(f, ML99_PRIV_VARIADICS_COUNT(__VA_ARGS__))(__VA_ARGS__)
+
+#define ML99_VARIADICS_COUNT(...) ML99_PRIV_VARIADICS_COUNT(__VA_ARGS__)
+#define ML99_VARIADICS_IS_SINGLE(...) ML99_PRIV_NOT(ML99_PRIV_CONTAINS_COMMA(__VA_ARGS__))
+#define ML99_VARIADICS_GET(i) ML99_PRIV_CAT(ML99_PRIV_VARIADICS_GET_, i)
+#define ML99_VARIADICS_TAIL(...) ML99_PRIV_TAIL(__VA_ARGS__)
+
+#ifndef DOXYGEN_IGNORE
+
+#define ML99_variadicsCount_IMPL(...) v(ML99_VARIADICS_COUNT(__VA_ARGS__))
+#define ML99_variadicsIsSingle_IMPL(...) v(ML99_VARIADICS_IS_SINGLE(__VA_ARGS__))
+
+#define ML99_PRIV_variadicsGet_0(...) ML99_call(ML99_PRIV_variadicsGet_0, __VA_ARGS__)
+#define ML99_PRIV_variadicsGet_1(...) ML99_call(ML99_PRIV_variadicsGet_1, __VA_ARGS__)
+#define ML99_PRIV_variadicsGet_2(...) ML99_call(ML99_PRIV_variadicsGet_2, __VA_ARGS__)
+#define ML99_PRIV_variadicsGet_3(...) ML99_call(ML99_PRIV_variadicsGet_3, __VA_ARGS__)
+#define ML99_PRIV_variadicsGet_4(...) ML99_call(ML99_PRIV_variadicsGet_4, __VA_ARGS__)
+#define ML99_PRIV_variadicsGet_5(...) ML99_call(ML99_PRIV_variadicsGet_5, __VA_ARGS__)
+#define ML99_PRIV_variadicsGet_6(...) ML99_call(ML99_PRIV_variadicsGet_6, __VA_ARGS__)
+#define ML99_PRIV_variadicsGet_7(...) ML99_call(ML99_PRIV_variadicsGet_7, __VA_ARGS__)
+
+#define ML99_PRIV_variadicsGet_0_IMPL(...) v(ML99_VARIADICS_GET(0)(__VA_ARGS__))
+#define ML99_PRIV_variadicsGet_1_IMPL(...) v(ML99_VARIADICS_GET(1)(__VA_ARGS__))
+#define ML99_PRIV_variadicsGet_2_IMPL(...) v(ML99_VARIADICS_GET(2)(__VA_ARGS__))
+#define ML99_PRIV_variadicsGet_3_IMPL(...) v(ML99_VARIADICS_GET(3)(__VA_ARGS__))
+#define ML99_PRIV_variadicsGet_4_IMPL(...) v(ML99_VARIADICS_GET(4)(__VA_ARGS__))
+#define ML99_PRIV_variadicsGet_5_IMPL(...) v(ML99_VARIADICS_GET(5)(__VA_ARGS__))
+#define ML99_PRIV_variadicsGet_6_IMPL(...) v(ML99_VARIADICS_GET(6)(__VA_ARGS__))
+#define ML99_PRIV_variadicsGet_7_IMPL(...) v(ML99_VARIADICS_GET(7)(__VA_ARGS__))
+
+#define ML99_PRIV_VARIADICS_GET_0(...) ML99_PRIV_VARIADICS_GET_AUX_0(__VA_ARGS__, ~)
+#define ML99_PRIV_VARIADICS_GET_1(...) ML99_PRIV_VARIADICS_GET_AUX_1(__VA_ARGS__, ~)
+#define ML99_PRIV_VARIADICS_GET_2(...) ML99_PRIV_VARIADICS_GET_AUX_2(__VA_ARGS__, ~)
+#define ML99_PRIV_VARIADICS_GET_3(...) ML99_PRIV_VARIADICS_GET_AUX_3(__VA_ARGS__, ~)
+#define ML99_PRIV_VARIADICS_GET_4(...) ML99_PRIV_VARIADICS_GET_AUX_4(__VA_ARGS__, ~)
+#define ML99_PRIV_VARIADICS_GET_5(...) ML99_PRIV_VARIADICS_GET_AUX_5(__VA_ARGS__, ~)
+#define ML99_PRIV_VARIADICS_GET_6(...) ML99_PRIV_VARIADICS_GET_AUX_6(__VA_ARGS__, ~)
+#define ML99_PRIV_VARIADICS_GET_7(...) ML99_PRIV_VARIADICS_GET_AUX_7(__VA_ARGS__, ~)
+
+#define ML99_PRIV_VARIADICS_GET_AUX_0(a, ...) a
+#define ML99_PRIV_VARIADICS_GET_AUX_1(_a, b, ...) b
+#define ML99_PRIV_VARIADICS_GET_AUX_2(_a, _b, c, ...) c
+#define ML99_PRIV_VARIADICS_GET_AUX_3(_a, _b, _c, d, ...) d
+#define ML99_PRIV_VARIADICS_GET_AUX_4(_a, _b, _c, _d, e, ...) e
+#define ML99_PRIV_VARIADICS_GET_AUX_5(_a, _b, _c, _d, _e, f, ...) f
+#define ML99_PRIV_VARIADICS_GET_AUX_6(_a, _b, _c, _d, _e, _f, g, ...) g
+#define ML99_PRIV_VARIADICS_GET_AUX_7(_a, _b, _c, _d, _e, _f, _g, h, ...) h
+
+#define ML99_variadicsTail_IMPL(...) v(ML99_VARIADICS_TAIL(__VA_ARGS__))
+
+// ML99_variadicsForEach_IMPL {
+
+#define ML99_variadicsForEach_IMPL(f, ...) \
+ ML99_PRIV_CAT(ML99_PRIV_variadicsForEach_, ML99_VARIADICS_IS_SINGLE(__VA_ARGS__)) \
+ (f, __VA_ARGS__)
+#define ML99_PRIV_variadicsForEach_1(f, x) ML99_appl_IMPL(f, x)
+#define ML99_PRIV_variadicsForEach_0(f, x, ...) \
+ ML99_TERMS(ML99_appl_IMPL(f, x), ML99_callUneval(ML99_variadicsForEach, f, __VA_ARGS__))
+// } (ML99_variadicsForEach_IMPL)
+
+// ML99_variadicsForEachI_IMPL {
+
+#define ML99_variadicsForEachI_IMPL(f, ...) ML99_PRIV_variadicsForEachIAux_IMPL(f, 0, __VA_ARGS__)
+
+#define ML99_PRIV_variadicsForEachIAux_IMPL(f, i, ...) \
+ ML99_PRIV_CAT(ML99_PRIV_variadicsForEachI_, ML99_VARIADICS_IS_SINGLE(__VA_ARGS__)) \
+ (f, i, __VA_ARGS__)
+
+#define ML99_PRIV_variadicsForEachI_1(f, i, x) ML99_appl2_IMPL(f, x, i)
+#define ML99_PRIV_variadicsForEachI_0(f, i, x, ...) \
+ ML99_TERMS( \
+ ML99_appl2_IMPL(f, x, i), \
+ ML99_callUneval(ML99_PRIV_variadicsForEachIAux, f, ML99_PRIV_INC(i), __VA_ARGS__))
+// } (ML99_variadicsForEachI_IMPL)
+
+/*
+ * The StackOverflow solution: <https://stackoverflow.com/a/2124385/13166656>.
+ *
+ * This macro supports at most 63 arguments because C99 allows implementations to handle only 127
+ * parameters/arguments per macro definition/invocation (C99 | 5.2.4 Environmental limits), and
+ * `ML99_PRIV_VARIADICS_COUNT_AUX` already accepts 64 arguments.
+ */
+// clang-format off
+#define ML99_PRIV_VARIADICS_COUNT(...) \
+ ML99_PRIV_VARIADICS_COUNT_AUX( \
+ __VA_ARGS__, \
+ 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, \
+ 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, \
+ 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, \
+ 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, \
+ 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, \
+ 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, \
+ 3, 2, 1, ~)
+
+#define ML99_PRIV_VARIADICS_COUNT_AUX( \
+ _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
+ _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
+ _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
+ _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
+ _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
+ _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
+ _61, _62, _63, x, ...) \
+ x
+// clang-format on
+
+// Arity specifiers {
+
+#define ML99_variadicsCount_ARITY 1
+#define ML99_variadicsIsSingle_ARITY 1
+#define ML99_variadicsTail_ARITY 1
+#define ML99_variadicsForEach_ARITY 2
+#define ML99_variadicsForEachI_ARITY 2
+
+#define ML99_PRIV_variadicsGet_0_ARITY 1
+#define ML99_PRIV_variadicsGet_1_ARITY 1
+#define ML99_PRIV_variadicsGet_2_ARITY 1
+#define ML99_PRIV_variadicsGet_3_ARITY 1
+#define ML99_PRIV_variadicsGet_4_ARITY 1
+#define ML99_PRIV_variadicsGet_5_ARITY 1
+#define ML99_PRIV_variadicsGet_6_ARITY 1
+#define ML99_PRIV_variadicsGet_7_ARITY 1
+// } (Arity specifiers)
+
+#endif // DOXYGEN_IGNORE
+
+#endif // ML99_VARIADICS_H
diff --git a/test/external/metalang99/optimization_tips.md b/test/external/metalang99/optimization_tips.md
new file mode 100644
index 0000000..261cbe8
--- /dev/null
+++ b/test/external/metalang99/optimization_tips.md
@@ -0,0 +1,24 @@
+# Optimization tips
+
+_This document describes a few optimization tips when using Metalang99._
+
+Generally speaking, the fewer reduction steps you perform, the faster you become. A reduction step is a concept defined formally by the [specification]. Here is its informal (and imprecise) description:
+
+ - Every `v(...)` is a reduction step.
+ - Every `ML99_call(op, ...)` induces as many reduction steps as required to evaluate `op` and `...`.
+
+To perform fewer reduction steps, you can:
+
+ - use `ML99_callUneval`,
+ - use plain macros (e.g., `ML99_CAT` instead of `ML99_cat`),
+ - use optimized versions (e.g., `ML99_listMapInPlace`),
+ - use tuples/variadics instead of lists,
+ - call a macro as `<X>_IMPL(...)`, if all the arguments are already evaluated.
+
+<details>
+ <summary>Be careful with the last trick!</summary>
+
+I strongly recommend to use the last trick only if `X` is defined locally to a caller so that you can control the correctness of expansion. For example, `X` can become painted blue, it can emit unexpected commas, the `#` and `##` operators can block expansion of parameters, and a plenty of other nasty things.
+</details>
+
+[specification]: spec/spec.pdf
diff --git a/test/external/metalang99/scripts/bench.sh b/test/external/metalang99/scripts/bench.sh
new file mode 100755
index 0000000..4b26aba
--- /dev/null
+++ b/test/external/metalang99/scripts/bench.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+bench() {
+ echo $1
+ time gcc bench/$1 -ftrack-macro-expansion=0 -Iinclude -E -P >/dev/null
+ echo ""
+}
+
+bench "compare_25_items.c"
+bench "list_of_63_items.c"
+bench "100_v.c"
+bench "100_call.c"
+bench "many_call_in_arg_pos.c"
+bench "filter_map.c"
diff --git a/test/external/metalang99/scripts/check-arities.py b/test/external/metalang99/scripts/check-arities.py
new file mode 100644
index 0000000..c745a0b
--- /dev/null
+++ b/test/external/metalang99/scripts/check-arities.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+
+# Make sure that arity specifiers of public metafunctions are consistent with their signatures.
+
+import os
+import re
+import xml.etree.ElementTree as ET
+import subprocess
+
+subprocess.call("doxygen > /dev/null 2> /dev/null", shell=True)
+
+
+def check_module(module):
+ print(f"Checking {module}.h ...")
+
+ tree = ET.parse(f"xml/{module}_8h.xml")
+ root = tree.getroot()
+
+ arity_specifiers = gather_arity_specifiers(root)
+
+ for metafunction_name, arity in gather_metafunctions(root).items():
+ expected_arity = int(arity)
+ actual_arity = int(arity_specifiers[metafunction_name])
+ assert expected_arity == actual_arity
+
+
+def gather_metafunctions(root):
+ metafunctions = {}
+
+ for definition in root.findall("./compounddef/sectiondef/memberdef"):
+ macro_name = definition.find("name").text
+ is_metalang99_compliant = re.search("ML99_[a-z]", macro_name)
+
+ exceptions = {
+ "ML99_call", "ML99_callUneval", "ML99_fatal", "ML99_abort", "ML99_tupleGet", "ML99_variadicsGet", "ML99_seqGet"}
+ is_exceptional = macro_name in exceptions
+
+ if (is_metalang99_compliant and not is_exceptional):
+ arity = len(list(definition.findall("param")))
+ metafunctions[macro_name] = arity
+
+ return metafunctions
+
+
+def gather_arity_specifiers(root):
+ arity_specifiers = {}
+
+ for definition in root.findall("./compounddef/programlisting/codeline/highlight[@class='preprocessor']"):
+ m = re.match(r"#define(\w+)_ARITY(\d)", "".join(definition.itertext()))
+ if m is not None:
+ metafunction_name = m.groups()[0]
+ arity = m.groups()[1]
+ arity_specifiers[metafunction_name] = arity
+
+ return arity_specifiers
+
+
+for path in os.listdir("include/metalang99"):
+ if path.endswith(".h"):
+ module = path.replace(".h", "")
+ check_module(module)
diff --git a/test/external/metalang99/scripts/check-fmt.sh b/test/external/metalang99/scripts/check-fmt.sh
new file mode 100755
index 0000000..a3342c6
--- /dev/null
+++ b/test/external/metalang99/scripts/check-fmt.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+./run-clang-format/run-clang-format.py \
+ --exclude examples/build \
+ --exclude tests/build \
+ -r include tests examples bench
diff --git a/test/external/metalang99/scripts/docs.sh b/test/external/metalang99/scripts/docs.sh
new file mode 100755
index 0000000..957faa2
--- /dev/null
+++ b/test/external/metalang99/scripts/docs.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+sphinx-build -b html docs _build/html
diff --git a/test/external/metalang99/scripts/fmt.sh b/test/external/metalang99/scripts/fmt.sh
new file mode 100755
index 0000000..5f550b6
--- /dev/null
+++ b/test/external/metalang99/scripts/fmt.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+find include tests examples bench \
+ \( -path examples/build -o -path tests/build \) -prune -false -o \
+ \( -iname "*.h" \) -or \( -iname "*.c" \) | xargs clang-format -i
diff --git a/test/external/metalang99/scripts/open-docs.sh b/test/external/metalang99/scripts/open-docs.sh
new file mode 100755
index 0000000..ae3e4b5
--- /dev/null
+++ b/test/external/metalang99/scripts/open-docs.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+xdg-open _build/html/index.html
diff --git a/test/external/metalang99/scripts/open-spec.sh b/test/external/metalang99/scripts/open-spec.sh
new file mode 100755
index 0000000..921e122
--- /dev/null
+++ b/test/external/metalang99/scripts/open-spec.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+xdg-open spec/spec.pdf
diff --git a/test/external/metalang99/scripts/spec.sh b/test/external/metalang99/scripts/spec.sh
new file mode 100755
index 0000000..8da58e4
--- /dev/null
+++ b/test/external/metalang99/scripts/spec.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -e
+
+cd spec
+
+pdflatex -shell-escape spec.tex
+biber spec
+pdflatex -shell-escape spec.tex
+pdflatex -shell-escape spec.tex
+
+cd ..
diff --git a/test/external/metalang99/scripts/test-all.sh b/test/external/metalang99/scripts/test-all.sh
new file mode 100755
index 0000000..c4adc73
--- /dev/null
+++ b/test/external/metalang99/scripts/test-all.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+
+./scripts/test.sh
+./scripts/test-examples.sh
diff --git a/test/external/metalang99/scripts/test-examples.sh b/test/external/metalang99/scripts/test-examples.sh
new file mode 100755
index 0000000..fb0db8a
--- /dev/null
+++ b/test/external/metalang99/scripts/test-examples.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set -e
+
+mkdir -p examples/build
+cd examples/build
+cmake ..
+cmake --build .
diff --git a/test/external/metalang99/scripts/test.sh b/test/external/metalang99/scripts/test.sh
new file mode 100755
index 0000000..ced5f53
--- /dev/null
+++ b/test/external/metalang99/scripts/test.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+mkdir -p tests/build
+cd tests/build
+cmake ..
+cmake --build .
+
+if [[ "$OSTYPE" == "linux-gnu" ]]; then
+ echo "Testing ./gen ..."
+ ./gen
+
+ echo "Testing ./stmt ..."
+ ./stmt
+fi
diff --git a/test/external/metalang99/spec/.gitignore b/test/external/metalang99/spec/.gitignore
new file mode 100644
index 0000000..859f705
--- /dev/null
+++ b/test/external/metalang99/spec/.gitignore
@@ -0,0 +1,276 @@
+## Core latex/pdflatex auxiliary files:
+*.aux
+*.lof
+*.log
+*.lot
+*.fls
+*.out
+*.toc
+*.fmt
+*.fot
+*.cb
+*.cb2
+.*.lb
+
+## Intermediate documents:
+*.dvi
+*.xdv
+*-converted-to.*
+# these rules might exclude image files for figures etc.
+# *.ps
+# *.eps
+# *.pdf
+
+## Generated if empty string is given at "Please type another file name for output:"
+.pdf
+
+## Bibliography auxiliary files (bibtex/biblatex/biber):
+*.bbl
+*.bcf
+*.blg
+*-blx.aux
+*-blx.bib
+*.run.xml
+
+## Build tool auxiliary files:
+*.fdb_latexmk
+*.synctex
+*.synctex(busy)
+*.synctex.gz
+*.synctex.gz(busy)
+*.pdfsync
+
+## Build tool directories for auxiliary files
+# latexrun
+latex.out/
+
+## Auxiliary and intermediate files from other packages:
+# algorithms
+*.alg
+*.loa
+
+# achemso
+acs-*.bib
+
+# amsthm
+*.thm
+
+# beamer
+*.nav
+*.pre
+*.snm
+*.vrb
+
+# changes
+*.soc
+
+# comment
+*.cut
+
+# cprotect
+*.cpt
+
+# elsarticle (documentclass of Elsevier journals)
+*.spl
+
+# endnotes
+*.ent
+
+# fixme
+*.lox
+
+# feynmf/feynmp
+*.mf
+*.mp
+*.t[1-9]
+*.t[1-9][0-9]
+*.tfm
+
+#(r)(e)ledmac/(r)(e)ledpar
+*.end
+*.?end
+*.[1-9]
+*.[1-9][0-9]
+*.[1-9][0-9][0-9]
+*.[1-9]R
+*.[1-9][0-9]R
+*.[1-9][0-9][0-9]R
+*.eledsec[1-9]
+*.eledsec[1-9]R
+*.eledsec[1-9][0-9]
+*.eledsec[1-9][0-9]R
+*.eledsec[1-9][0-9][0-9]
+*.eledsec[1-9][0-9][0-9]R
+
+# glossaries
+*.acn
+*.acr
+*.glg
+*.glo
+*.gls
+*.glsdefs
+*.lzo
+*.lzs
+
+# uncomment this for glossaries-extra (will ignore makeindex's style files!)
+# *.ist
+
+# gnuplottex
+*-gnuplottex-*
+
+# gregoriotex
+*.gaux
+*.gtex
+
+# htlatex
+*.4ct
+*.4tc
+*.idv
+*.lg
+*.trc
+*.xref
+
+# hyperref
+*.brf
+
+# knitr
+*-concordance.tex
+# TODO Comment the next line if you want to keep your tikz graphics files
+*.tikz
+*-tikzDictionary
+
+# listings
+*.lol
+
+# luatexja-ruby
+*.ltjruby
+
+# makeidx
+*.idx
+*.ilg
+*.ind
+
+# minitoc
+*.maf
+*.mlf
+*.mlt
+*.mtc[0-9]*
+*.slf[0-9]*
+*.slt[0-9]*
+*.stc[0-9]*
+
+# minted
+_minted*
+*.pyg
+
+# morewrites
+*.mw
+
+# nomencl
+*.nlg
+*.nlo
+*.nls
+
+# pax
+*.pax
+
+# pdfpcnotes
+*.pdfpc
+
+# sagetex
+*.sagetex.sage
+*.sagetex.py
+*.sagetex.scmd
+
+# scrwfile
+*.wrt
+
+# sympy
+*.sout
+*.sympy
+sympy-plots-for-*.tex/
+
+# pdfcomment
+*.upa
+*.upb
+
+# pythontex
+*.pytxcode
+pythontex-files-*/
+
+# tcolorbox
+*.listing
+
+# thmtools
+*.loe
+
+# TikZ & PGF
+*.dpth
+*.md5
+*.auxlock
+
+# todonotes
+*.tdo
+
+# vhistory
+*.hst
+*.ver
+
+# easy-todo
+*.lod
+
+# xcolor
+*.xcp
+
+# xmpincl
+*.xmpi
+
+# xindy
+*.xdy
+
+# xypic precompiled matrices and outlines
+*.xyc
+*.xyd
+
+# endfloat
+*.ttt
+*.fff
+
+# Latexian
+TSWLatexianTemp*
+
+## Editors:
+# WinEdt
+*.bak
+*.sav
+
+# Texpad
+.texpadtmp
+
+# LyX
+*.lyx~
+
+# Kile
+*.backup
+
+# gummi
+.*.swp
+
+# KBibTeX
+*~[0-9]*
+
+# TeXnicCenter
+*.tps
+
+# auto folder when using emacs and auctex
+./auto/*
+*.el
+
+# expex forward references with \gathertags
+*-tags.tex
+
+# standalone packages
+*.sta
+
+# Makeindex log files
+*.lpz
diff --git a/test/external/metalang99/spec/references.bib b/test/external/metalang99/spec/references.bib
new file mode 100644
index 0000000..adcb68a
--- /dev/null
+++ b/test/external/metalang99/spec/references.bib
@@ -0,0 +1,17 @@
+@online{Metalang99,
+ author = "hirrolot",
+ title = "Full-blown preprocessor metaprogramming",
+ url = "https://github.com/hirrolot/metalang99",
+}
+
+@online{ApplicativeEvaluationStrategy,
+ author = "Wikipedia",
+ title = "Applicative order",
+ url = "https://en.wikipedia.org/wiki/Evaluation_strategy#Applicative_order",
+}
+
+@online{Bluepainting,
+ author = "",
+ title = "C99 draft, section 6.10.3.4, paragraph 2 -- Rescanning and further replacement",
+ url = "http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf",
+}
diff --git a/test/external/metalang99/spec/spec.pdf b/test/external/metalang99/spec/spec.pdf
new file mode 100644
index 0000000..de1a062
--- /dev/null
+++ b/test/external/metalang99/spec/spec.pdf
Binary files differ
diff --git a/test/external/metalang99/spec/spec.tex b/test/external/metalang99/spec/spec.tex
new file mode 100644
index 0000000..99fb7e4
--- /dev/null
+++ b/test/external/metalang99/spec/spec.tex
@@ -0,0 +1,289 @@
+\documentclass[12pt]{article}
+
+\usepackage{hyperref}
+\usepackage{float}
+\usepackage{bussproofs}
+\usepackage{minted}
+\usepackage{amsmath}
+\usepackage{amssymb}
+\usepackage[standard,thmmarks]{ntheorem}
+\usepackage{biblatex}
+\usepackage{csquotes}
+\usepackage{mathtools}
+\usepackage{tabularx}
+\usepackage[english]{babel}
+
+\theoremstyle{break}
+\newtheorem{notation}{Notation}
+
+\addbibresource{references.bib}
+
+\floatstyle{boxed}
+\restylefloat{figure}
+\allowdisplaybreaks
+
+\begin{document}
+
+\title{Metalang99 Specification (v1.13.5)}
+\date{\today}
+\author{\texttt{hirrolot} \\ e-mail: \href{mailto:hirrolot@gmail.com}{hirrolot@gmail.com}}
+\maketitle
+
+\begin{abstract}
+This paper formally describes the syntax and semantics of metaprograms written in Metalang99,
+a metalanguage aimed at full-blown C99 preprocessor metaprogramming. For the motivation and
+a user-friendly overview, please see the official repository \cite{Metalang99}.
+\end{abstract}
+
+\tableofcontents
+
+\newpage
+
+\section{EBNF Grammar}
+
+\begin{figure}[H]
+ \caption{Grammar rules}
+
+\begin{minted}{bnf}
+<eval> ::= "ML99_EVAL(" <term-seq> ")" ;
+
+<term-seq> ::= <term> { "," <term> }* ;
+
+<term> ::=
+ "ML99_call(" <op> "," <term-seq> ")"
+ | "ML99_callUneval(" <ident> "," <pp-token-list> ")"
+ | "ML99_abort(" <term-seq> ")"
+ | "ML99_fatal(" <ident> "," <pp-token-list> ")"
+ | "v(" <pp-token-list> ")" ;
+
+<op> ::= <ident> | <term> ;
+\end{minted}
+
+\end{figure}
+
+Notes:
+
+\begin{itemize}
+ \item \texttt{<pp-token-list>} stands for a list of preprocessor tokens (e.g., \texttt{a 123, hello!}).
+ \item The grammar above describes metaprograms already expanded by the preprocessor,
+ except for \texttt{ML99\_EVAL}, \texttt{ML99\_call}, \texttt{ML99\_callUneval}, \\
+ \texttt{ML99\_abort}, \texttt{ML99\_fatal}, and \texttt{v}.
+ \item \texttt{ML99\_call} accepts \texttt{op} either as an identifier or as a term that
+ reduces to an identifier.
+ \item \texttt{ML99\_callUneval} accepts an operation strictly as an identifier.
+\end{itemize}
+
+The \texttt{ML99\_call} syntax hurts IDE support (no parameters documentation highlighting) and is also
+less natural. The workaround is to define a wrapper around an implementation macro like this:
+
+\begin{minted}{c}
+/// The documentation string.
+#define FOO(a, b, c) ML99_call(FOO, a, b, c)
+#define FOO_IMPL(a, b, c) // The implementation.
+\end{minted}
+
+Then \texttt{FOO} can be conveniently called as \texttt{FOO(v(1), v(2), v(3))}.
+
+\section{Notations}
+
+\begin{notation}[Sequence]
+ \begin{itemize}
+ \item $\overline{x} \coloneqq x_1 \ldots x_n$. Examples:
+ \begin{itemize}
+ \item Metalang99 terms: \texttt{v(abc), ML99\_call(FOO, v(123)), v(u 8 9)}
+ \item Preprocessor tokens: \texttt{abc 13 "hello" + -}
+ \end{itemize}
+ \item $()$ denotes the empty sequence.
+ \item Appending to a sequence:
+ \begin{itemize}
+ \item Appending an element: $S \ y \coloneqq x_1 \ldots x_n \ y$, where $S = x_1 \ldots x_n$
+ \item Appending a sequence: $S_1 \ S_2 \coloneqq x_1 \ldots x_n \ y_1 \ldots y_m$, where $S_1 = x_1 \ldots x_n$
+ and $S_2 = y_1 \ldots y_m$
+ \end{itemize}
+ \end{itemize}
+\end{notation}
+
+\begin{notation}[Reduction step]
+ $\to$ denotes a single step of reduction (computation, evaluation).
+\end{notation}
+
+\begin{notation}[Metavariables]
+ \ \\
+ \begin{tabular}{|c|c|}
+ \hline
+ \texttt{tok} & preprocessor token \\
+ \texttt{ident} & preprocessor identifier \\
+ \texttt{t} & Metalang99 term \\
+ \texttt{a} & Metalang99 term used as an argument \\
+ \hline
+ \end{tabular}
+\end{notation}
+
+\section{Reduction Semantics}
+
+We define a reduction semantics for Metalang99 \ref{ReductionSemantics}. The abstract
+machine executes configurations of the form $\langle K; F; A; C \rangle$:
+
+\begin{itemize}
+ \item $K$ is a continuation of the form $\langle K; F; A; C \rangle$, where
+ $C$ includes the $?$ sign denoting a result passed into the continuation.
+ For example, let $K$ be $\langle K'; (1, 2, 3); v(x), \ ? \rangle$,
+ then $K(v(y))$ is $\langle K'; (1, 2, 3); v(x), v(y) \rangle$. A special
+ continuation $halt$ terminates the abstract machine and substitutes itself
+ with a provided result. For example, when the abstract machine encounters
+ $halt(1 + 2)$, it will just stop and paste $1 + 2$.
+
+ \item $F$ is a left folder of the form $(acc, \overline{tok}) \to acc$. It is used
+ to flexibly append a newly evaluated term to an accumulator without extra reduction
+ steps. There are the only two folders:
+ \begin{itemize}
+ \item $fspace(acc, \overline{tok}) \coloneqq acc \ \overline{tok}$
+ \item $fcomma(acc, \overline{tok}) \coloneqq if (acc \ is \ ()) \ then \ \overline{tok} \ else \ acc \ "," \ \overline{tok}$
+ \end{itemize}
+
+ \item $A$ (accumulator) is a sequence of already computed results.
+
+ \item $C$ (control) is a sequence of terms upon which the abstract
+ machine is operating right now.
+\end{itemize}
+
+\begin{figure}
+ \caption{Reduction Semantics}
+
+ \begin{align*}
+ (v): & \ \langle K; F; A; \texttt{v}(\overline{tok}), \overline{t} \rangle \to
+ \langle K; F; F(A, \overline{tok}); \overline{t} \rangle \\
+ (op): & \ \langle K; F; A; \texttt{ML99\_call}(t, \overline{a}), \overline{t'} \rangle \to \langle \\
+ & \ \ \ \ \langle K; F; A; \texttt{ML99\_call}(?), \overline{t'} \rangle; \\
+ & \ \ \ \ fcomma; \\
+ & \ \ \ \ (); \\
+ & \ \ \ \ t, \overline{a} \rangle \\
+ (args): & \ \langle K; F; A; \texttt{ML99\_call}(ident, \overline{a}), \overline{t} \rangle \to \langle \\
+ & \ \ \ \ \langle \langle K; F; F(A, ?); \overline{t} \rangle; fspace; (); ident\texttt{\_IMPL}(?) \rangle; \\
+ & \ \ \ \ fcomma; \\
+ & \ \ \ \ (); \\
+ & \ \ \ \ \overline{a} \rangle \\
+ (callUneval): & \ \langle K; F; A; \texttt{ML99\_callUneval}(ident, \overline{tok}), \overline{t} \rangle \to \langle \\
+ & \ \ \ \ \langle K; F; F(A, ?); \overline{t} \rangle; \\
+ & \ \ \ \ fspace; \\
+ & \ \ \ \ (); \\
+ & \ \ \ \ ident\texttt{\_IMPL}(\overline{tok}) \rangle \\
+ (abort): & \ \langle K; F; A; \texttt{ML99\_abort}(\overline{t}), \overline{t'} \rangle \to \langle halt; fspace; (); \overline{t} \rangle \\
+ (fatal): & \ \langle K; F; A; \texttt{ML99\_fatal}(ident, \overline{tok}), \overline{t} \rangle \to halt(\ldots) \\
+ (end): & \ \langle K; F; A; () \rangle \to K(A) \\
+ (start): & \ \texttt{ML99\_call}(\overline{t}) \to \langle halt; fspace; (); \overline{t} \rangle
+ \end{align*}
+ \label{ReductionSemantics}
+\end{figure}
+
+Notes:
+
+\begin{itemize}
+ \item Metalang99 follows applicative evaluation strategy \cite{ApplicativeEvaluationStrategy}.
+
+ \item $(args)$ Metalang99 generates a usual C-style macro invocation with
+ fully evaluated arguments, which will be then expanded by the preprocessor, resulting
+ in yet another concrete sequence of Metalang99 terms to be evaluated by the computational
+ rules.
+ \item $(args)$ Metalang99 appends \texttt{\_IMPL} to every macro identifier called using
+ \texttt{ML99\_call} -- it makes easier to follow the convention that all implementations
+ of metafunctions must have the postfix \texttt{\_IMPL}.
+ \item $(callUneval)$ \texttt{ML99\_callUneval} is used when an operation and all
+ arguments are already evaluated. It is semantically the same as \\ \texttt{ML99\_call(ident, v(...))}
+ but performs one less reduction steps to benefit in performance.
+ \item $(fatal)$ The ellipsis means that an implementation is free to provide
+ diagnostics in any format.
+ \item $(fatal)$ interprets its variadic arguments without preprocessor expansion -- i.e.,
+ they are pasted as-is. This is intended because otherwise identifiers located in an
+ error message may stand for other macros that will be unintentionally expanded.
+ \item The number of reduction steps is finite and may vary from version to version. If
+ the limit is exceeded, Metalang99 will not be able to perform reduction of a given
+ metaprogram anymore.
+\end{itemize}
+
+\subsection{Examples}
+
+Take the following code:
+
+\begin{minted}{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)
+\end{minted}
+
+See how \texttt{ML99\_call(X, v(CALL\_X))} is evaluated:
+
+\begin{example}[Evaluation of terms]
+\begin{align*}
+ \texttt{ML99\_EVAL}(\texttt{ML99\_call}(X, \texttt{v}(\texttt{CALL\_X}))) & \ \underrightarrow{(start)} \\
+ \langle halt; fspace; (); \texttt{ML99\_call}(X, \texttt{v}(\texttt{CALL\_X})) \rangle & \ \underrightarrow{(args)} \\
+ \langle \langle halt; fspace; (); \texttt{X}(?) \rangle; fcomma; (); \texttt{v}(\texttt{CALL\_X}) \rangle & \ \underrightarrow{(v)} \\
+ \langle \langle halt; fspace; (); \texttt{X}(?) \rangle; fcomma; \texttt{CALL\_X}; () \rangle & \ \underrightarrow{(end)} \\
+ \langle halt; fspace; (); \texttt{ML99\_call}(\texttt{CALL\_X}, \texttt{v}(123)) \rangle & \ \underrightarrow{(args)} \\
+ \langle \langle halt; fspace; (); \texttt{CALL\_X}(?) \rangle; fcomma; (); \texttt{v}(123) \rangle & \ \underrightarrow{(v)} \\
+ \langle \langle halt; fspace; (); \texttt{CALL\_X}(?) \rangle; fcomma; 123; () \rangle & \ \underrightarrow{(end)} \\
+ \langle halt; fspace; (); \texttt{ML99\_call}(X, \texttt{v}(\texttt{ID})) \rangle & \ \underrightarrow{(args)} \\
+ \langle \langle halt; fspace; (); \texttt{X}(?) \rangle; fcomma; (); \texttt{v}(\texttt{ID}) \rangle & \ \underrightarrow{(v)} \\
+ \langle \langle halt; fspace; (); \texttt{X}(?) \rangle; fcomma; \texttt{ID}; \rangle & \ \underrightarrow{(end)} \\
+ \langle halt; fspace; (); \texttt{ML99\_call}(\texttt{ID}, \texttt{v}(123)) \rangle & \ \underrightarrow{(args)} \\
+ \langle \langle halt; fspace; (); \texttt{ID}(?) \rangle; fcomma; (); \texttt{v}(123) \rangle & \ \underrightarrow{(v)} \\
+ \langle \langle halt; fspace; (); \texttt{ID}(?) \rangle; fcomma; 123; () \rangle & \ \underrightarrow{(end)} \\
+ \langle halt; fspace; (); \texttt{v}(123) \rangle & \ \underrightarrow{(v)} \\
+ \langle halt; fspace; 123; () \rangle & \ \underrightarrow{(end)} \\
+ halt(123) &
+\end{align*}
+\end{example}
+
+The analogous version written in ordinary C looks like this:
+
+\begin{minted}{c}
+#define X(op) op(123)
+#define CALL_X(_123) X(ID)
+#define ID(x) x
+\end{minted}
+
+However, unlike the Metalang99 version above, \texttt{X(CALL\_X)} gets blocked \cite{Bluepainting} due to the
+second call to \texttt{X}. The trick is that Metalang99 performs evaluation step-by-step,
+unlike the preprocessor:
+
+\begin{itemize}
+ \item The Metalang99 version: \texttt{X(CALL\_X)} expands to \texttt{ML99\_call(\\ CALL\_X, v(123))}.
+ This expansion does not contain \texttt{X}, and therefore \texttt{X} is \textbf{not}
+ blocked by the preprocessor.
+
+ \item The ordinary version: \texttt{X(CALL\_X)} expands to \texttt{X(ID)}. This expansion
+ does contains \texttt{X}, and therefore \texttt{X} is blocked by the preprocessor.
+\end{itemize}
+
+\section{Properties}
+
+\subsection{Progress}
+
+\begin{proposition}[Progress]
+Either $\langle K; F; A; \overline{t} \rangle \to \langle K; F; A; \overline{t'} \rangle$ or \\
+$\langle K; F; A; \overline{t} \rangle \to halt(\overline{x})$.
+\end{proposition}
+
+\begin{proof}
+By inspection of \ref{ReductionSemantics}.
+\end{proof}
+
+\section{Caveats}
+
+\begin{itemize}
+\item Consider this scenario:
+ \begin{itemize}
+ \item You call \texttt{FOO(1, 2, 3)}
+ \item It gets expanded by the preprocessor (not by Metalang99)
+ \item Its expansion contains \texttt{FOO}
+ \end{itemize}
+Then \texttt{FOO} gets blocked \cite{Bluepainting} by the preprocessor, i.e. Metalang99 cannot handle ordinary
+macro recursion; you must use \texttt{ML99\_call} to be sure that recursive calls
+will behave as expected. I therefore recommend to use only primitive C-style macros, e.g.
+for performance reasons or because of you cannot express them in terms of Metalang99.
+\end{itemize}
+
+\emergencystretch=1em
+\printbibliography
+
+\end{document}
diff --git a/test/external/metalang99/tests/.gitignore b/test/external/metalang99/tests/.gitignore
new file mode 100644
index 0000000..567609b
--- /dev/null
+++ b/test/external/metalang99/tests/.gitignore
@@ -0,0 +1 @@
+build/
diff --git a/test/external/metalang99/tests/CMakeLists.txt b/test/external/metalang99/tests/CMakeLists.txt
new file mode 100644
index 0000000..95153b7
--- /dev/null
+++ b/test/external/metalang99/tests/CMakeLists.txt
@@ -0,0 +1,38 @@
+cmake_minimum_required(VERSION 3.16)
+project(test LANGUAGES C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ add_compile_options(-Wall -Wextra -pedantic -std=c99
+ -ftrack-macro-expansion=0)
+elseif(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ add_compile_options("-fmacro-backtrace-limit=1")
+elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
+ # Enable a standard-conforming C99/C11 preprocessor.
+ add_compile_options("/std:c11")
+elseif(CMAKE_C_COMPILER_ID STREQUAL "TinyCC")
+ add_compile_definitions(ML99_ALLOW_POOR_DIAGNOSTICS)
+endif()
+
+include_directories(../include)
+
+add_executable(metalang99 metalang99.c)
+add_executable(assert assert.c)
+add_executable(choice choice.c)
+add_executable(either either.c)
+add_executable(gen gen.c)
+add_executable(stmt stmt.c)
+add_executable(lang lang.c)
+add_executable(list list.c)
+add_executable(bool bool.c)
+add_executable(maybe maybe.c)
+add_executable(nat nat.c)
+add_executable(ident ident.c)
+add_executable(tuple tuple.c)
+add_executable(util util.c)
+add_executable(variadics variadics.c)
+add_executable(seq seq.c)
+add_executable(rec eval/rec.c)
+
+foreach(TARGET ${BUILDSYSTEM_TARGETS})
+ set_target_properties(TARGET PROPERTIES C_STANDARD 99 C_STANDARD_REQUIRED ON)
+endforeach()
diff --git a/test/external/metalang99/tests/assert.c b/test/external/metalang99/tests/assert.c
new file mode 100644
index 0000000..44033cb
--- /dev/null
+++ b/test/external/metalang99/tests/assert.c
@@ -0,0 +1,19 @@
+#include <metalang99/assert.h>
+
+// This is used to check that `1 == 1` is put into parentheses automatically.
+#define COND 1 == 1
+
+ML99_EVAL(ML99_assert(v(COND)));
+ML99_EVAL(ML99_assertEq(v(COND), v(COND)));
+
+ML99_ASSERT(v(COND));
+ML99_ASSERT_EQ(v(COND), v(COND));
+
+ML99_ASSERT_UNEVAL(COND);
+
+#undef COND
+
+ML99_ASSERT_EMPTY(v());
+ML99_ASSERT_EMPTY_UNEVAL();
+
+int main(void) {}
diff --git a/test/external/metalang99/tests/bool.c b/test/external/metalang99/tests/bool.c
new file mode 100644
index 0000000..e974920
--- /dev/null
+++ b/test/external/metalang99/tests/bool.c
@@ -0,0 +1,121 @@
+#include <metalang99/assert.h>
+#include <metalang99/bool.h>
+
+int main(void) {
+
+ // ML99_true, ML99_false
+ {
+ ML99_ASSERT_EQ(ML99_true(), v(1));
+ ML99_ASSERT_EQ(ML99_true(~, ~, ~), v(1));
+
+ ML99_ASSERT_EQ(ML99_false(), v(0));
+ ML99_ASSERT_EQ(ML99_false(~, ~, ~), v(0));
+ }
+
+ // ML99_not
+ {
+ ML99_ASSERT_EQ(ML99_not(v(0)), v(1));
+ ML99_ASSERT_EQ(ML99_not(v(1)), v(0));
+ }
+
+ // ML99_and
+ {
+ ML99_ASSERT_EQ(ML99_and(v(0), v(0)), v(0));
+ ML99_ASSERT_EQ(ML99_and(v(0), v(1)), v(0));
+ ML99_ASSERT_EQ(ML99_and(v(1), v(0)), v(0));
+ ML99_ASSERT_EQ(ML99_and(v(1), v(1)), v(1));
+ }
+
+ // ML99_or
+ {
+ ML99_ASSERT_EQ(ML99_or(v(0), v(0)), v(0));
+ ML99_ASSERT_EQ(ML99_or(v(0), v(1)), v(1));
+ ML99_ASSERT_EQ(ML99_or(v(1), v(0)), v(1));
+ ML99_ASSERT_EQ(ML99_or(v(1), v(1)), v(1));
+ }
+
+ // ML99_xor
+ {
+ ML99_ASSERT_EQ(ML99_xor(v(0), v(0)), v(0));
+ ML99_ASSERT_EQ(ML99_xor(v(0), v(1)), v(1));
+ ML99_ASSERT_EQ(ML99_xor(v(1), v(0)), v(1));
+ ML99_ASSERT_EQ(ML99_xor(v(1), v(1)), v(0));
+ }
+
+ // ML99_boolEq
+ {
+ ML99_ASSERT_EQ(ML99_boolEq(v(0), v(0)), v(1));
+ ML99_ASSERT_EQ(ML99_boolEq(v(0), v(1)), v(0));
+ ML99_ASSERT_EQ(ML99_boolEq(v(1), v(0)), v(0));
+ ML99_ASSERT_EQ(ML99_boolEq(v(1), v(1)), v(1));
+ }
+
+#define MATCH_1_IMPL(...) v(12) // `...` due to the TCC's bug.
+#define MATCH_0_IMPL(...) v(9)
+
+ // ML99_boolMatch
+ {
+ ML99_ASSERT_EQ(ML99_boolMatch(v(1), v(MATCH_)), v(12));
+ ML99_ASSERT_EQ(ML99_boolMatch(v(0), v(MATCH_)), v(9));
+ }
+
+#undef MATCH_1_IMPL
+#undef MATCH_0_IMPL
+
+#define MATCH_1_IMPL(x, y, z) v(ML99_ASSERT_UNEVAL(x == 1 && y == 2 && z == 3))
+#define MATCH_0_IMPL(x, y, z) v(ML99_ASSERT_UNEVAL(x == 1 && y == 2 && z == 3))
+
+ // ML99_boolMatchWithArgs
+ {
+ ML99_EVAL(ML99_boolMatchWithArgs(v(1), v(MATCH_), v(1, 2, 3)));
+ ML99_EVAL(ML99_boolMatchWithArgs(v(0), v(MATCH_), v(1, 2, 3)));
+ }
+
+#undef MATCH_1_IMPL
+#undef MATCH_0_IMPL
+
+ // ML99_if
+ {
+ ML99_ASSERT_EQ(ML99_if(ML99_true(), v(24), v(848)), v(24));
+ ML99_ASSERT_EQ(ML99_if(ML99_true(), v(1549), v(1678)), v(1549));
+
+ ML99_ASSERT_EQ(ML99_if(ML99_false(), v(516), v(115)), v(115));
+ ML99_ASSERT_EQ(ML99_if(ML99_false(), v(10), v(6)), v(6));
+ }
+
+#define CHECK(...) CHECK_AUX(__VA_ARGS__)
+#define CHECK_AUX(a, b, c) ML99_ASSERT_UNEVAL(a == 1 && b == 2 && c == 3)
+
+#define X 1, 2, 3
+
+ // ML99_IF
+ {
+ ML99_ASSERT_UNEVAL(ML99_IF(ML99_TRUE(), 24, 848) == 24);
+ ML99_ASSERT_UNEVAL(ML99_IF(ML99_FALSE(), 516, 115) == 115);
+
+ // Ensure that a branch can expand to multiple commas (`X`).
+ CHECK(ML99_IF(ML99_TRUE(), X, ~));
+ CHECK(ML99_IF(ML99_FALSE(), ~, X));
+ }
+
+#undef CHECK
+#undef CHECK_AUX
+#undef X
+
+ // Plain macros
+ {
+ ML99_ASSERT_UNEVAL(ML99_TRUE());
+ ML99_ASSERT_UNEVAL(ML99_TRUE(~, ~, ~));
+
+ ML99_ASSERT_UNEVAL(!ML99_FALSE());
+ ML99_ASSERT_UNEVAL(!ML99_FALSE(~, ~, ~));
+
+ ML99_ASSERT_UNEVAL(ML99_NOT(0) == 1);
+ ML99_ASSERT_UNEVAL(ML99_NOT(1) == 0);
+
+ ML99_ASSERT_UNEVAL(ML99_AND(0, 1) == 0);
+ ML99_ASSERT_UNEVAL(ML99_OR(0, 1) == 1);
+ ML99_ASSERT_UNEVAL(ML99_XOR(0, 1) == 1);
+ ML99_ASSERT_UNEVAL(ML99_BOOL_EQ(0, 1) == 0);
+ }
+}
diff --git a/test/external/metalang99/tests/choice.c b/test/external/metalang99/tests/choice.c
new file mode 100644
index 0000000..93f4fb5
--- /dev/null
+++ b/test/external/metalang99/tests/choice.c
@@ -0,0 +1,64 @@
+#include <metalang99/assert.h>
+#include <metalang99/choice.h>
+
+int main(void) {
+
+#define MATCH_IMPL(foo) ML99_match(v(foo), v(MATCH_))
+#define MATCH_FooA_IMPL(x) v(ML99_ASSERT_UNEVAL(x == 19))
+#define MATCH_FooB_IMPL(x) v(ML99_ASSERT_UNEVAL(x == 1756))
+#define MATCH_FooC_IMPL(_) v(ML99_ASSERT_UNEVAL(1))
+
+ // ML99_match
+ {
+ ML99_EVAL(ML99_call(MATCH, ML99_choice(v(FooA), v(19))));
+ ML99_EVAL(ML99_call(MATCH, ML99_choice(v(FooB), v(1756))));
+ ML99_EVAL(ML99_call(MATCH, ML99_choice(v(FooC), v(~))));
+ }
+
+#undef MATCH_IMPL
+#undef MATCH_FooA_IMPL
+#undef MATCH_FooB_IMPL
+#undef MATCH_FooC_IMPL
+
+#define MATCH_IMPL(foo) ML99_matchWithArgs(v(foo), v(MATCH_), v(3, 8))
+#define MATCH_FooA_IMPL(x, _3, _8) v(ML99_ASSERT_UNEVAL(x == 19 && _3 == 3 && _8 == 8))
+#define MATCH_FooB_IMPL(x, _3, _8) v(ML99_ASSERT_UNEVAL(x == 1756 && _3 == 3 && _8 == 8))
+#define MATCH_FooC_IMPL(_, _3, _8) v(ML99_ASSERT_UNEVAL(_3 == 3 && _8 == 8))
+
+ // ML99_matchWithArgs
+ {
+ ML99_EVAL(ML99_call(MATCH, ML99_choice(v(FooA), v(19))));
+ ML99_EVAL(ML99_call(MATCH, ML99_choice(v(FooB), v(1756))));
+ ML99_EVAL(ML99_call(MATCH, ML99_choice(v(FooC), v(~))));
+ }
+
+#undef MATCH_IMPL
+#undef MATCH_FooA_IMPL
+#undef MATCH_FooB_IMPL
+#undef MATCH_FooC_IMPL
+
+#define CHECK(x, y, z) ML99_ASSERT_UNEVAL(x == 1 && y == 2 && z == 3)
+#define CHECK_EXPAND(args) CHECK(args)
+
+ // ML99_choiceTag, ML99_choiceData
+ {
+ ML99_ASSERT_EQ(ML99_choiceTag(ML99_choice(v(5), v(1, 2, 3))), v(5));
+ CHECK_EXPAND(ML99_EVAL(ML99_choiceData(ML99_choice(v(5), v(1, 2, 3)))));
+ }
+
+ // ML99_CHOICE, ML99_CHOICE_TAG, ML99_CHOICE_DATA
+ {
+ ML99_ASSERT_UNEVAL(ML99_CHOICE_TAG(ML99_CHOICE(5, 1, 2, 3)) == 5);
+ CHECK_EXPAND(ML99_CHOICE_DATA(ML99_CHOICE(5, 1, 2, 3)));
+ }
+
+#undef CHECK
+#undef CHECK_EXPAND
+
+#define CHECK(tag, x, y, z) tag == 5 && x == 1 && y == 2 && z == 3
+
+ // Representation
+ { ML99_ASSERT_UNEVAL(CHECK ML99_CHOICE(5, 1, 2, 3)); }
+
+#undef CHECK
+}
diff --git a/test/external/metalang99/tests/either.c b/test/external/metalang99/tests/either.c
new file mode 100644
index 0000000..4a29fb9
--- /dev/null
+++ b/test/external/metalang99/tests/either.c
@@ -0,0 +1,66 @@
+#include <metalang99/assert.h>
+#include <metalang99/either.h>
+#include <metalang99/nat.h>
+
+int main(void) {
+
+#define MATCH_IMPL(either) ML99_match(v(either), v(MATCH_))
+#define MATCH_left_IMPL(x) v(ML99_ASSERT_UNEVAL(x == 18))
+#define MATCH_right_IMPL(x) v(ML99_ASSERT_UNEVAL(x == 4))
+
+ // Pattern matching
+ {
+ ML99_EVAL(ML99_call(MATCH, ML99_left(v(18))));
+ ML99_EVAL(ML99_call(MATCH, ML99_right(v(4))));
+ }
+
+#undef MATCH_IMPL
+#undef MATCH_left_IMPL
+#undef MATCH_right_IMPL
+
+#define VAL v(abc ? +-148 % "hello world")
+
+ // ML99_isLeft
+ {
+ ML99_ASSERT(ML99_isLeft(ML99_left(VAL)));
+ ML99_ASSERT(ML99_not(ML99_isLeft(ML99_right(VAL))));
+ }
+
+ // ML99_IS_LEFT
+ {
+ ML99_ASSERT_UNEVAL(ML99_IS_LEFT(ML99_LEFT(VAL)));
+ ML99_ASSERT_UNEVAL(!ML99_IS_LEFT(ML99_RIGHT(VAL)));
+ }
+
+ // ML99_isRight
+ {
+ ML99_ASSERT(ML99_isRight(ML99_right(VAL)));
+ ML99_ASSERT(ML99_not(ML99_isRight(ML99_left(VAL))));
+ }
+
+ // ML99_IS_RIGHT
+ {
+ ML99_ASSERT_UNEVAL(ML99_IS_RIGHT(ML99_RIGHT(VAL)));
+ ML99_ASSERT_UNEVAL(!ML99_IS_RIGHT(ML99_LEFT(VAL)));
+ }
+
+ // ML99_eitherEq
+ {
+ ML99_ASSERT(ML99_eitherEq(v(ML99_natEq), ML99_left(v(123)), ML99_left(v(123))));
+ ML99_ASSERT(ML99_not(ML99_eitherEq(v(ML99_natEq), ML99_left(v(18)), ML99_left(v(123)))));
+
+ ML99_ASSERT(ML99_eitherEq(v(ML99_natEq), ML99_right(v(123)), ML99_right(v(123))));
+ ML99_ASSERT(ML99_not(ML99_eitherEq(v(ML99_natEq), ML99_right(v(18)), ML99_right(v(123)))));
+
+ ML99_ASSERT(ML99_not(ML99_eitherEq(v(ML99_natEq), ML99_left(v(123)), ML99_right(v(123)))));
+ ML99_ASSERT(ML99_not(ML99_eitherEq(v(ML99_natEq), ML99_left(v(123)), ML99_right(v(4)))));
+ ML99_ASSERT(ML99_not(ML99_eitherEq(v(ML99_natEq), ML99_right(v(123)), ML99_left(v(123)))));
+ ML99_ASSERT(ML99_not(ML99_eitherEq(v(ML99_natEq), ML99_right(v(123)), ML99_left(v(4)))));
+ }
+
+ // ML99_unwrapLeft
+ { ML99_ASSERT_EQ(ML99_unwrapLeft(ML99_left(v(123))), v(123)); }
+
+ // ML99_unwrapRight
+ { ML99_ASSERT_EQ(ML99_unwrapRight(ML99_right(v(123))), v(123)); }
+}
diff --git a/test/external/metalang99/tests/eval/rec.c b/test/external/metalang99/tests/eval/rec.c
new file mode 100644
index 0000000..aff7390
--- /dev/null
+++ b/test/external/metalang99/tests/eval/rec.c
@@ -0,0 +1,25 @@
+#include <metalang99/eval/rec.h>
+
+#include <metalang99/assert.h>
+
+#include <metalang99/priv/util.h>
+
+#include <metalang99/nat/eq.h>
+#include <metalang99/nat/inc.h>
+
+#define F(acc, i) ML99_PRIV_IF(ML99_PRIV_NAT_EQ(i, 10), F_DONE, F_PROGRESS)(acc, i)
+#define F_DONE(acc, _i) ML99_PRIV_REC_CONTINUE(ML99_PRIV_REC_STOP)(~, acc)
+#define F_PROGRESS(acc, i) ML99_PRIV_REC_CONTINUE(F)(acc##X, ML99_PRIV_INC(i))
+#define F_HOOK() F
+
+#define XXXXXXXXXX 678
+
+ML99_ASSERT_UNEVAL(ML99_PRIV_REC_UNROLL(F(, 0)) == 678);
+
+#undef F
+#undef F_DONE
+#undef F_PROGRESS
+#undef F_HOOK
+#undef XXXXXXXXXX
+
+int main(void) {}
diff --git a/test/external/metalang99/tests/gen.c b/test/external/metalang99/tests/gen.c
new file mode 100644
index 0000000..bb1e163
--- /dev/null
+++ b/test/external/metalang99/tests/gen.c
@@ -0,0 +1,283 @@
+#include <metalang99/assert.h>
+#include <metalang99/gen.h>
+#include <metalang99/ident.h>
+#include <metalang99/list.h>
+#include <metalang99/tuple.h>
+
+#include <assert.h>
+
+// clang-format off
+static void
+ test_indexed_params ML99_EVAL(ML99_indexedParams(ML99_list(v(int, long long, const char *))))
+// clang-format on
+{
+ int i = _0;
+ long long ll = _1;
+ const char *str = _2;
+
+ (void)i;
+ (void)ll;
+ (void)str;
+}
+
+static int test_fn_ptr(const char *str, long long x) {
+ (void)str;
+ (void)x;
+ return 123;
+}
+
+int main(void) {
+
+ // ML99_braced
+ { struct TestBraced ML99_EVAL(ML99_braced(v(int a, b, c;))); }
+
+ // ML99_semicoloned
+ {
+ ML99_EVAL(ML99_semicoloned(v(struct TestSemicoloned { int a, b, c; })));
+ }
+
+ // ML99_assign(Stmt)
+ {
+ int x = 0;
+
+ ML99_EVAL(ML99_assign(v(x), v(5)));
+ assert(5 == x);
+
+ ML99_EVAL(ML99_assignStmt(v(x), v(7)))
+ assert(7 == x);
+ }
+
+ // ML99_assignInitializerList(Stmt)
+ {
+ typedef struct {
+ int x, y;
+ } Point;
+
+ ML99_EVAL(ML99_assignInitializerList(v(Point p1), v(.x = 2, .y = 3)));
+ assert(2 == p1.x);
+ assert(3 == p1.y);
+
+ ML99_EVAL(ML99_assignInitializerListStmt(v(Point p2), v(.x = 5, .y = 7)))
+ assert(5 == p2.x);
+ assert(7 == p2.y);
+ }
+
+#define F(a, b, c) ML99_ASSERT_UNEVAL(a == 1 && b == 2 && c == 3)
+
+ // ML99_invoke(Stmt)
+ {
+ ML99_EVAL(ML99_invoke(v(F), v(1, 2, 3)));
+ ML99_EVAL(ML99_invokeStmt(v(F), v(1, 2, 3)))
+ }
+
+#undef F
+
+ // ML99_prefixedBlock
+ {
+
+ ML99_EVAL(ML99_prefixedBlock(v(if (1)), v(goto end_prefixed_block;)))
+
+ // Unreachable code.
+ assert(0);
+
+ end_prefixed_block:;
+ }
+
+ // ML99_typedef
+ {
+
+ ML99_EVAL(ML99_typedef(v(Point), v(struct { int x, y; })));
+
+ Point point = {5, 7};
+ point.x = 1;
+ point.y = 2;
+
+ (void)point;
+ }
+
+ // ML99_struct
+ {
+
+ ML99_EVAL(ML99_struct(v(Point), v(int x, y;)));
+
+ struct Point point = {5, 7};
+ point.x = 1;
+ point.y = 2;
+
+ (void)point;
+ }
+
+ // ML99_anonStruct
+ {
+ typedef ML99_EVAL(ML99_anonStruct(v(int x, y;)))
+ Point;
+
+ Point point = {5, 7};
+ point.x = 1;
+ point.y = 2;
+
+ (void)point;
+ }
+
+ // ML99_union
+ {
+ ML99_EVAL(ML99_union(v(Point), v(int x, y;)));
+
+ union Point point;
+ point.x = 1;
+ point.y = 2;
+
+ (void)point;
+ }
+
+ // ML99_anonUnion
+ {
+ typedef ML99_EVAL(ML99_anonUnion(v(int x, y;)))
+ Point;
+
+ Point point;
+ point.x = 1;
+ point.y = 2;
+
+ (void)point;
+ }
+
+ // ML99_enum
+ {
+ ML99_EVAL(ML99_enum(v(MyEnum), v(Foo, Bar)));
+
+ enum MyEnum foo = Foo, bar = Bar;
+ (void)foo;
+ (void)bar;
+ }
+
+ // ML99_anonEnum
+ {
+ typedef ML99_EVAL(ML99_anonEnum(v(Foo, Bar)))
+ MyEnum;
+
+ MyEnum foo = Foo, bar = Bar;
+ (void)foo;
+ (void)bar;
+ }
+
+ // ML99_fnPtr(Stmt)
+ {
+ {
+ ML99_EVAL(ML99_fnPtr(v(int), v(ptr), v(const char *str), v(long long x)))
+ = test_fn_ptr;
+ assert(test_fn_ptr == ptr);
+ }
+
+ {
+ ML99_EVAL(ML99_fnPtrStmt(v(int), v(ptr), v(const char *str), v(long long x)))
+ ptr = test_fn_ptr;
+ (void)ptr;
+ }
+ }
+
+#define CHECK_EXPAND(args) CHECK(args)
+
+#define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 0 && y == 1 && z == 2)
+#define F_IMPL(x) v(, x)
+#define F_ARITY 1
+
+ // ML99_repeat
+ { CHECK_EXPAND(ML99_EVAL(ML99_repeat(v(3), v(F)))); }
+
+#undef CHECK
+#undef F_IMPL
+#undef F_ARITY
+
+#define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 5 && y == 5 && z == 5)
+
+ // ML99_times
+ { CHECK_EXPAND(ML99_EVAL(ML99_times(v(3), v(, 5)))); }
+
+#undef CHECK
+
+#undef CHECK_EXPAND
+
+ // ML99_indexedParams
+ {
+ ML99_ASSERT_UNEVAL(ML99_IDENT_EQ(
+ ML99_C_KEYWORD_DETECTOR,
+ void,
+ ML99_EVAL(ML99_untuple(ML99_indexedParams(ML99_nil())))));
+
+ (void)test_indexed_params;
+ }
+
+ // ML99_indexedFields
+ {
+ ML99_ASSERT_EMPTY(ML99_indexedFields(ML99_nil()));
+
+ struct {
+ ML99_EVAL(ML99_indexedFields(ML99_list(v(int, long long, const char *))))
+ } data = {0};
+
+ int i = data._0;
+ long long ll = data._1;
+ const char *str = data._2;
+
+ (void)i;
+ (void)ll;
+ (void)str;
+ }
+
+ // clang-format off
+
+ // ML99_indexedInitializerList
+ {
+ // When N=0.
+ {
+ const struct {
+ int _0;
+ long long _1;
+ const char *_2;
+ } test = ML99_EVAL(ML99_indexedInitializerList(v(0)));
+
+ assert(0 == test._0);
+ assert(0 == test._1);
+ assert(0 == test._2);
+ }
+
+ // When N>0.
+ {
+ int _0 = 123;
+ long long _1 = 149494456;
+ const char *_2 = "abc";
+
+ struct {
+ int i;
+ long long ll;
+ const char *str;
+ } data = ML99_EVAL(ML99_indexedInitializerList(v(3)));
+
+ (void)data;
+ }
+ }
+
+ // ML99_indexedArgs
+ {
+ ML99_ASSERT_EMPTY(ML99_indexedArgs(v(0)));
+
+ int _0 = 123;
+ long long _1 = 149494456;
+ const char *_2 = "abc";
+
+ const struct {
+ int i;
+ long long ll;
+ const char *str;
+ } test = { ML99_EVAL(ML99_indexedArgs(v(3))) };
+
+ assert(test.i == _0);
+ assert(test.ll == _1);
+ assert(test.str == _2);
+ }
+
+ // clang-format on
+
+ return 0;
+}
diff --git a/test/external/metalang99/tests/ident.c b/test/external/metalang99/tests/ident.c
new file mode 100644
index 0000000..5f32f16
--- /dev/null
+++ b/test/external/metalang99/tests/ident.c
@@ -0,0 +1,395 @@
+#include <metalang99/assert.h>
+#include <metalang99/bool.h>
+#include <metalang99/ident.h>
+
+int main(void) {
+
+#define EMPTY
+
+#define FOO_x ()
+#define FOO_y ()
+
+ // ML99_detectIdent
+ {
+ ML99_ASSERT(ML99_detectIdent(v(FOO_), v(x)));
+ ML99_ASSERT(ML99_detectIdent(v(FOO_), v(y)));
+ ML99_ASSERT(ML99_not(ML99_detectIdent(v(FOO_), v(z))));
+
+ ML99_ASSERT(ML99_not(ML99_detectIdent(v(BAR_), v(x))));
+ ML99_ASSERT(ML99_not(ML99_detectIdent(v(BAR_), v(abc))));
+ ML99_ASSERT(ML99_not(ML99_detectIdent(v(BAR_), v(defghi))));
+ }
+
+ // ML99_DETECT_IDENT
+ {
+ ML99_ASSERT_UNEVAL(ML99_DETECT_IDENT(FOO_, x));
+ ML99_ASSERT_UNEVAL(!ML99_DETECT_IDENT(BAR_, x));
+ }
+
+#undef FOO_x
+#undef FOO_y
+
+#define FOO_x_x ()
+#define FOO_y_y ()
+
+ // ML99_identEq
+ {
+ ML99_ASSERT(ML99_identEq(v(FOO_), v(x), v(x)));
+ ML99_ASSERT(ML99_identEq(v(FOO_), v(y), v(y)));
+
+ ML99_ASSERT(ML99_not(ML99_identEq(v(FOO_), v(x), v(y))));
+ ML99_ASSERT(ML99_not(ML99_identEq(v(FOO_), v(abc), v(d))));
+ ML99_ASSERT(ML99_not(ML99_identEq(v(FOO_), v(x), v(EMPTY))));
+ ML99_ASSERT(ML99_not(ML99_identEq(v(FOO_), v(EMPTY), v(y))));
+ ML99_ASSERT(ML99_not(ML99_identEq(v(FOO_), v(EMPTY), v(EMPTY))));
+ }
+
+ // ML99_IDENT_EQ
+ {
+ ML99_ASSERT_UNEVAL(ML99_IDENT_EQ(FOO_, x, x));
+ ML99_ASSERT_UNEVAL(!ML99_IDENT_EQ(FOO_, x, y));
+ }
+
+#undef FOO_x_x
+#undef FOO_y_y
+
+ // ML99_charEq
+ {
+ ML99_ASSERT(ML99_charEq(v(a), v(a)));
+ ML99_ASSERT(ML99_charEq(v(x), v(x)));
+ ML99_ASSERT(ML99_charEq(v(e), v(e)));
+
+ ML99_ASSERT(ML99_charEq(v(T), v(T)));
+ ML99_ASSERT(ML99_charEq(v(J), v(J)));
+ ML99_ASSERT(ML99_charEq(v(D), v(D)));
+
+ ML99_ASSERT(ML99_charEq(v(0), v(0)));
+ ML99_ASSERT(ML99_charEq(v(5), v(5)));
+ ML99_ASSERT(ML99_charEq(v(9), v(9)));
+
+ ML99_ASSERT(ML99_not(ML99_charEq(v(a), v(idf2))));
+ ML99_ASSERT(ML99_not(ML99_charEq(v(T), v(abracadabra))));
+ ML99_ASSERT(ML99_not(ML99_charEq(v(0), v(123))));
+ ML99_ASSERT(ML99_not(ML99_charEq(v(abracadabra), v(abracadabra))));
+ }
+
+ // ML99_CHAR_EQ
+ {
+ ML99_ASSERT_UNEVAL(ML99_CHAR_EQ(x, x));
+ ML99_ASSERT_UNEVAL(!ML99_CHAR_EQ(x, 0));
+ }
+
+ // ML99_C_KEYWORD_DETECTOR
+ {
+
+#define TEST(keyword) \
+ ML99_ASSERT_UNEVAL( \
+ ML99_IDENT_EQ(ML99_C_KEYWORD_DETECTOR, keyword, keyword) && \
+ !ML99_IDENT_EQ(ML99_C_KEYWORD_DETECTOR, keyword, blah) && \
+ !ML99_IDENT_EQ(ML99_C_KEYWORD_DETECTOR, keyword, EMPTY) && \
+ !ML99_IDENT_EQ(ML99_C_KEYWORD_DETECTOR, EMPTY, keyword))
+
+ TEST(auto);
+ TEST(break);
+ TEST(case);
+ TEST(char);
+ TEST(const);
+ TEST(continue);
+ TEST(default);
+ TEST(do);
+ TEST(double);
+ TEST(else);
+ TEST(enum);
+ TEST(extern);
+ TEST(float);
+ TEST(for);
+ TEST(goto);
+ TEST(if);
+ TEST(inline);
+ TEST(int);
+ TEST(long);
+ TEST(register);
+ TEST(restrict);
+ // clang-format off
+ TEST(return);
+ // clang-format on
+ TEST(short);
+ TEST(signed);
+ TEST(sizeof);
+ TEST(static);
+ TEST(struct);
+ TEST(switch);
+ TEST(typedef);
+ TEST(union);
+ TEST(unsigned);
+ TEST(void);
+ TEST(volatile);
+ TEST(while);
+ TEST(_Alignas);
+ TEST(_Alignof);
+ TEST(_Atomic);
+ TEST(_Bool);
+ TEST(_Complex);
+ TEST(_Generic);
+ TEST(_Imaginary);
+ TEST(_Noreturn);
+ TEST(_Static_assert);
+ TEST(_Thread_local);
+
+#undef TEST
+
+ ML99_ASSERT_UNEVAL(!ML99_IDENT_EQ(ML99_C_KEYWORD_DETECTOR, restrict, void));
+ ML99_ASSERT_UNEVAL(!ML99_IDENT_EQ(ML99_C_KEYWORD_DETECTOR, case, while));
+ ML99_ASSERT_UNEVAL(!ML99_IDENT_EQ(ML99_C_KEYWORD_DETECTOR, volatile, _Alignof));
+ ML99_ASSERT_UNEVAL(!ML99_IDENT_EQ(ML99_C_KEYWORD_DETECTOR, _Generic, _Alignas));
+
+ ML99_ASSERT(ML99_identEq(v(ML99_C_KEYWORD_DETECTOR), v(_Bool), v(_Bool)));
+ ML99_ASSERT(ML99_not(ML99_identEq(v(ML99_C_KEYWORD_DETECTOR), v(_Atomic), v(_Bool))));
+ }
+
+ // ML99_UNDERSCORE_DETECTOR
+ {
+ ML99_ASSERT(ML99_detectIdent(v(ML99_UNDERSCORE_DETECTOR), v(_)));
+ ML99_ASSERT(ML99_not(ML99_detectIdent(v(ML99_UNDERSCORE_DETECTOR), v(blah))));
+ ML99_ASSERT(ML99_not(ML99_detectIdent(v(ML99_UNDERSCORE_DETECTOR), v())));
+ }
+
+ // ML99_LOWERCASE_DETECTOR
+ {
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(a), v(a)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(b), v(b)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(c), v(c)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(d), v(d)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(e), v(e)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(f), v(f)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(g), v(g)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(h), v(h)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(i), v(i)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(j), v(j)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(k), v(k)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(l), v(l)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(m), v(m)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(n), v(n)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(o), v(o)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(p), v(p)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(q), v(q)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(r), v(r)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(s), v(s)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(t), v(t)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(u), v(u)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(v), v(v)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(w), v(w)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(x), v(x)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(y), v(y)));
+ ML99_ASSERT(ML99_identEq(v(ML99_LOWERCASE_DETECTOR), v(z), v(z)));
+ }
+
+ // ML99_UPPERCASE_DETECTOR
+ {
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(A), v(A)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(B), v(B)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(C), v(C)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(D), v(D)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(E), v(E)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(F), v(F)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(G), v(G)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(H), v(H)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(I), v(I)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(J), v(J)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(K), v(K)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(L), v(L)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(M), v(M)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(N), v(N)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(O), v(O)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(P), v(P)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(Q), v(Q)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(R), v(R)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(S), v(S)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(T), v(T)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(U), v(U)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(V), v(V)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(W), v(W)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(X), v(X)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(Y), v(Y)));
+ ML99_ASSERT(ML99_identEq(v(ML99_UPPERCASE_DETECTOR), v(Z), v(Z)));
+ }
+
+ // ML99_DIGIT_DETECTOR
+ {
+ ML99_ASSERT(ML99_identEq(v(ML99_DIGIT_DETECTOR), v(0), v(0)));
+ ML99_ASSERT(ML99_identEq(v(ML99_DIGIT_DETECTOR), v(1), v(1)));
+ ML99_ASSERT(ML99_identEq(v(ML99_DIGIT_DETECTOR), v(2), v(2)));
+ ML99_ASSERT(ML99_identEq(v(ML99_DIGIT_DETECTOR), v(3), v(3)));
+ ML99_ASSERT(ML99_identEq(v(ML99_DIGIT_DETECTOR), v(4), v(4)));
+ ML99_ASSERT(ML99_identEq(v(ML99_DIGIT_DETECTOR), v(5), v(5)));
+ ML99_ASSERT(ML99_identEq(v(ML99_DIGIT_DETECTOR), v(6), v(6)));
+ ML99_ASSERT(ML99_identEq(v(ML99_DIGIT_DETECTOR), v(7), v(7)));
+ ML99_ASSERT(ML99_identEq(v(ML99_DIGIT_DETECTOR), v(8), v(8)));
+ ML99_ASSERT(ML99_identEq(v(ML99_DIGIT_DETECTOR), v(9), v(9)));
+ }
+
+ // ML99_IS_LOWERCASE
+ {
+ ML99_ASSERT_UNEVAL(ML99_IS_LOWERCASE(a));
+ ML99_ASSERT_UNEVAL(ML99_IS_LOWERCASE(j));
+ ML99_ASSERT_UNEVAL(ML99_IS_LOWERCASE(z));
+
+ ML99_ASSERT_UNEVAL(!ML99_IS_LOWERCASE(8));
+ ML99_ASSERT_UNEVAL(!ML99_IS_LOWERCASE(I));
+ ML99_ASSERT_UNEVAL(!ML99_IS_LOWERCASE(_));
+ ML99_ASSERT_UNEVAL(!ML99_IS_LOWERCASE(abracadabra));
+
+ ML99_ASSERT(ML99_isLowercase(v(z)));
+ ML99_ASSERT(ML99_not(ML99_isLowercase(v(8))));
+ }
+
+ // ML99_IS_UPPERCASE
+ {
+ ML99_ASSERT_UNEVAL(ML99_IS_UPPERCASE(A));
+ ML99_ASSERT_UNEVAL(ML99_IS_UPPERCASE(J));
+ ML99_ASSERT_UNEVAL(ML99_IS_UPPERCASE(Z));
+
+ ML99_ASSERT_UNEVAL(!ML99_IS_UPPERCASE(8));
+ ML99_ASSERT_UNEVAL(!ML99_IS_UPPERCASE(i));
+ ML99_ASSERT_UNEVAL(!ML99_IS_UPPERCASE(_));
+ ML99_ASSERT_UNEVAL(!ML99_IS_UPPERCASE(abracadabra));
+
+ ML99_ASSERT(ML99_isUppercase(v(Z)));
+ ML99_ASSERT(ML99_not(ML99_isUppercase(v(8))));
+ }
+
+ // ML99_isDigit
+ {
+ ML99_ASSERT(ML99_isDigit(v(0)));
+ ML99_ASSERT(ML99_isDigit(v(2)));
+ ML99_ASSERT(ML99_isDigit(v(9)));
+
+ ML99_ASSERT(ML99_not(ML99_isDigit(v(U))));
+ ML99_ASSERT(ML99_not(ML99_isDigit(v(i))));
+ ML99_ASSERT(ML99_not(ML99_isDigit(v(_))));
+ ML99_ASSERT(ML99_not(ML99_isDigit(v(abracadabra))));
+ }
+
+ // ML99_IS_DIGIT
+ {
+ ML99_ASSERT_UNEVAL(ML99_IS_DIGIT(7));
+ ML99_ASSERT_UNEVAL(!ML99_IS_DIGIT(k));
+ }
+
+ // ML99_isChar
+ {
+ ML99_ASSERT(ML99_isChar(v(0)));
+ ML99_ASSERT(ML99_isChar(v(4)));
+ ML99_ASSERT(ML99_isChar(v(8)));
+
+ ML99_ASSERT(ML99_isChar(v(a)));
+ ML99_ASSERT(ML99_isChar(v(b)));
+ ML99_ASSERT(ML99_isChar(v(c)));
+
+ ML99_ASSERT(ML99_isChar(v(A)));
+ ML99_ASSERT(ML99_isChar(v(B)));
+ ML99_ASSERT(ML99_isChar(v(C)));
+
+ ML99_ASSERT(ML99_isChar(v(_)));
+
+ ML99_ASSERT(ML99_not(ML99_isChar(v(kk))));
+ ML99_ASSERT(ML99_not(ML99_isChar(v(0abc))));
+ ML99_ASSERT(ML99_not(ML99_isChar(v(abracadabra))));
+ }
+
+ // ML99_IS_CHAR
+ {
+ ML99_ASSERT_UNEVAL(ML99_IS_CHAR(z));
+ ML99_ASSERT_UNEVAL(!ML99_IS_CHAR(xyz));
+ }
+
+ // ML99_charLit
+ {
+ ML99_ASSERT_EQ(ML99_charLit(v(a)), v('a'));
+ ML99_ASSERT_EQ(ML99_charLit(v(b)), v('b'));
+ ML99_ASSERT_EQ(ML99_charLit(v(c)), v('c'));
+ ML99_ASSERT_EQ(ML99_charLit(v(d)), v('d'));
+ ML99_ASSERT_EQ(ML99_charLit(v(e)), v('e'));
+ ML99_ASSERT_EQ(ML99_charLit(v(f)), v('f'));
+ ML99_ASSERT_EQ(ML99_charLit(v(g)), v('g'));
+ ML99_ASSERT_EQ(ML99_charLit(v(h)), v('h'));
+ ML99_ASSERT_EQ(ML99_charLit(v(i)), v('i'));
+ ML99_ASSERT_EQ(ML99_charLit(v(j)), v('j'));
+ ML99_ASSERT_EQ(ML99_charLit(v(k)), v('k'));
+ ML99_ASSERT_EQ(ML99_charLit(v(l)), v('l'));
+ ML99_ASSERT_EQ(ML99_charLit(v(m)), v('m'));
+ ML99_ASSERT_EQ(ML99_charLit(v(n)), v('n'));
+ ML99_ASSERT_EQ(ML99_charLit(v(o)), v('o'));
+ ML99_ASSERT_EQ(ML99_charLit(v(p)), v('p'));
+ ML99_ASSERT_EQ(ML99_charLit(v(q)), v('q'));
+ ML99_ASSERT_EQ(ML99_charLit(v(r)), v('r'));
+ ML99_ASSERT_EQ(ML99_charLit(v(s)), v('s'));
+ ML99_ASSERT_EQ(ML99_charLit(v(t)), v('t'));
+ ML99_ASSERT_EQ(ML99_charLit(v(u)), v('u'));
+ ML99_ASSERT_EQ(ML99_charLit(v(v)), v('v'));
+ ML99_ASSERT_EQ(ML99_charLit(v(w)), v('w'));
+ ML99_ASSERT_EQ(ML99_charLit(v(x)), v('x'));
+ ML99_ASSERT_EQ(ML99_charLit(v(y)), v('y'));
+ ML99_ASSERT_EQ(ML99_charLit(v(z)), v('z'));
+
+ ML99_ASSERT_EQ(ML99_charLit(v(A)), v('A'));
+ ML99_ASSERT_EQ(ML99_charLit(v(B)), v('B'));
+ ML99_ASSERT_EQ(ML99_charLit(v(C)), v('C'));
+ ML99_ASSERT_EQ(ML99_charLit(v(D)), v('D'));
+ ML99_ASSERT_EQ(ML99_charLit(v(E)), v('E'));
+ ML99_ASSERT_EQ(ML99_charLit(v(F)), v('F'));
+ ML99_ASSERT_EQ(ML99_charLit(v(G)), v('G'));
+ ML99_ASSERT_EQ(ML99_charLit(v(H)), v('H'));
+ ML99_ASSERT_EQ(ML99_charLit(v(I)), v('I'));
+ ML99_ASSERT_EQ(ML99_charLit(v(J)), v('J'));
+ ML99_ASSERT_EQ(ML99_charLit(v(K)), v('K'));
+ ML99_ASSERT_EQ(ML99_charLit(v(L)), v('L'));
+ ML99_ASSERT_EQ(ML99_charLit(v(M)), v('M'));
+ ML99_ASSERT_EQ(ML99_charLit(v(N)), v('N'));
+ ML99_ASSERT_EQ(ML99_charLit(v(O)), v('O'));
+ ML99_ASSERT_EQ(ML99_charLit(v(P)), v('P'));
+ ML99_ASSERT_EQ(ML99_charLit(v(Q)), v('Q'));
+ ML99_ASSERT_EQ(ML99_charLit(v(R)), v('R'));
+ ML99_ASSERT_EQ(ML99_charLit(v(S)), v('S'));
+ ML99_ASSERT_EQ(ML99_charLit(v(T)), v('T'));
+ ML99_ASSERT_EQ(ML99_charLit(v(U)), v('U'));
+ ML99_ASSERT_EQ(ML99_charLit(v(V)), v('V'));
+ ML99_ASSERT_EQ(ML99_charLit(v(W)), v('W'));
+ ML99_ASSERT_EQ(ML99_charLit(v(X)), v('X'));
+ ML99_ASSERT_EQ(ML99_charLit(v(Y)), v('Y'));
+ ML99_ASSERT_EQ(ML99_charLit(v(Z)), v('Z'));
+
+ ML99_ASSERT_EQ(ML99_charLit(v(0)), v('0'));
+ ML99_ASSERT_EQ(ML99_charLit(v(1)), v('1'));
+ ML99_ASSERT_EQ(ML99_charLit(v(2)), v('2'));
+ ML99_ASSERT_EQ(ML99_charLit(v(3)), v('3'));
+ ML99_ASSERT_EQ(ML99_charLit(v(4)), v('4'));
+ ML99_ASSERT_EQ(ML99_charLit(v(5)), v('5'));
+ ML99_ASSERT_EQ(ML99_charLit(v(6)), v('6'));
+ ML99_ASSERT_EQ(ML99_charLit(v(7)), v('7'));
+ ML99_ASSERT_EQ(ML99_charLit(v(8)), v('8'));
+ ML99_ASSERT_EQ(ML99_charLit(v(9)), v('9'));
+
+ ML99_ASSERT_EQ(ML99_charLit(v(_)), v('_'));
+ }
+
+ // ML99_CHAR_LIT
+ {
+ ML99_ASSERT_UNEVAL(ML99_CHAR_LIT(r) == 'r');
+ ML99_ASSERT_UNEVAL(ML99_CHAR_LIT(8) == '8');
+ ML99_ASSERT_UNEVAL(ML99_CHAR_LIT(_) == '_');
+ }
+
+#define FST(...) FST_AUX(__VA_ARGS__)
+#define FST_AUX(x, ...) x
+
+ // ML99_LOWERCASE_CHARS, ML99_UPPERCASE_CHARS, ML99_DIGITS
+ {
+ ML99_ASSERT_UNEVAL(ML99_CHAR_EQ(a, FST(ML99_LOWERCASE_CHARS(~, ~, ~))));
+ ML99_ASSERT_UNEVAL(ML99_CHAR_EQ(A, FST(ML99_UPPERCASE_CHARS(~, ~, ~))));
+ ML99_ASSERT_UNEVAL(FST(ML99_DIGITS(~, ~, ~)) == 0);
+ }
+
+#undef FST
+#undef FST_AUX
+}
diff --git a/test/external/metalang99/tests/lang.c b/test/external/metalang99/tests/lang.c
new file mode 100644
index 0000000..df76c3d
--- /dev/null
+++ b/test/external/metalang99/tests/lang.c
@@ -0,0 +1,165 @@
+// `...` is sometimes used to workaround a TCC bug, see
+// <https://github.com/hirrolot/datatype99/issues/10#issuecomment-830813172>.
+
+#include <metalang99/assert.h>
+#include <metalang99/util.h>
+
+int main(void) {
+
+ ML99_ASSERT_EMPTY_UNEVAL(ML99_EVAL(v()));
+
+#ifndef __TINYC__
+#define F_IMPL() v(123)
+#else
+#define F_IMPL(...) v(123) // `...` due to the TCC's bug.
+#endif
+
+ // A function with zero arguments
+ {
+ ML99_ASSERT_EQ(ML99_call(F, v()), v(123));
+ ML99_ASSERT_EQ(ML99_call(v(F), v()), v(123));
+ ML99_ASSERT_EQ(ML99_callUneval(F, ), v(123));
+ }
+
+#undef F_IMPL
+
+#define F_IMPL(x, y, z) v(x##y##z)
+#define BAR_IMPL(x, y) v(x + y)
+
+ // Regular usage of the metalanguage
+ {
+ ML99_ASSERT_EQ(ML99_call(BAR, v(5), v(7)), v(5 + 7));
+ ML99_ASSERT_EQ(ML99_call(ML99_call(F, v(B), v(A), v(R)), v(6), v(11)), v(6 + 11));
+
+ ML99_ASSERT_EQ(ML99_call(BAR, v(5, 7)), v(5 + 7));
+ ML99_ASSERT_EQ(ML99_call(ML99_call(F, v(B, A, R)), v(6, 11)), v(6 + 11));
+
+ ML99_ASSERT_EQ(ML99_callUneval(BAR, 5, 7), v(5 + 7));
+ }
+
+#undef F_IMPL
+#undef BAR_IMPL
+
+// Even if a term in the argument position evaluates to more than one terms, they should be appended
+// to each other but not interspersed with a comma.
+#define F_IMPL(...) ML99_TERMS(v(1), v(2), v(3)) // `...` due to the TCC's bug.
+#define BAR_IMPL(x) v()
+
+ ML99_EVAL(ML99_call(BAR, ML99_call(F, v())))
+
+#undef F_IMPL
+#undef BAR_IMPL
+
+// Recursion might arise from a higher-order macro, if `op` invokes `F`, but nonetheless the
+// second call to `F` must be performed as expected.
+#define F_IMPL(op) ML99_call(op, v(123))
+#define OP_IMPL(x) ML99_call(F, v(ID))
+#define ID_IMPL(x) v(x)
+
+ ML99_ASSERT_EQ(ML99_call(F, v(OP)), v(123));
+
+#undef F_IMPL
+#undef OP_IMPL
+#undef ID_IMPL
+
+ // ML99_abort
+ {
+ ML99_ASSERT_EMPTY(ML99_abort(v()));
+ ML99_ASSERT_EQ(ML99_abort(v(815057)), v(815057));
+ ML99_ASSERT_UNEVAL(ML99_EVAL(v(~), ML99_abort(v(123)), v(~)) == 123);
+
+// Ensure that `ML99_abort` also works correctly after some evaluations.
+#define F_IMPL(...) ML99_call(G, v(1, 2), ML99_call(H, v(123))) // `...` due to the TCC's bug.
+#define G_IMPL(_1, _2, _123_plus_1) \
+ ML99_abort(v(ML99_ASSERT_UNEVAL(_1 == 1 && _2 == 2 && _123_plus_1 == 123 + 1)))
+#define H_IMPL(a) v(a + 1)
+
+ ML99_EVAL(ML99_call(F, v()));
+
+#undef F_IMPL
+#undef G_IMPL
+#undef H_IMPL
+
+ // Ensure that `ML99_abort` immediately aborts interpretation even in an argument position.
+ ML99_ASSERT_EQ(ML99_call(NonExistingF, ML99_abort(v(123))), v(123));
+ }
+
+ // Partial application
+ {
+
+#ifndef __TINYC__
+#define F_IMPL() v(123)
+#else
+#define F_IMPL(...) v(123) // // `...` due to the TCC's bug.
+#endif
+
+#define F_ARITY 1
+
+ // The arity of a function with zero arguments must be 1
+ { ML99_ASSERT_EQ(ML99_appl(v(F), v()), v(123)); }
+
+#undef F_IMPL
+#undef F_ARITY
+
+#define F_IMPL(a, b, c, d) v(a##b##c##d)
+#define F_ARITY 4
+
+ // Regular usage of partial application
+ {
+ ML99_ASSERT_EQ(
+ ML99_appl(ML99_appl(ML99_appl(ML99_appl(v(F), v(10)), v(5)), v(7)), v(8)),
+ v(10578));
+ ML99_ASSERT_EQ(
+ ML99_appl(ML99_appl(ML99_appl2(v(F), v(10), v(5)), v(7)), v(8)),
+ v(10578));
+ ML99_ASSERT_EQ(ML99_appl(ML99_appl3(v(F), v(10), v(5), v(7)), v(8)), v(10578));
+ ML99_ASSERT_EQ(ML99_appl4(v(F), v(10), v(5), v(7), v(8)), v(10578));
+ }
+
+#undef F_IMPL
+#undef F_ARITY
+
+#define F_ARITY 255
+
+ // The maximum arity
+ {
+ ML99_EVAL(ML99_empty(ML99_appl(v(F), v(~))))
+ ML99_EVAL(ML99_empty(ML99_appl2(v(F), v(~), v(~))))
+ ML99_EVAL(ML99_empty(ML99_appl3(v(F), v(~), v(~), v(~))))
+ }
+
+#undef F_ARITY
+ }
+
+#define F_IMPL(x) v((x + 1))
+#define G_IMPL(x) v((x * 8))
+
+#define F_ARITY 1
+#define G_ARITY 1
+
+ // ML99_compose
+ { ML99_ASSERT_EQ(ML99_appl(ML99_compose(v(F), v(G)), v(3)), v((3 * 8) + 1)); }
+
+#undef F_IMPL
+#undef G_IMPL
+
+#undef F_ARITY
+#undef G_ARITY
+
+#define F_IMPL(x) v(x)
+
+#define PROG ML99_TERMS(v(1), v(, ), v(2), v(, ), ML99_call(F, v(7)))
+
+#define CHECK(...) CHECK_AUX(__VA_ARGS__)
+#define CHECK_AUX(a, b, c) ML99_ASSERT_UNEVAL(a == 1 && b == 2 && c == 7)
+
+ // ML99_QUOTE
+ { CHECK(ML99_EVAL(ML99_EVAL(ML99_QUOTE(PROG)))); }
+
+#undef F_IMPL
+
+#undef PROG
+
+#undef CHECK
+#undef CHECK_AUX
+}
diff --git a/test/external/metalang99/tests/list.c b/test/external/metalang99/tests/list.c
new file mode 100644
index 0000000..dcaeed6
--- /dev/null
+++ b/test/external/metalang99/tests/list.c
@@ -0,0 +1,528 @@
+#include <metalang99/assert.h>
+#include <metalang99/list.h>
+#include <metalang99/maybe.h>
+#include <metalang99/nat.h>
+#include <metalang99/tuple.h>
+#include <metalang99/util.h>
+
+int main(void) {
+
+#define CMP_NATURALS(lhs, rhs) ML99_listEq(v(ML99_natEq), lhs, rhs)
+
+ // ML99_list, ML99_cons, ML99_nil
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_nil(v(~, ~, ~)), ML99_nil()));
+
+ ML99_ASSERT(ML99_listEq(
+ v(ML99_natEq),
+ ML99_list(v(1, 2, 3, 4, 5, 6, 7)),
+ ML99_cons(
+ v(1),
+ ML99_cons(
+ v(2),
+ ML99_cons(
+ v(3),
+ ML99_cons(
+ v(4),
+ ML99_cons(v(5), ML99_cons(v(6), ML99_cons(v(7), ML99_nil())))))))));
+ }
+
+#define F_IMPL(x, y) ML99_add(v(x), v(y))
+#define F_ARITY 1
+
+ // ML99_listFromTuples
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_listFromTuples(v(F), v((1, 2))), ML99_list(v(3))));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listFromTuples(v(F), v((1, 2), (3, 4), (5, 6))),
+ ML99_list(v(3, 7, 11))));
+ }
+
+#undef F_IMPL
+#undef F_ARITY
+
+ // ML99_listFromSeq
+ {
+ ML99_ASSERT(ML99_isNil(ML99_listFromSeq(ML99_empty())));
+ ML99_ASSERT(CMP_NATURALS(ML99_listFromSeq(v((1))), ML99_list(v(1))));
+ ML99_ASSERT(CMP_NATURALS(ML99_listFromSeq(v((1)(2))), ML99_list(v(1, 2))));
+ ML99_ASSERT(CMP_NATURALS(ML99_listFromSeq(v((1)(2)(3))), ML99_list(v(1, 2, 3))));
+ }
+
+ // ML99_listHead
+ {
+ ML99_ASSERT_EQ(ML99_listHead(ML99_list(v(1))), v(1));
+ ML99_ASSERT_EQ(ML99_listHead(ML99_list(v(1, 2))), v(1));
+ ML99_ASSERT_EQ(ML99_listHead(ML99_list(v(1, 2, 3))), v(1));
+ }
+
+ // ML99_listTail
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_listTail(ML99_list(v(1))), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(ML99_listTail(ML99_list(v(1, 2))), ML99_list(v(2))));
+ ML99_ASSERT(CMP_NATURALS(ML99_listTail(ML99_list(v(1, 2, 3))), ML99_list(v(2, 3))));
+ }
+
+ // ML99_listLast
+ {
+ ML99_ASSERT_EQ(ML99_listLast(ML99_list(v(1))), v(1));
+ ML99_ASSERT_EQ(ML99_listLast(ML99_list(v(1, 2))), v(2));
+ ML99_ASSERT_EQ(ML99_listLast(ML99_list(v(1, 2, 3))), v(3));
+ }
+
+ // ML99_listInit
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_listInit(ML99_list(v(1))), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(ML99_listInit(ML99_list(v(1, 2))), ML99_list(v(1))));
+ ML99_ASSERT(CMP_NATURALS(ML99_listInit(ML99_list(v(1, 2, 3))), ML99_list(v(1, 2))));
+ }
+
+ // ML99_listLen
+ {
+ ML99_ASSERT_EQ(ML99_listLen(ML99_nil()), v(0));
+ ML99_ASSERT_EQ(ML99_listLen(ML99_list(v(123))), v(1));
+ ML99_ASSERT_EQ(ML99_listLen(ML99_list(v(123, 222))), v(2));
+ ML99_ASSERT_EQ(ML99_listLen(ML99_list(v(123, 222, 18))), v(3));
+ }
+
+ // ML99_listAppend
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_listAppend(ML99_nil(), ML99_nil()), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listAppend(ML99_nil(), ML99_list(v(1, 2, 3))),
+ ML99_list(v(1, 2, 3))));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listAppend(ML99_list(v(1, 2, 3)), ML99_nil()),
+ ML99_list(v(1, 2, 3))));
+
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listAppend(ML99_list(v(1, 2, 3)), ML99_list(v(4, 5, 6))),
+ ML99_list(v(1, 2, 3, 4, 5, 6))));
+ }
+
+ // ML99_listAppendItem
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_listAppendItem(v(123), ML99_nil()), ML99_list(v(123))));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listAppendItem(v(222), ML99_list(v(1, 2, 3))),
+ ML99_list(v(1, 2, 3, 222))));
+ }
+
+ // ML99_listReverse
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_listReverse(ML99_nil()), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(ML99_listReverse(ML99_list(v(1, 2, 3))), ML99_list(v(3, 2, 1))));
+ }
+
+ // ML99_listContains
+ {
+ ML99_ASSERT(ML99_not(ML99_listContains(v(ML99_natEq), v(1), ML99_nil())));
+ ML99_ASSERT(ML99_listContains(v(ML99_natEq), v(1), ML99_list(v(1, 2, 3))));
+ ML99_ASSERT(ML99_listContains(v(ML99_natEq), v(2), ML99_list(v(1, 2, 3))));
+ ML99_ASSERT(ML99_listContains(v(ML99_natEq), v(3), ML99_list(v(1, 2, 3))));
+ ML99_ASSERT(ML99_not(ML99_listContains(v(ML99_natEq), v(187), ML99_list(v(1, 2, 3)))));
+ }
+
+ // ML99_listUnwrap
+ {
+ ML99_ASSERT_EMPTY(ML99_listUnwrap(ML99_nil()));
+ ML99_ASSERT_EQ(ML99_listUnwrap(ML99_list(v(18, +, 3, +, 6))), v(18 + 3 + 6));
+ }
+
+ // ML99_LIST_EVAL
+ {
+ ML99_ASSERT_EMPTY_UNEVAL(ML99_LIST_EVAL(ML99_nil()));
+ ML99_ASSERT_UNEVAL(ML99_LIST_EVAL(ML99_list(v(19, +, 6))) == 19 + 6);
+ }
+
+#define CHECK(a, b, c) ML99_ASSERT_UNEVAL(a == 1 && b == 2 && c == 3)
+#define CHECK_EXPAND(args) CHECK(args)
+
+ // ML99_listUnwrapCommaSep
+ {
+ ML99_ASSERT_EMPTY(ML99_listUnwrapCommaSep(ML99_nil()));
+ CHECK_EXPAND(ML99_EVAL(ML99_listUnwrapCommaSep(ML99_list(v(1, 2, 3)))));
+ }
+
+ // ML99_LIST_EVAL_COMMA_SEP
+ {
+ ML99_ASSERT_EMPTY_UNEVAL(ML99_LIST_EVAL_COMMA_SEP(ML99_nil()));
+ CHECK_EXPAND(ML99_EVAL(v(ML99_LIST_EVAL_COMMA_SEP(ML99_list(v(1, 2, 3))))));
+ }
+
+#undef CHECK
+#undef CHECK_EXPAND
+
+ // ML99_isNil
+ {
+ ML99_ASSERT(ML99_isNil(ML99_nil()));
+ ML99_ASSERT(ML99_not(ML99_isNil(ML99_list(v(123)))));
+ ML99_ASSERT(ML99_not(ML99_isNil(ML99_list(v(8, 214, 10, 0, 122)))));
+ }
+
+ // ML99_IS_NIL
+ {
+ ML99_ASSERT_UNEVAL(ML99_IS_NIL(ML99_NIL()));
+ ML99_ASSERT_UNEVAL(ML99_NOT(ML99_IS_NIL(ML99_CONS(123, ML99_NIL()))));
+ ML99_ASSERT_UNEVAL(ML99_NOT(ML99_IS_NIL(ML99_EVAL(ML99_list(v(8, 214, 10, 0, 122))))));
+ }
+
+ // ML99_isCons
+ {
+ ML99_ASSERT(ML99_not(ML99_isCons(ML99_nil())));
+ ML99_ASSERT(ML99_isCons(ML99_list(v(123))));
+ ML99_ASSERT(ML99_isCons(ML99_list(v(8, 214, 10, 0, 122))));
+ }
+
+ // ML99_IS_CONS
+ {
+ ML99_ASSERT_UNEVAL(ML99_NOT(ML99_IS_CONS(ML99_NIL())));
+ ML99_ASSERT_UNEVAL(ML99_IS_CONS(ML99_CONS(123, ML99_NIL())));
+ ML99_ASSERT_UNEVAL(ML99_IS_CONS(ML99_EVAL(ML99_list(v(8, 214, 10, 0, 122)))));
+ }
+
+ // ML99_listGet
+ {
+ ML99_ASSERT_EQ(ML99_listGet(v(0), ML99_list(v(123, 222))), v(123));
+ ML99_ASSERT_EQ(ML99_listGet(v(1), ML99_list(v(123, 222))), v(222));
+ }
+
+ // ML99_listTake
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_listTake(v(1), ML99_nil()), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(ML99_listTake(v(200), ML99_nil()), ML99_nil()));
+
+ ML99_ASSERT(CMP_NATURALS(ML99_listTake(v(1), ML99_list(v(1, 2, 3))), ML99_list(v(1))));
+ ML99_ASSERT(CMP_NATURALS(ML99_listTake(v(2), ML99_list(v(1, 2, 3))), ML99_list(v(1, 2))));
+ ML99_ASSERT(
+ CMP_NATURALS(ML99_listTake(v(3), ML99_list(v(1, 2, 3))), ML99_list(v(1, 2, 3))));
+ }
+
+ // ML99_listTakeWhile
+ {
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listTakeWhile(ML99_appl(v(ML99_lesser), v(5)), ML99_nil()),
+ ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listTakeWhile(ML99_appl(v(ML99_greater), v(5)), ML99_list(v(7))),
+ ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listTakeWhile(ML99_appl(v(ML99_greater), v(5)), ML99_list(v(1, 9, 7))),
+ ML99_list(v(1))));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listTakeWhile(ML99_appl(v(ML99_greater), v(5)), ML99_list(v(4, 9, 2, 3))),
+ ML99_list(v(4))));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listTakeWhile(ML99_appl(v(ML99_greater), v(5)), ML99_list(v(2, 4, 7, 9, 28))),
+ ML99_list(v(2, 4))));
+ }
+
+ // ML99_listDrop
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_listDrop(v(1), ML99_nil()), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(ML99_listDrop(v(200), ML99_nil()), ML99_nil()));
+
+ ML99_ASSERT(CMP_NATURALS(ML99_listDrop(v(1), ML99_list(v(1, 2, 3))), ML99_list(v(2, 3))));
+ ML99_ASSERT(CMP_NATURALS(ML99_listDrop(v(2), ML99_list(v(1, 2, 3))), ML99_list(v(3))));
+ ML99_ASSERT(CMP_NATURALS(ML99_listDrop(v(3), ML99_list(v(1, 2, 3))), ML99_nil()));
+ }
+
+ // ML99_listDropWhile
+ {
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listDropWhile(ML99_appl(v(ML99_lesser), v(5)), ML99_nil()),
+ ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listDropWhile(ML99_appl(v(ML99_greater), v(5)), ML99_list(v(7))),
+ ML99_list(v(7))));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listDropWhile(ML99_appl(v(ML99_greater), v(5)), ML99_list(v(1, 9, 7))),
+ ML99_list(v(9, 7))));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listDropWhile(ML99_appl(v(ML99_greater), v(5)), ML99_list(v(4, 9, 2, 3))),
+ ML99_list(v(9, 2, 3))));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listDropWhile(ML99_appl(v(ML99_greater), v(5)), ML99_list(v(2, 4, 7, 9, 28))),
+ ML99_list(v(7, 9, 28))));
+ }
+
+#define EQ_IMPL(x, y) \
+ v(ML99_AND( \
+ ML99_NAT_EQ(ML99_TUPLE_GET(0)(x), ML99_TUPLE_GET(0)(y)), \
+ ML99_NAT_EQ(ML99_TUPLE_GET(1)(x), ML99_TUPLE_GET(1)(y))))
+#define EQ_ARITY 2
+
+ // ML99_listZip
+ {
+ ML99_ASSERT(ML99_listEq(v(EQ), ML99_listZip(ML99_nil(), ML99_nil()), ML99_nil()));
+ ML99_ASSERT(
+ ML99_listEq(v(EQ), ML99_listZip(ML99_list(v(1, 2, 3)), ML99_nil()), ML99_nil()));
+ ML99_ASSERT(
+ ML99_listEq(v(EQ), ML99_listZip(ML99_nil(), ML99_list(v(1, 2, 3))), ML99_nil()));
+
+ ML99_ASSERT(ML99_listEq(
+ v(EQ),
+ ML99_listZip(ML99_list(v(1, 2, 3)), ML99_list(v(4, 5, 6))),
+ ML99_list(ML99_tuple(v(1, 4)), ML99_tuple(v(2, 5)), ML99_tuple(v(3, 6)))));
+
+ ML99_ASSERT(ML99_listEq(
+ v(EQ),
+ ML99_listZip(ML99_list(v(1, 2, 3)), ML99_list(v(4, 5))),
+ ML99_list(ML99_tuple(v(1, 4)), ML99_tuple(v(2, 5)))));
+
+ ML99_ASSERT(ML99_listEq(
+ v(EQ),
+ ML99_listZip(ML99_list(v(1, 2)), ML99_list(v(4, 5, 6))),
+ ML99_list(ML99_tuple(v(1, 4)), ML99_tuple(v(2, 5)))));
+ }
+
+#undef EQ_IMPL
+#undef EQ_ARITY
+
+ // ML99_listUnzip & ML99_listZip
+ {
+#define UNZIPPED ML99_listUnzip(ML99_nil())
+
+ ML99_ASSERT(CMP_NATURALS(ML99_tupleGet(0)(UNZIPPED), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(ML99_tupleGet(1)(UNZIPPED), ML99_nil()));
+
+#undef UNZIPPED
+
+#define UNZIPPED ML99_listUnzip(ML99_listZip(ML99_list(v(1, 2)), ML99_list(v(4, 5))))
+
+ ML99_ASSERT(CMP_NATURALS(ML99_tupleGet(0)(UNZIPPED), ML99_list(v(1, 2))));
+ ML99_ASSERT(CMP_NATURALS(ML99_tupleGet(1)(UNZIPPED), ML99_list(v(4, 5))));
+
+#undef UNZIPPED
+ }
+
+ // ML99_listEq
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_nil(), ML99_nil()));
+ ML99_ASSERT(ML99_not(CMP_NATURALS(ML99_nil(), ML99_list(v(25, 88, 1)))));
+ ML99_ASSERT(ML99_not(CMP_NATURALS(ML99_list(v(25, 88, 1)), ML99_nil())));
+
+ ML99_ASSERT(CMP_NATURALS(ML99_list(v(1, 2, 3)), ML99_list(v(1, 2, 3))));
+ ML99_ASSERT(ML99_not(CMP_NATURALS(ML99_list(v(1, 2, 3)), ML99_list(v(1)))));
+ ML99_ASSERT(ML99_not(CMP_NATURALS(ML99_list(v(1)), ML99_list(v(1, 2, 3)))));
+ ML99_ASSERT(ML99_not(CMP_NATURALS(ML99_list(v(0, 5, 6, 6)), ML99_list(v(6, 7)))));
+ }
+
+ // ML99_listAppl
+ {
+ ML99_ASSERT_EQ(ML99_call(ML99_listAppl(v(ML99_add), ML99_nil()), v(6, 9)), v(6 + 9));
+ ML99_ASSERT_EQ(ML99_appl(ML99_listAppl(v(ML99_add), ML99_list(v(6))), v(9)), v(6 + 9));
+ ML99_ASSERT_EQ(ML99_listAppl(v(ML99_add), ML99_list(v(6, 9))), v(6 + 9));
+ }
+
+ // ML99_listPrependToAll
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_listPrependToAll(v(+), ML99_nil()), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listPrependToAll(v(111), ML99_list(v(5, 9, 22))),
+ ML99_list(v(111, 5, 111, 9, 111, 22))));
+ }
+
+ // ML99_listIntersperse
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_listIntersperse(v(+), ML99_nil()), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listIntersperse(v(111), ML99_list(v(5, 9, 22))),
+ ML99_list(v(5, 111, 9, 111, 22))));
+ }
+
+#define ABCDEFG ML99_TRUE()
+
+ // ML99_listFoldr
+ {
+ ML99_ASSERT_EQ(ML99_listFoldr(v(ML99_cat), v(7), ML99_nil()), v(7));
+ ML99_ASSERT(
+ ML99_listFoldr(ML99_appl(v(ML99_flip), v(ML99_cat)), v(A), ML99_list(v(G, DEF, BC))));
+ }
+
+ // ML99_listFoldl
+ {
+ ML99_ASSERT_EQ(ML99_listFoldl(v(ML99_cat), v(7), ML99_nil()), v(7));
+ ML99_ASSERT(ML99_listFoldl(v(ML99_cat), v(A), ML99_list(v(BC, DEF, G))));
+ }
+
+ // ML99_listFoldl1
+ { ML99_ASSERT(ML99_listFoldl1(v(ML99_cat), ML99_list(v(AB, CDEF, G)))); }
+
+#undef ABCDEFG
+
+ // ML99_listMap
+ {
+ ML99_ASSERT(
+ CMP_NATURALS(ML99_listMap(ML99_appl(v(ML99_add), v(3)), ML99_nil()), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listMap(ML99_appl(v(ML99_add), v(3)), ML99_list(v(1, 2, 3))),
+ ML99_list(v(4, 5, 6))));
+ }
+
+#define A0 19
+#define B1 6
+#define C2 11
+
+ // ML99_listMapI
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_listMapI(v(ML99_cat), ML99_nil()), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listMapI(v(ML99_cat), ML99_list(v(A, B, C))),
+ ML99_list(v(19, 6, 11))));
+ }
+
+#undef A0
+#undef B1
+#undef C2
+
+#define FOO_x
+#define FOO_y
+#define FOO_z
+
+ // ML99_listMapInPlace
+ {
+ ML99_ASSERT_EMPTY(ML99_listMapInPlace(v(NonExistingF), ML99_nil()));
+ ML99_EVAL(ML99_listMapInPlace(ML99_appl(v(ML99_cat), v(FOO_)), ML99_list(v(x, y, z))))
+ }
+
+#undef FOO_x
+#undef FOO_y
+#undef FOO_z
+
+#define FOO_x0
+#define FOO_y1
+#define FOO_z2
+
+#define MY_CAT_IMPL(x, i) v(FOO_##x##i)
+#define MY_CAT_ARITY 2
+
+ // ML99_listMapInPlaceI
+ {
+ ML99_ASSERT_EMPTY(ML99_listMapInPlaceI(v(NonExistingF), ML99_nil()));
+ ML99_EVAL(ML99_listMapInPlaceI(v(MY_CAT), ML99_list(v(x, y, z))))
+ }
+
+#undef MY_CAT_IMPL
+#undef MY_CAT_ARITY
+
+#undef FOO_x
+#undef FOO_y
+#undef FOO_z
+
+ // ML99_listFor
+ {
+ ML99_ASSERT(
+ CMP_NATURALS(ML99_listFor(ML99_nil(), ML99_appl(v(ML99_add), v(3))), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listFor(ML99_list(v(1, 2, 3)), ML99_appl(v(ML99_add), v(3))),
+ ML99_list(v(4, 5, 6))));
+ }
+
+ // ML99_listMapInitLast
+ {
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listMapInitLast(
+ ML99_appl(v(ML99_add), v(3)),
+ ML99_appl(v(ML99_add), v(19)),
+ ML99_list(v(4))),
+ ML99_list(v(23))));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listMapInitLast(
+ ML99_appl(v(ML99_add), v(3)),
+ ML99_appl(v(ML99_add), v(7)),
+ ML99_list(v(1, 2, 3))),
+ ML99_list(v(4, 5, 10))));
+ }
+
+ // ML99_listForInitLast
+ {
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listForInitLast(
+ ML99_list(v(4)),
+ ML99_appl(v(ML99_add), v(3)),
+ ML99_appl(v(ML99_add), v(19))),
+ ML99_list(v(23))));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listForInitLast(
+ ML99_list(v(1, 2, 3)),
+ ML99_appl(v(ML99_add), v(3)),
+ ML99_appl(v(ML99_add), v(7))),
+ ML99_list(v(4, 5, 10))));
+ }
+
+ // ML99_listFilter
+ {
+ ML99_ASSERT(
+ CMP_NATURALS(ML99_listFilter(ML99_appl(v(ML99_add), v(3)), ML99_nil()), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(
+ ML99_listFilter(ML99_appl(v(ML99_lesser), v(3)), ML99_list(v(14, 0, 1, 7, 2, 65, 3))),
+ ML99_list(v(14, 7, 65))));
+ }
+
+ // ML99_listFilterMap
+ {
+#define LIST ML99_list(v(5, 7, 3, 12))
+
+#define F_IMPL(x) ML99_if(ML99_lesserEq(v(x), v(5)), ML99_just(v(x)), ML99_nothing())
+#define F_ARITY 1
+
+ ML99_ASSERT(CMP_NATURALS(ML99_listFilterMap(v(F), LIST), ML99_list(v(5, 3))));
+
+#undef F_IMPL
+#undef F_ARITY
+
+#undef LIST
+ }
+
+ // ML99_listReplicate
+ {
+ ML99_ASSERT(CMP_NATURALS(ML99_listReplicate(v(0), v(~)), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(ML99_listReplicate(v(3), v(7)), ML99_list(v(7, 7, 7))));
+ }
+
+ // ML99_listPartition
+ {
+
+ // Partitioning ML99_nil()
+ {
+#define PARTITIONED ML99_listPartition(ML99_appl(v(ML99_greater), v(10)), ML99_nil())
+
+ ML99_ASSERT(CMP_NATURALS(ML99_tupleGet(0)(PARTITIONED), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(ML99_tupleGet(1)(PARTITIONED), ML99_nil()));
+
+#undef PARTITIONED
+ }
+
+ // Only the second list contains items
+ {
+#define PARTITIONED ML99_listPartition(ML99_appl(v(ML99_greater), v(10)), ML99_list(v(11, 12, 13)))
+
+ ML99_ASSERT(CMP_NATURALS(ML99_tupleGet(0)(PARTITIONED), ML99_nil()));
+ ML99_ASSERT(CMP_NATURALS(ML99_tupleGet(1)(PARTITIONED), ML99_list(v(11, 12, 13))));
+
+#undef PARTITIONED
+ }
+
+ // Only the first list contains items
+ {
+#define PARTITIONED ML99_listPartition(ML99_appl(v(ML99_greater), v(10)), ML99_list(v(4, 7)))
+
+ ML99_ASSERT(CMP_NATURALS(ML99_tupleGet(0)(PARTITIONED), ML99_list(v(4, 7))));
+ ML99_ASSERT(CMP_NATURALS(ML99_tupleGet(1)(PARTITIONED), ML99_nil()));
+
+#undef PARTITIONED
+ }
+
+ // Both lists contain items
+ {
+#define PARTITIONED \
+ ML99_listPartition(ML99_appl(v(ML99_greater), v(10)), ML99_list(v(11, 4, 12, 13, 7)))
+
+ ML99_ASSERT(CMP_NATURALS(ML99_tupleGet(0)(PARTITIONED), ML99_list(v(4, 7))));
+ ML99_ASSERT(CMP_NATURALS(ML99_tupleGet(1)(PARTITIONED), ML99_list(v(11, 12, 13))));
+
+#undef PARTITIONED
+ }
+ }
+}
diff --git a/test/external/metalang99/tests/maybe.c b/test/external/metalang99/tests/maybe.c
new file mode 100644
index 0000000..f8b169b
--- /dev/null
+++ b/test/external/metalang99/tests/maybe.c
@@ -0,0 +1,58 @@
+#include <metalang99/assert.h>
+#include <metalang99/maybe.h>
+#include <metalang99/nat.h>
+
+int main(void) {
+
+#define MATCH_IMPL(maybe) ML99_match(v(maybe), v(MATCH_))
+#define MATCH_just_IMPL(x) v(ML99_ASSERT_UNEVAL(x == 87))
+#define MATCH_nothing_IMPL(_) v(ML99_ASSERT_UNEVAL(1))
+
+ // Pattern matching
+ {
+ ML99_EVAL(ML99_call(MATCH, ML99_just(v(87))));
+ ML99_EVAL(ML99_call(MATCH, ML99_nothing(~, ~, ~)));
+ }
+
+#undef MATCH_IMPL
+#undef MATCH_just_IMPL
+#undef MATCH_nothing_IMPL
+
+#define VAL v(abc ? +-148 % "hello world")
+
+ // ML99_isJust
+ {
+ ML99_ASSERT(ML99_isJust(ML99_just(VAL)));
+ ML99_ASSERT(ML99_not(ML99_isJust(ML99_nothing())));
+ }
+
+ // ML99_IS_JUST
+ {
+ ML99_ASSERT_UNEVAL(ML99_IS_JUST(ML99_JUST(VAL)));
+ ML99_ASSERT_UNEVAL(!ML99_IS_JUST(ML99_NOTHING()));
+ }
+
+ // ML99_isNothing
+ {
+ ML99_ASSERT(ML99_isNothing(ML99_nothing()));
+ ML99_ASSERT(ML99_not(ML99_isNothing(ML99_just(VAL))));
+ }
+
+ // ML99_IS_NOTHING
+ {
+ ML99_ASSERT_UNEVAL(ML99_IS_NOTHING(ML99_NOTHING()));
+ ML99_ASSERT_UNEVAL(!ML99_IS_NOTHING(ML99_JUST(VAL)));
+ }
+
+ // ML99_maybeEq
+ {
+ ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_just(v(123)), ML99_just(v(123))));
+
+ ML99_ASSERT(ML99_not(ML99_maybeEq(v(ML99_natEq), ML99_just(v(123)), ML99_just(v(4)))));
+ ML99_ASSERT(ML99_not(ML99_maybeEq(v(ML99_natEq), ML99_just(v(123)), ML99_nothing())));
+ ML99_ASSERT(ML99_not(ML99_maybeEq(v(ML99_natEq), ML99_nothing(), ML99_just(v(123)))));
+ }
+
+ // ML99_maybeUnwrap
+ { ML99_ASSERT_EQ(ML99_maybeUnwrap(ML99_just(v(123))), v(123)); }
+}
diff --git a/test/external/metalang99/tests/metalang99.c b/test/external/metalang99/tests/metalang99.c
new file mode 100644
index 0000000..b469885
--- /dev/null
+++ b/test/external/metalang99/tests/metalang99.c
@@ -0,0 +1,51 @@
+#include <metalang99.h>
+#include <metalang99/assert.h>
+
+int main(void) {
+
+#undef ML99_MAJOR
+#undef ML99_MINOR
+#undef ML99_PATCH
+
+#define ML99_MAJOR 1
+#define ML99_MINOR 2
+#define ML99_PATCH 3
+
+ // ML99_VERSION_COMPATIBLE
+ {
+
+ ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 0, 0));
+ ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 1, 0));
+ ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 1, 1));
+
+ ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 2, 0));
+ ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 2, 1));
+ ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 2, 2));
+ ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 2, 3));
+
+ // Major-incompatible.
+ ML99_ASSERT_UNEVAL(!ML99_VERSION_COMPATIBLE(2, 0, 0));
+ ML99_ASSERT_UNEVAL(!ML99_VERSION_COMPATIBLE(7, 1, 2));
+
+ // Minor-incompatible.
+ ML99_ASSERT_UNEVAL(!ML99_VERSION_COMPATIBLE(1, 3, 0));
+ ML99_ASSERT_UNEVAL(!ML99_VERSION_COMPATIBLE(1, 4, 9));
+
+ // Patch-incompatible.
+ ML99_ASSERT_UNEVAL(!ML99_VERSION_COMPATIBLE(1, 2, 4));
+ ML99_ASSERT_UNEVAL(!ML99_VERSION_COMPATIBLE(1, 2, 5));
+ }
+
+ // ML99_VERSION_EQ
+ {
+ ML99_ASSERT_UNEVAL(ML99_VERSION_EQ(1, 2, 3));
+
+ ML99_ASSERT_UNEVAL(!ML99_VERSION_EQ(1, 2, 7));
+ ML99_ASSERT_UNEVAL(!ML99_VERSION_EQ(1, 7, 3));
+ ML99_ASSERT_UNEVAL(!ML99_VERSION_EQ(7, 2, 3));
+ }
+
+#undef ML99_MAJOR
+#undef ML99_MINOR
+#undef ML99_PATCH
+}
diff --git a/test/external/metalang99/tests/nat.c b/test/external/metalang99/tests/nat.c
new file mode 100644
index 0000000..0509d8e
--- /dev/null
+++ b/test/external/metalang99/tests/nat.c
@@ -0,0 +1,260 @@
+// `...` is sometimes used to workaround a TCC bug, see
+// <https://github.com/hirrolot/datatype99/issues/10#issuecomment-830813172>.
+
+#include <metalang99/assert.h>
+#include <metalang99/nat.h>
+
+int main(void) {
+
+#define MATCH_Z_IMPL(...) v(88) // `...` due to the TCC's bug.
+#define MATCH_S_IMPL(x) v(x)
+
+ // ML99_natMatch
+ {
+ ML99_ASSERT_EQ(ML99_natMatch(v(0), v(MATCH_)), v(88));
+ ML99_ASSERT_EQ(ML99_natMatch(v(123), v(MATCH_)), v(122));
+ }
+
+#undef MATCH_Z_IMPL
+#undef MATCH_S_IMPL
+
+#define MATCH_Z_IMPL(x, y, z) v(ML99_ASSERT_UNEVAL(x == 1 && y == 2 && z == 3))
+#define MATCH_S_IMPL(n, x, y, z) v(ML99_ASSERT_UNEVAL(n == 122 && x == 1 && y == 2 && z == 3))
+
+ // ML99_natMatchWithArgs
+ {
+ ML99_EVAL(ML99_natMatchWithArgs(v(0), v(MATCH_), v(1, 2, 3)));
+ ML99_EVAL(ML99_natMatchWithArgs(v(123), v(MATCH_), v(1, 2, 3)));
+ }
+
+#undef MATCH_Z_IMPL
+#undef MATCH_S_IMPL
+
+ // ML99_inc
+ {
+ ML99_ASSERT_EQ(ML99_inc(v(0)), v(1));
+ ML99_ASSERT_EQ(ML99_inc(v(15)), v(16));
+ ML99_ASSERT_EQ(ML99_inc(v(198)), v(199));
+ ML99_ASSERT_EQ(ML99_inc(v(254)), v(ML99_NAT_MAX));
+ ML99_ASSERT_EQ(ML99_inc(v(ML99_NAT_MAX)), v(0));
+ }
+
+ // ML99_INC
+ {
+ ML99_ASSERT_UNEVAL(ML99_INC(0) == 1);
+ ML99_ASSERT_UNEVAL(ML99_INC(15) == 16);
+ ML99_ASSERT_UNEVAL(ML99_INC(254) == ML99_NAT_MAX);
+ }
+
+ // ML99_dec
+ {
+ ML99_ASSERT_EQ(ML99_dec(v(0)), v(ML99_NAT_MAX));
+ ML99_ASSERT_EQ(ML99_dec(v(1)), v(0));
+ ML99_ASSERT_EQ(ML99_dec(v(71)), v(70));
+ ML99_ASSERT_EQ(ML99_dec(v(201)), v(200));
+ ML99_ASSERT_EQ(ML99_dec(v(ML99_NAT_MAX)), v(254));
+ }
+
+ // ML99_DEC
+ {
+ ML99_ASSERT_UNEVAL(ML99_DEC(0) == ML99_NAT_MAX);
+ ML99_ASSERT_UNEVAL(ML99_DEC(1) == 0);
+ ML99_ASSERT_UNEVAL(ML99_DEC(ML99_NAT_MAX) == 254);
+ }
+
+ // ML99_natEq
+ {
+ ML99_ASSERT(ML99_natEq(v(0), v(0)));
+ ML99_ASSERT(ML99_natEq(v(18), v(18)));
+ ML99_ASSERT(ML99_natEq(v(183), v(183)));
+ ML99_ASSERT(ML99_natEq(v(ML99_NAT_MAX), v(ML99_NAT_MAX)));
+
+ ML99_ASSERT(ML99_not(ML99_natEq(v(0), v(1))));
+ ML99_ASSERT(ML99_not(ML99_natEq(v(198), v(91))));
+ }
+
+ // ML99_NAT_EQ
+ {
+ ML99_ASSERT_UNEVAL(ML99_NAT_EQ(18, 18));
+ ML99_ASSERT_UNEVAL(!ML99_NAT_EQ(198, 91));
+ }
+
+ // ML99_natNeq
+ {
+ ML99_ASSERT(ML99_natNeq(v(0), v(1)));
+ ML99_ASSERT(ML99_natNeq(v(0), v(168)));
+ ML99_ASSERT(ML99_natNeq(v(1), v(34)));
+ ML99_ASSERT(ML99_natNeq(v(184), v(381)));
+ ML99_ASSERT(ML99_natNeq(v(3), v(101)));
+
+ ML99_ASSERT(ML99_not(ML99_natNeq(v(0), v(0))));
+ ML99_ASSERT(ML99_not(ML99_natNeq(v(101), v(101))));
+ }
+
+ // ML99_NAT_NEQ
+ {
+ ML99_ASSERT_UNEVAL(ML99_NAT_NEQ(0, 168));
+ ML99_ASSERT_UNEVAL(!ML99_NAT_NEQ(101, 101));
+ }
+
+ // ML99_greater
+ {
+ ML99_ASSERT(ML99_greater(v(1), v(0)));
+ ML99_ASSERT(ML99_greater(v(ML99_NAT_MAX), v(0)));
+ ML99_ASSERT(ML99_greater(v(5), v(4)));
+ ML99_ASSERT(ML99_greater(v(147), v(80)));
+ ML99_ASSERT(ML99_greater(v(217), v(209)));
+
+ ML99_ASSERT(ML99_not(ML99_greater(v(0), v(13))));
+ ML99_ASSERT(ML99_not(ML99_greater(v(17), v(120))));
+ }
+
+ // ML99_lesser
+ {
+ ML99_ASSERT(ML99_lesser(v(0), v(1)));
+ ML99_ASSERT(ML99_lesser(v(0), v(ML99_NAT_MAX)));
+ ML99_ASSERT(ML99_lesser(v(19), v(25)));
+ ML99_ASSERT(ML99_lesser(v(109), v(110)));
+ ML99_ASSERT(ML99_lesser(v(10), v(208)));
+
+ ML99_ASSERT(ML99_not(ML99_lesser(v(12), v(0))));
+ ML99_ASSERT(ML99_not(ML99_lesser(v(123), v(123))));
+ }
+
+ // ML99_greaterEq
+ {
+ ML99_ASSERT(ML99_greaterEq(v(0), v(0)));
+ ML99_ASSERT(ML99_greaterEq(v(18), v(18)));
+ ML99_ASSERT(ML99_greaterEq(v(175), v(175)));
+ ML99_ASSERT(ML99_greaterEq(v(ML99_NAT_MAX), v(ML99_NAT_MAX)));
+
+ ML99_ASSERT(ML99_greaterEq(v(1), v(0)));
+ ML99_ASSERT(ML99_greaterEq(v(ML99_NAT_MAX), v(0)));
+ ML99_ASSERT(ML99_greaterEq(v(19), v(10)));
+ ML99_ASSERT(ML99_greaterEq(v(178), v(177)));
+
+ ML99_ASSERT(ML99_not(ML99_greaterEq(v(0), v(7))));
+ ML99_ASSERT(ML99_not(ML99_greaterEq(v(1), v(19))));
+ }
+
+ // ML99_lesserEq
+ {
+ ML99_ASSERT(ML99_lesserEq(v(0), v(0)));
+ ML99_ASSERT(ML99_lesserEq(v(2), v(2)));
+ ML99_ASSERT(ML99_lesserEq(v(1), v(1)));
+ ML99_ASSERT(ML99_lesserEq(v(25), v(25)));
+ ML99_ASSERT(ML99_lesserEq(v(198), v(198)));
+
+ ML99_ASSERT(ML99_lesserEq(v(0), v(1)));
+ ML99_ASSERT(ML99_lesserEq(v(0), v(ML99_NAT_MAX)));
+ ML99_ASSERT(ML99_lesserEq(v(18), v(27)));
+ ML99_ASSERT(ML99_lesserEq(v(82), v(90)));
+ ML99_ASSERT(ML99_lesserEq(v(145), v(146)));
+ ML99_ASSERT(ML99_lesserEq(v(181), v(ML99_NAT_MAX)));
+
+ ML99_ASSERT(ML99_not(ML99_lesserEq(v(7), v(0))));
+ ML99_ASSERT(ML99_not(ML99_lesserEq(v(182), v(181))));
+ }
+
+ // ML99_add
+ {
+ ML99_ASSERT_EQ(ML99_add(v(0), v(0)), v(0));
+ ML99_ASSERT_EQ(ML99_add(v(19), v(83)), v(19 + 83));
+ ML99_ASSERT_EQ(ML99_add(v(8), v(4)), v(8 + 4));
+ ML99_ASSERT_EQ(ML99_add(v(1), v(254)), v(1 + 254));
+ }
+
+ // ML99_sub
+ {
+ ML99_ASSERT_EQ(ML99_sub(v(1), v(1)), v(1 - 1));
+ ML99_ASSERT_EQ(ML99_sub(v(5), v(3)), v(5 - 3));
+ ML99_ASSERT_EQ(ML99_sub(v(105), v(19)), v(105 - 19));
+ ML99_ASSERT_EQ(ML99_sub(v(ML99_NAT_MAX), v(40)), v(ML99_NAT_MAX - 40));
+ }
+
+ // ML99_mul
+ {
+ ML99_ASSERT_EQ(ML99_mul(v(11), v(0)), v(0));
+ ML99_ASSERT_EQ(ML99_mul(v(0), v(11)), v(0));
+ ML99_ASSERT_EQ(ML99_mul(v(15), v(8)), v(15 * 8));
+ ML99_ASSERT_EQ(ML99_mul(v(ML99_NAT_MAX), v(1)), v(ML99_NAT_MAX * 1));
+ }
+
+ // ML99_div
+ {
+ ML99_ASSERT_EQ(ML99_div(v(15), v(1)), v(15));
+ ML99_ASSERT_EQ(ML99_div(v(15), v(15)), v(1));
+ ML99_ASSERT_EQ(ML99_div(v(45), v(3)), v(45 / 3));
+ ML99_ASSERT_EQ(ML99_div(v(ML99_NAT_MAX), v(5)), v(ML99_NAT_MAX / 5));
+ }
+
+ // ML99_divChecked
+ {
+ ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(15), v(1)), ML99_just(v(15))));
+ ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(15), v(15)), ML99_just(v(1))));
+ ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(45), v(3)), ML99_just(v(15))));
+ ML99_ASSERT(
+ ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(ML99_NAT_MAX), v(5)), ML99_just(v(51))));
+
+ ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(4), v(0)), ML99_nothing()));
+ ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(3), v(27)), ML99_nothing()));
+ ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(166), v(9)), ML99_nothing()));
+ ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(0), v(11)), ML99_nothing()));
+ }
+
+ // ML99_DIV_CHECKED
+ {
+ ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), v(ML99_DIV_CHECKED(15, 1)), ML99_just(v(15))));
+ ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), v(ML99_DIV_CHECKED(4, 0)), ML99_nothing()));
+ }
+
+ // ML99_mod
+ {
+ ML99_ASSERT_EQ(ML99_mod(v(0), v(1)), v(0 % 1));
+ ML99_ASSERT_EQ(ML99_mod(v(0), v(123)), v(0 % 123));
+
+ ML99_ASSERT_EQ(ML99_mod(v(1), v(28)), v(1 % 28));
+ ML99_ASSERT_EQ(ML99_mod(v(1), v(123)), v(1 % 123));
+
+ ML99_ASSERT_EQ(ML99_mod(v(1), v(1)), v(0));
+ ML99_ASSERT_EQ(ML99_mod(v(16), v(4)), v(0));
+ ML99_ASSERT_EQ(ML99_mod(v(ML99_NAT_MAX), v(ML99_NAT_MAX)), v(0));
+
+ ML99_ASSERT_EQ(ML99_mod(v(8), v(3)), v(8 % 3));
+ ML99_ASSERT_EQ(ML99_mod(v(10), v(4)), v(10 % 4));
+ ML99_ASSERT_EQ(ML99_mod(v(101), v(7)), v(101 % 7));
+
+ ML99_ASSERT_EQ(ML99_mod(v(13), v(14)), v(13 % 14));
+ ML99_ASSERT_EQ(ML99_mod(v(20), v(36)), v(20 % 36));
+ ML99_ASSERT_EQ(ML99_mod(v(16), v(ML99_NAT_MAX)), v(16 % ML99_NAT_MAX));
+ }
+
+ // ML99_add3, ML99_sub3, ML99_mul3, ML99_div3
+ {
+ ML99_ASSERT_EQ(ML99_add3(v(8), v(2), v(4)), v(8 + 2 + 4));
+ ML99_ASSERT_EQ(ML99_sub3(v(14), v(1), v(7)), v(14 - 1 - 7));
+ ML99_ASSERT_EQ(ML99_mul3(v(3), v(2), v(6)), v(3 * 2 * 6));
+ ML99_ASSERT_EQ(ML99_div3(v(30), v(2), v(3)), v(30 / 2 / 3));
+ }
+
+ // ML99_min
+ {
+ ML99_ASSERT_EQ(ML99_min(v(0), v(1)), v(0));
+ ML99_ASSERT_EQ(ML99_min(v(5), v(7)), v(5));
+ ML99_ASSERT_EQ(ML99_min(v(200), v(ML99_NAT_MAX)), v(200));
+ }
+
+ // ML99_max
+ {
+ ML99_ASSERT_EQ(ML99_max(v(0), v(1)), v(1));
+ ML99_ASSERT_EQ(ML99_max(v(5), v(7)), v(7));
+ ML99_ASSERT_EQ(ML99_max(v(200), v(ML99_NAT_MAX)), v(ML99_NAT_MAX));
+ }
+
+ // ML99_assertIsNat
+ {
+ ML99_EVAL(ML99_assertIsNat(v(0)))
+ ML99_EVAL(ML99_assertIsNat(v(13)))
+ ML99_EVAL(ML99_assertIsNat(v(255)))
+ }
+}
diff --git a/test/external/metalang99/tests/seq.c b/test/external/metalang99/tests/seq.c
new file mode 100644
index 0000000..eea6f0f
--- /dev/null
+++ b/test/external/metalang99/tests/seq.c
@@ -0,0 +1,100 @@
+#include <metalang99/assert.h>
+#include <metalang99/seq.h>
+
+int main(void) {
+
+ // ML99_seqGet
+ {
+ ML99_ASSERT_EQ(ML99_seqGet(0)(v((19))), v(19));
+ ML99_ASSERT_EQ(ML99_seqGet(0)(v((19)(8))), v(19));
+ ML99_ASSERT_EQ(ML99_seqGet(0)(v((19)(8)(7378))), v(19));
+
+ ML99_ASSERT_EQ(ML99_seqGet(1)(v((19)(8))), v(8));
+ ML99_ASSERT_EQ(ML99_seqGet(2)(v((19)(8)(7378))), v(7378));
+ ML99_ASSERT_EQ(ML99_seqGet(3)(v((19)(8)(7378)(10))), v(10));
+ ML99_ASSERT_EQ(ML99_seqGet(4)(v((19)(8)(7378)(10)(121))), v(121));
+ ML99_ASSERT_EQ(ML99_seqGet(5)(v((19)(8)(7378)(10)(121)(1))), v(1));
+ ML99_ASSERT_EQ(ML99_seqGet(6)(v((19)(8)(7378)(10)(121)(1)(80))), v(80));
+ ML99_ASSERT_EQ(ML99_seqGet(7)(v((19)(8)(7378)(10)(121)(1)(80)(23))), v(23));
+ }
+
+ // ML99_SEQ_GET
+ {
+ ML99_ASSERT_UNEVAL(ML99_SEQ_GET(0)((19)) == 19);
+ ML99_ASSERT_UNEVAL(ML99_SEQ_GET(0)((19)(8)) == 19);
+ ML99_ASSERT_UNEVAL(ML99_SEQ_GET(0)((19)(8)(7378)) == 19);
+
+ ML99_ASSERT_UNEVAL(ML99_SEQ_GET(1)((19)(8)) == 8);
+ ML99_ASSERT_UNEVAL(ML99_SEQ_GET(1)((19)(8)(7378)) == 8);
+ }
+
+#define CHECK_TAIL(a) a == 51 && CHECK_TAIL_AUX_0
+#define CHECK_TAIL_AUX_0(b) b == 3 && CHECK_TAIL_AUX_1
+#define CHECK_TAIL_AUX_1(c) c == 9
+
+ // ML99_seqTail
+ {
+ ML99_ASSERT_UNEVAL(CHECK_TAIL ML99_EVAL(ML99_seqTail(v((9191)(51)(3)(9)))));
+ ML99_ASSERT_EMPTY(ML99_seqTail(v((~, ~, ~))));
+ }
+
+ // ML99_SEQ_TAIL
+ {
+ ML99_ASSERT_UNEVAL(CHECK_TAIL ML99_SEQ_TAIL((9191)(51)(3)(9)));
+ ML99_ASSERT_EMPTY_UNEVAL(ML99_SEQ_TAIL((~, ~, ~)));
+ }
+
+#undef CHECK_TAIL
+#undef CHECK_TAIL_AUX_0
+#undef CHECK_TAIL_AUX_1
+
+ // ML99_seqIsEmpty
+ {
+ ML99_ASSERT(ML99_seqIsEmpty(v()));
+
+ ML99_ASSERT(ML99_not(ML99_seqIsEmpty(v((~, ~, ~)))));
+ ML99_ASSERT(ML99_not(ML99_seqIsEmpty(v((~)(~)))));
+ ML99_ASSERT(ML99_not(ML99_seqIsEmpty(v((~)(~)(~)))));
+ }
+
+ // ML99_SEQ_IS_EMPTY
+ {
+ ML99_ASSERT_UNEVAL(ML99_SEQ_IS_EMPTY());
+
+ ML99_ASSERT_UNEVAL(ML99_NOT(ML99_SEQ_IS_EMPTY((~, ~, ~))));
+ ML99_ASSERT_UNEVAL(ML99_NOT(ML99_SEQ_IS_EMPTY((~)(~))));
+ ML99_ASSERT_UNEVAL(ML99_NOT(ML99_SEQ_IS_EMPTY((~)(~)(~))));
+ }
+
+#define CHECK_EXPAND(...) CHECK(__VA_ARGS__)
+
+#define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 1987 && y == 2987 && z == 3987)
+#define F_IMPL(x) v(, x##987)
+#define F_ARITY 1
+
+ // ML99_seqForEach
+ {
+ ML99_ASSERT_EMPTY(ML99_seqForEach(v(F), v()));
+ CHECK_EXPAND(ML99_EVAL(ML99_seqForEach(v(F), v((1)(2)(3)))));
+ }
+
+#undef CHECK
+#undef F_IMPL
+#undef F_ARITY
+
+#define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 10 && y == 21 && z == 32)
+#define F_IMPL(i, x) v(, ), v(x##i)
+#define F_ARITY 2
+
+ // ML99_seqForEachI
+ {
+ ML99_ASSERT_EMPTY(ML99_seqForEachI(v(F), v()));
+ CHECK_EXPAND(ML99_EVAL(ML99_seqForEachI(v(F), v((1)(2)(3)))));
+ }
+
+#undef CHECK
+#undef F_IMPL
+#undef F_ARITY
+
+#undef CHECK_EXPAND
+}
diff --git a/test/external/metalang99/tests/stmt.c b/test/external/metalang99/tests/stmt.c
new file mode 100644
index 0000000..cc00b1b
--- /dev/null
+++ b/test/external/metalang99/tests/stmt.c
@@ -0,0 +1,114 @@
+#include <metalang99/stmt.h>
+
+#include <assert.h>
+
+int main(void) {
+
+ // ML99_INTRODUCE_VAR_TO_STMT
+ {
+ if (1)
+ ML99_INTRODUCE_VAR_TO_STMT(int x = 5, y = 7) {
+ assert(5 == x);
+ assert(7 == y);
+ }
+ }
+
+ // ML99_INTRODUCE_NON_NULL_PTR_TO_STMT
+ {
+ int x = 5, y = 7;
+
+ // clang-format off
+ if (1)
+ ML99_INTRODUCE_NON_NULL_PTR_TO_STMT(int, x_ptr, &x)
+ ML99_INTRODUCE_NON_NULL_PTR_TO_STMT(int, y_ptr, &y) {
+ assert(x == *x_ptr);
+ assert(y == *y_ptr);
+ }
+ // clang-format on
+ }
+
+ // ML99_CHAIN_EXPR_STMT
+ {
+ int x, y;
+
+ // clang-format off
+ if (1)
+ ML99_CHAIN_EXPR_STMT(x = 1)
+ ML99_CHAIN_EXPR_STMT(y = 2) {
+ assert(1 == x);
+ assert(2 == y);
+ }
+ // clang-format on
+
+ // Test -Wunused suppression via ML99_CHAIN_EXPR_STMT.
+ int z;
+
+ if (1)
+ ML99_CHAIN_EXPR_STMT((void)z);
+ }
+
+ // ML99_CHAIN_EXPR_STMT_AFTER
+ {
+ int x = 5, y = 7;
+
+ if (1) {
+ assert(5 == x);
+ assert(7 == y);
+
+ ML99_CHAIN_EXPR_STMT_AFTER(x = 1) {
+ assert(5 == x);
+ assert(7 == y);
+
+ ML99_CHAIN_EXPR_STMT_AFTER(y = 2) {
+ assert(5 == x);
+ assert(7 == y);
+ }
+
+ assert(5 == x);
+ assert(2 == y);
+ }
+
+ assert(1 == x);
+ assert(2 == y);
+ }
+ }
+
+ // ML99_SUPPRESS_UNUSED_BEFORE_STMT
+ {
+ int x, y;
+
+ // clang-format off
+ if (1)
+ ML99_SUPPRESS_UNUSED_BEFORE_STMT(x)
+ ML99_SUPPRESS_UNUSED_BEFORE_STMT(y)
+ ;
+ // clang-format on
+ }
+
+ // Clang-Format breaks with the following sequence of statements so they are put into a macro.
+ // clang-format off
+
+#define STMT_CHAINING \
+ ML99_INTRODUCE_VAR_TO_STMT(int x = 5) \
+ ML99_INTRODUCE_NON_NULL_PTR_TO_STMT(int, x_ptr, &x) { \
+ assert(x == *x_ptr); \
+ \
+ ML99_CHAIN_EXPR_STMT(x = 7) \
+ ML99_INTRODUCE_VAR_TO_STMT(int y = 5) \
+ ML99_SUPPRESS_UNUSED_BEFORE_STMT(y) { \
+ ML99_CHAIN_EXPR_STMT_AFTER(x = 123) { \
+ assert(7 == x); \
+ } \
+ \
+ assert(123 == x); \
+ } \
+ }
+
+ // clang-format on
+
+ { STMT_CHAINING }
+
+#undef STMT_CHAINING
+
+ return 0;
+}
diff --git a/test/external/metalang99/tests/tuple.c b/test/external/metalang99/tests/tuple.c
new file mode 100644
index 0000000..af92350
--- /dev/null
+++ b/test/external/metalang99/tests/tuple.c
@@ -0,0 +1,184 @@
+#include <metalang99/assert.h>
+#include <metalang99/tuple.h>
+
+int main(void) {
+
+#define CHECK(x, y) ML99_ASSERT_UNEVAL(x == 518 && y == 1910)
+#define CHECK_EXPAND(args) CHECK args
+
+ // ML99_tuple
+ { CHECK_EXPAND(ML99_EVAL(ML99_tuple(v(518, 1910)))); }
+
+ // ML99_TUPLE
+ { CHECK_EXPAND(ML99_TUPLE(518, 1910)); }
+
+#undef CHECK
+#undef CHECK_EXPAND
+
+ // ML99_untupleEval
+ { ML99_ASSERT_EQ(ML99_untupleEval(v((v(198)))), v(198)); }
+
+ // ML99_untuple(Checked)
+ {
+ ML99_ASSERT_EQ(ML99_untuple(v((198))), v(198));
+ ML99_ASSERT_EQ(ML99_untupleChecked(v((198))), v(198));
+ }
+
+ // ML99_UNTUPLE
+ { ML99_ASSERT_UNEVAL(ML99_UNTUPLE((198)) == 198); }
+
+ // ML99_tupleEval + ML99_untupleEval
+ { ML99_ASSERT_EQ(ML99_untupleEval(ML99_tupleEval(v(187))), v(187)); }
+
+ // ML99_tuple + ML99_untuple
+ { ML99_ASSERT_EQ(ML99_untuple(ML99_tuple(v(187))), v(187)); }
+
+ // ML99_isTuple
+ {
+ ML99_ASSERT(ML99_isTuple(v((1, 2, 3))));
+ ML99_ASSERT(ML99_not(ML99_isTuple(v(123))));
+ }
+
+ // ML99_IS_TUPLE
+ {
+ ML99_ASSERT_UNEVAL(ML99_IS_TUPLE((1, 2, 3)));
+ ML99_ASSERT_UNEVAL(!ML99_IS_TUPLE(123));
+ }
+
+ // ML99_isUntuple
+ {
+ ML99_ASSERT(ML99_not(ML99_isUntuple(v((1, 2, 3)))));
+
+ ML99_ASSERT(ML99_isUntuple(v(123)));
+ ML99_ASSERT(ML99_isUntuple(v(123())));
+ ML99_ASSERT(ML99_isUntuple(v(123(~))));
+ ML99_ASSERT(ML99_isUntuple(v(123(~, ~, ~))));
+
+ ML99_ASSERT(ML99_isUntuple(v(()())));
+ ML99_ASSERT(ML99_isUntuple(v(()() ~)));
+
+ ML99_ASSERT(ML99_isUntuple(v((~)(~))));
+ ML99_ASSERT(ML99_isUntuple(v((~)(~) ~)));
+
+ ML99_ASSERT(ML99_isUntuple(v((~, ~, ~)(~, ~, ~))));
+ ML99_ASSERT(ML99_isUntuple(v((~, ~, ~)(~, ~, ~) ~)));
+
+ ML99_ASSERT(ML99_isUntuple(v((~, ~, ~)(~, ~, ~)(~, ~, ~))));
+ ML99_ASSERT(ML99_isUntuple(v((~, ~, ~)(~, ~, ~)(~, ~, ~) ~)));
+ }
+
+ // ML99_IS_UNTUPLE
+ {
+ ML99_ASSERT_UNEVAL(!ML99_IS_UNTUPLE((1, 2, 3)));
+ ML99_ASSERT_UNEVAL(ML99_IS_UNTUPLE(123));
+ ML99_ASSERT_UNEVAL(ML99_IS_UNTUPLE((~)(~)));
+ }
+
+ // ML99_tupleCount
+ {
+ ML99_ASSERT_EQ(ML99_tupleCount(v((1, 2, 3))), v(3));
+ ML99_ASSERT_EQ(ML99_tupleCount(v((*))), v(1));
+ }
+
+ // ML99_TUPLE_COUNT
+ {
+ ML99_ASSERT_UNEVAL(ML99_TUPLE_COUNT((1, 2, 3)) == 3);
+ ML99_ASSERT_UNEVAL(ML99_TUPLE_COUNT((*)) == 1);
+ }
+
+ // ML99_tupleIsSingle
+ {
+ ML99_ASSERT(ML99_not(ML99_tupleIsSingle(v((1, 2, 3)))));
+ ML99_ASSERT(ML99_tupleIsSingle(v((*))));
+ }
+
+ // ML99_TUPLE_IS_SINGLE
+ {
+ ML99_ASSERT_UNEVAL(!ML99_TUPLE_IS_SINGLE((1, 2, 3)));
+ ML99_ASSERT_UNEVAL(ML99_TUPLE_IS_SINGLE((*)));
+ }
+
+ // ML99_tupleGet
+ {
+ ML99_ASSERT_EMPTY(ML99_tupleGet(0)(v(())));
+ ML99_ASSERT_EQ(ML99_tupleGet(0)(v((19))), v(19));
+ ML99_ASSERT_EQ(ML99_tupleGet(0)(v((19, 8))), v(19));
+ ML99_ASSERT_EQ(ML99_tupleGet(0)(v((19, 8, 7378))), v(19));
+
+ ML99_ASSERT_EQ(ML99_tupleGet(1)(v((19, 8))), v(8));
+ ML99_ASSERT_EQ(ML99_tupleGet(2)(v((19, 8, 7378))), v(7378));
+ ML99_ASSERT_EQ(ML99_tupleGet(3)(v((19, 8, 7378, 10))), v(10));
+ ML99_ASSERT_EQ(ML99_tupleGet(4)(v((19, 8, 7378, 10, 121))), v(121));
+ ML99_ASSERT_EQ(ML99_tupleGet(5)(v((19, 8, 7378, 10, 121, 1))), v(1));
+ ML99_ASSERT_EQ(ML99_tupleGet(6)(v((19, 8, 7378, 10, 121, 1, 80))), v(80));
+ ML99_ASSERT_EQ(ML99_tupleGet(7)(v((19, 8, 7378, 10, 121, 1, 80, 23))), v(23));
+ }
+
+ // ML99_TUPLE_GET
+ {
+ ML99_ASSERT_EMPTY_UNEVAL(ML99_TUPLE_GET(0)(()));
+
+ ML99_ASSERT_UNEVAL(ML99_TUPLE_GET(0)((19)) == 19);
+ ML99_ASSERT_UNEVAL(ML99_TUPLE_GET(0)((19, 8)) == 19);
+ ML99_ASSERT_UNEVAL(ML99_TUPLE_GET(0)((19, 8, 7378)) == 19);
+ }
+
+#define CHECK_TAIL(...) CHECK_TAIL_AUX(__VA_ARGS__)
+#define CHECK_TAIL_AUX(a, b, c) ML99_ASSERT_UNEVAL(a == 51 && b == 3 && c == 9)
+
+ // ML99_tupleTail
+ { CHECK_TAIL(ML99_EVAL(ML99_tupleTail(v((9191, 51, 3, 9))))); }
+
+ // ML99_TUPLE_TAIL
+ { CHECK_TAIL(ML99_TUPLE_TAIL((9191, 51, 3, 9))); }
+
+#undef CHECK_TAIL
+#undef CHECK_TAIL_AUX
+
+#define CHECK(a, b, c) ML99_ASSERT_UNEVAL(a == 1 && b == 2 && c == 3)
+#define CHECK_EXPAND(args) CHECK args
+
+ // ML99_tuple(Append|Prepend)
+ {
+ CHECK_EXPAND(ML99_EVAL(ML99_tupleAppend(ML99_tuple(v(1)), v(2, 3))));
+ CHECK_EXPAND(ML99_EVAL(ML99_tuplePrepend(ML99_tuple(v(3)), v(1, 2))));
+ }
+
+ // ML99_TUPLE(APPEND|PREPEND)
+ {
+ CHECK_EXPAND(ML99_TUPLE_APPEND((1), 2, 3));
+ CHECK_EXPAND(ML99_TUPLE_PREPEND((3), 1, 2));
+ }
+
+#undef CHECK
+#undef CHECK_EXPAND
+
+#define CHECK_EXPAND(...) CHECK(__VA_ARGS__)
+
+#define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 1987 && y == 2987 && z == 3987)
+#define F_IMPL(x) v(, x##987)
+#define F_ARITY 1
+
+ // ML99_tupleForEach
+ { CHECK_EXPAND(ML99_EVAL(ML99_tupleForEach(v(F), v((1, 2, 3))))); }
+
+#undef CHECK
+#undef F_IMPL
+#undef F_ARITY
+
+#define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 10 && y == 21 && z == 32)
+#define F_IMPL(x, i) v(, ), v(x##i)
+#define F_ARITY 2
+
+ // ML99_tupleForEachI
+ { CHECK_EXPAND(ML99_EVAL(ML99_tupleForEachI(v(F), v((1, 2, 3))))); }
+
+#undef CHECK
+#undef F_IMPL
+#undef F_ARITY
+
+#undef CHECK_EXPAND
+
+ // ML99_assertIsTuple
+ { ML99_EVAL(ML99_assertIsTuple(ML99_tuple(v(1, 2, 3)))); }
+}
diff --git a/test/external/metalang99/tests/util.c b/test/external/metalang99/tests/util.c
new file mode 100644
index 0000000..8b42ff9
--- /dev/null
+++ b/test/external/metalang99/tests/util.c
@@ -0,0 +1,137 @@
+#include <metalang99/assert.h>
+#include <metalang99/util.h>
+
+int main(void) {
+
+ // ML99_cat(Eval), ML99_cat(3|4)
+ {
+ ML99_ASSERT_EQ(ML99_cat(v(12), v(345)), v(12345));
+ ML99_ASSERT_EQ(ML99_cat3(v(12), v(3), v(45)), v(12345));
+ ML99_ASSERT_EQ(ML99_cat4(v(12), v(3), v(4), v(5)), v(12345));
+
+#define ABC v(123)
+
+ ML99_ASSERT_EQ(ML99_catEval(v(A), v(BC)), v(123));
+
+#undef ABC
+ }
+
+ // ML99_CAT, ML99_CAT(3|4)
+ {
+ ML99_ASSERT_UNEVAL(ML99_CAT(12, 345) == 12345);
+ ML99_ASSERT_UNEVAL(ML99_CAT3(12, 3, 45) == 12345);
+ ML99_ASSERT_UNEVAL(ML99_CAT4(12, 3, 4, 5) == 12345);
+ }
+
+#define CHECK(x, y) ML99_ASSERT_UNEVAL(x == 518 && y == 1910)
+#define CHECK_EXPAND(args) CHECK args
+
+ // ML99_id
+ {
+ ML99_ASSERT_EMPTY(ML99_id(v()));
+ CHECK_EXPAND(ML99_EVAL(ML99_id(v((518, 1910)))));
+ ML99_ASSERT_EQ(ML99_appl(ML99_compose(v(ML99_id), v(ML99_id)), v(181)), v(181));
+ }
+
+#undef CHECK
+#undef CHECK_EXPAND
+
+ // ML99_ID
+ {
+ ML99_ASSERT_EMPTY_UNEVAL(ML99_ID());
+ ML99_ASSERT_UNEVAL(ML99_ID(123) == 123);
+ }
+
+ // ML99_const
+ { ML99_ASSERT_EQ(ML99_appl2(v(ML99_const), v(1810), v(~)), v(1810)); }
+
+#define ABC ML99_TRUE()
+
+ // ML99_flip
+ { ML99_ASSERT(ML99_appl2(ML99_flip(v(ML99_cat)), v(C), v(AB))); }
+
+#undef ABC
+
+ // ML99_uncomma
+ {
+ ML99_ASSERT_EMPTY(ML99_uncomma(ML99_QUOTE(v())));
+ ML99_ASSERT_EQ(ML99_uncomma(ML99_QUOTE(v(1), v(+), v(2), v(+), v(3))), v(1 + 2 + 3));
+ }
+
+#define F(x, y, z) x + y + z
+
+ // ML99_reify
+ { ML99_ASSERT_EQ(ML99_appl(ML99_reify(v(F)), v(1, 2, 3)), v(1 + 2 + 3)); }
+
+#undef F
+
+ // ML99_empty
+ {
+ ML99_ASSERT_EMPTY(ML99_empty(v()));
+ ML99_ASSERT_EMPTY(ML99_empty(v(1, 2, 3)));
+ }
+
+ // ML99_EMPTY
+ {
+ ML99_ASSERT_EMPTY_UNEVAL(ML99_EMPTY());
+ ML99_ASSERT_EMPTY_UNEVAL(ML99_EMPTY(1, 2, 3));
+ }
+
+#define F 3 ML99_RPAREN(~, ~, ~) + G ML99_LPAREN(~, ~, ~) 1, 2,
+#define G(_1, _2, _3) _1##_2##_3
+
+ // ML99_LPAREN, ML99_RPAREN
+ {
+
+ // G(1, 2, 3) + G(1, 2, 3) + G(1, 2, 3) + G(1, 2, 3)
+ ML99_ASSERT_UNEVAL(ML99_ID(G ML99_LPAREN() 1, 2, F F F 3 ML99_RPAREN() == 123 * 4));
+ }
+
+#undef F
+#undef G
+
+#define CHECK(x, y, z) ML99_ASSERT_UNEVAL(x == 5 && y == 6 && z == 7)
+#define CHECK_EXPAND(args) CHECK(args)
+
+ // ML99_COMMA
+ { CHECK_EXPAND(5 ML99_COMMA() 6 ML99_COMMA(~, ~, ~) 7); }
+
+#undef CHECK
+#undef CHECK_EXPAND
+
+ // ML99_GEN_SYM
+ {
+
+#define TEST(...) TEST_NAMED(ML99_GEN_SYM(TEST_, x), __VA_ARGS__)
+#define TEST_NAMED(x_sym, ...) \
+ do { \
+ int x_sym = 5; \
+ (void)x_sym; \
+ __VA_ARGS__ \
+ } while (0)
+
+ // `x` here will not conflict the the `x` inside `TEST`.
+ TEST(int x = 123; (void)x;);
+
+#undef TEST
+#undef TEST_NAMED
+
+// Two identical calls to `ML99_GEN_SYM` must yield different identifiers.
+#define TEST(x1_sym, x2_sym) \
+ do { \
+ int x1_sym, x2_sym; \
+ (void)x1_sym; \
+ (void)x2_sym; \
+ } while (0)
+
+ TEST(ML99_GEN_SYM(TEST_, x), ML99_GEN_SYM(TEST_, x));
+
+#undef TEST
+ }
+
+ // ML99_TRAILING_SEMICOLON
+ {
+ ML99_TRAILING_SEMICOLON();
+ ML99_TRAILING_SEMICOLON(~, ~, ~);
+ }
+}
diff --git a/test/external/metalang99/tests/variadics.c b/test/external/metalang99/tests/variadics.c
new file mode 100644
index 0000000..111faa8
--- /dev/null
+++ b/test/external/metalang99/tests/variadics.c
@@ -0,0 +1,137 @@
+#include <metalang99/assert.h>
+#include <metalang99/variadics.h>
+
+int main(void) {
+
+ // ML99_variadicsGet
+ {
+ ML99_ASSERT_EMPTY(ML99_variadicsGet(0)(v()));
+ ML99_ASSERT_EQ(ML99_variadicsGet(0)(v(19)), v(19));
+ ML99_ASSERT_EQ(ML99_variadicsGet(0)(v(19, 8)), v(19));
+ ML99_ASSERT_EQ(ML99_variadicsGet(0)(v(19, 8, 7378)), v(19));
+
+ ML99_ASSERT_EQ(ML99_variadicsGet(1)(v(19, 8)), v(8));
+ ML99_ASSERT_EQ(ML99_variadicsGet(2)(v(19, 8, 7378)), v(7378));
+ ML99_ASSERT_EQ(ML99_variadicsGet(3)(v(19, 8, 7378, 10)), v(10));
+ ML99_ASSERT_EQ(ML99_variadicsGet(4)(v(19, 8, 7378, 10, 121)), v(121));
+ ML99_ASSERT_EQ(ML99_variadicsGet(5)(v(19, 8, 7378, 10, 121, 1)), v(1));
+ ML99_ASSERT_EQ(ML99_variadicsGet(6)(v(19, 8, 7378, 10, 121, 1, 80)), v(80));
+ ML99_ASSERT_EQ(ML99_variadicsGet(7)(v(19, 8, 7378, 10, 121, 1, 80, 23)), v(23));
+ }
+
+ // ML99_VARIADICS_GET
+ {
+ ML99_ASSERT_EMPTY_UNEVAL(ML99_VARIADICS_GET(0)());
+
+ ML99_ASSERT_UNEVAL(ML99_VARIADICS_GET(0)(19) == 19);
+ ML99_ASSERT_UNEVAL(ML99_VARIADICS_GET(0)(19, 8) == 19);
+ ML99_ASSERT_UNEVAL(ML99_VARIADICS_GET(0)(19, 8, 7378) == 19);
+
+ ML99_ASSERT_UNEVAL(ML99_VARIADICS_GET(1)(19, 8) == 8);
+ ML99_ASSERT_UNEVAL(ML99_VARIADICS_GET(1)(19, 8, 7378) == 8);
+ }
+
+#define CHECK_TAIL(...) CHECK_TAIL_AUX(__VA_ARGS__)
+#define CHECK_TAIL_AUX(a, b, c) ML99_ASSERT_UNEVAL(a == 51 && b == 3 && c == 9)
+
+ // ML99_variadicsTail
+ { CHECK_TAIL(ML99_EVAL(ML99_variadicsTail(v(9191, 51, 3, 9)))); }
+
+ // ML99_VARIADICS_TAIL
+ { CHECK_TAIL(ML99_VARIADICS_TAIL(9191, 51, 3, 9)); }
+
+#undef CHECK_TAIL
+#undef CHECK_TAIL_AUX
+
+#define _5_ARGS v(~, ~, ~, ~, ~)
+#define _10_ARGS _5_ARGS, _5_ARGS
+#define _50_ARGS _10_ARGS, _10_ARGS, _10_ARGS, _10_ARGS, _10_ARGS
+
+ // ML99_variadicsCount
+ {
+ ML99_ASSERT_EQ(ML99_variadicsCount(v()), v(1));
+ ML99_ASSERT_EQ(ML99_variadicsCount(v(~)), v(1));
+ ML99_ASSERT_EQ(ML99_variadicsCount(v(~, ~)), v(2));
+ ML99_ASSERT_EQ(ML99_variadicsCount(v(~, ~, ~)), v(3));
+ ML99_ASSERT_EQ(ML99_variadicsCount(v(~, ~, ~, ~)), v(4));
+ ML99_ASSERT_EQ(ML99_variadicsCount(_5_ARGS), v(5));
+ ML99_ASSERT_EQ(ML99_variadicsCount(_5_ARGS, v(~)), v(6));
+ ML99_ASSERT_EQ(ML99_variadicsCount(_5_ARGS, v(~, ~)), v(7));
+ ML99_ASSERT_EQ(ML99_variadicsCount(_5_ARGS, v(~, ~, ~)), v(8));
+ ML99_ASSERT_EQ(ML99_variadicsCount(_5_ARGS, v(~, ~, ~, ~)), v(9));
+ ML99_ASSERT_EQ(ML99_variadicsCount(_10_ARGS), v(10));
+ ML99_ASSERT_EQ(ML99_variadicsCount(_10_ARGS, v(~)), v(11));
+ ML99_ASSERT_EQ(ML99_variadicsCount(_50_ARGS, _10_ARGS, v(~, ~, ~)), v(63));
+ }
+
+#define X(...) ML99_OVERLOAD(X_, __VA_ARGS__)
+#define X_1(a) ML99_ASSERT_UNEVAL(a == 123)
+#define X_2(a, b) ML99_ASSERT_UNEVAL(a == 93145 && b == 456)
+#define X_7(a, b, c, d, e, f, g) \
+ ML99_ASSERT_UNEVAL(a == 1516 && b == 1 && c == 9 && d == 111 && e == 119 && f == 677 && g == 62)
+
+ // ML99_OVERLOAD
+ {
+ X(123);
+ X(93145, 456);
+ X(1516, 1, 9, 111, 119, 677, 62);
+ }
+
+#undef X_IMPL
+#undef X_1_IMPL
+#undef X_2_IMPL
+#undef X_7_IMPL
+
+ // ML99_VARIADICS_COUNT
+ {
+ ML99_ASSERT_EQ(v(ML99_VARIADICS_COUNT()), v(1));
+ ML99_ASSERT_EQ(v(ML99_VARIADICS_COUNT(~)), v(1));
+ ML99_ASSERT_EQ(v(ML99_VARIADICS_COUNT(~, ~)), v(2));
+ ML99_ASSERT_EQ(v(ML99_VARIADICS_COUNT(~, ~, ~)), v(3));
+ }
+
+#undef _5_ARGS
+#undef _10_ARGS
+#undef _50_ARGS
+#undef _100_ARGS
+
+ // ML99_variadicsIsSingle
+ {
+ ML99_ASSERT(ML99_variadicsIsSingle(v()));
+ ML99_ASSERT(ML99_variadicsIsSingle(v(~)));
+ ML99_ASSERT(ML99_not(ML99_variadicsIsSingle(v(~, ~, ~))));
+ }
+
+ // ML99_VARIADICS_IS_SINGLE
+ {
+ ML99_ASSERT_UNEVAL(ML99_VARIADICS_IS_SINGLE());
+ ML99_ASSERT_UNEVAL(ML99_VARIADICS_IS_SINGLE(~));
+ ML99_ASSERT_UNEVAL(ML99_NOT(ML99_VARIADICS_IS_SINGLE(~, ~, ~)));
+ }
+
+#define CHECK_EXPAND(...) CHECK(__VA_ARGS__)
+
+#define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 1987 && y == 2987 && z == 3987)
+#define F_IMPL(x) v(, x##987)
+#define F_ARITY 1
+
+ // ML99_variadicsForEach
+ { CHECK_EXPAND(ML99_EVAL(ML99_variadicsForEach(v(F), v(1, 2, 3)))); }
+
+#undef CHECK
+#undef F_IMPL
+#undef F_ARITY
+
+#define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 10 && y == 21 && z == 32)
+#define F_IMPL(x, i) v(, ), v(x##i)
+#define F_ARITY 2
+
+ // ML99_variadicsForEachI
+ { CHECK_EXPAND(ML99_EVAL(ML99_variadicsForEachI(v(F), v(1, 2, 3)))); }
+
+#undef CHECK
+#undef F_IMPL
+#undef F_ARITY
+
+#undef CHECK_EXPAND
+}