From 052144cabb126efe925a96f8a0597a0f2005d206 Mon Sep 17 00:00:00 2001 From: lemon Date: Mon, 23 Feb 2026 20:36:05 +0100 Subject: add metalang99 testsuite (preprocessor stress testing) --- test/external/metalang99/tests/.gitignore | 1 + test/external/metalang99/tests/CMakeLists.txt | 38 ++ test/external/metalang99/tests/assert.c | 19 + test/external/metalang99/tests/bool.c | 121 ++++++ test/external/metalang99/tests/choice.c | 64 ++++ test/external/metalang99/tests/either.c | 66 ++++ test/external/metalang99/tests/eval/rec.c | 25 ++ test/external/metalang99/tests/gen.c | 283 ++++++++++++++ test/external/metalang99/tests/ident.c | 395 +++++++++++++++++++ test/external/metalang99/tests/lang.c | 165 ++++++++ test/external/metalang99/tests/list.c | 528 ++++++++++++++++++++++++++ test/external/metalang99/tests/maybe.c | 58 +++ test/external/metalang99/tests/metalang99.c | 51 +++ test/external/metalang99/tests/nat.c | 260 +++++++++++++ test/external/metalang99/tests/seq.c | 100 +++++ test/external/metalang99/tests/stmt.c | 114 ++++++ test/external/metalang99/tests/tuple.c | 184 +++++++++ test/external/metalang99/tests/util.c | 137 +++++++ test/external/metalang99/tests/variadics.c | 137 +++++++ 19 files changed, 2746 insertions(+) create mode 100644 test/external/metalang99/tests/.gitignore create mode 100644 test/external/metalang99/tests/CMakeLists.txt create mode 100644 test/external/metalang99/tests/assert.c create mode 100644 test/external/metalang99/tests/bool.c create mode 100644 test/external/metalang99/tests/choice.c create mode 100644 test/external/metalang99/tests/either.c create mode 100644 test/external/metalang99/tests/eval/rec.c create mode 100644 test/external/metalang99/tests/gen.c create mode 100644 test/external/metalang99/tests/ident.c create mode 100644 test/external/metalang99/tests/lang.c create mode 100644 test/external/metalang99/tests/list.c create mode 100644 test/external/metalang99/tests/maybe.c create mode 100644 test/external/metalang99/tests/metalang99.c create mode 100644 test/external/metalang99/tests/nat.c create mode 100644 test/external/metalang99/tests/seq.c create mode 100644 test/external/metalang99/tests/stmt.c create mode 100644 test/external/metalang99/tests/tuple.c create mode 100644 test/external/metalang99/tests/util.c create mode 100644 test/external/metalang99/tests/variadics.c (limited to 'test/external/metalang99/tests') 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 + +// 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 +#include + +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 +#include + +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 +#include +#include + +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 + +#include + +#include + +#include +#include + +#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 +#include +#include +#include +#include + +#include + +// 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 +#include +#include + +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 +// . + +#include +#include + +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 +#include +#include +#include +#include +#include + +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 +#include +#include + +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 +#include + +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 +// . + +#include +#include + +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 +#include + +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 + +#include + +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 +#include + +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 +#include + +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 +#include + +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 +} -- cgit v1.2.3