aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/external/metalang99/tests
diff options
context:
space:
mode:
Diffstat (limited to 'test/external/metalang99/tests')
-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
19 files changed, 2746 insertions, 0 deletions
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
+}