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/examples/.gitignore | 1 + test/external/metalang99/examples/CMakeLists.txt | 30 +++ test/external/metalang99/examples/ackermann.c | 22 +++ .../external/metalang99/examples/assert_for_each.c | 31 +++ test/external/metalang99/examples/binary_tree.c | 25 +++ test/external/metalang99/examples/demo.c | 48 +++++ test/external/metalang99/examples/duffs_device.c | 76 ++++++++ test/external/metalang99/examples/factorial.c | 16 ++ .../external/metalang99/examples/lambda_calculus.c | 209 +++++++++++++++++++++ test/external/metalang99/examples/overload.c | 15 ++ test/external/metalang99/examples/rectangle.c | 25 +++ 11 files changed, 498 insertions(+) create mode 100644 test/external/metalang99/examples/.gitignore create mode 100644 test/external/metalang99/examples/CMakeLists.txt create mode 100644 test/external/metalang99/examples/ackermann.c create mode 100644 test/external/metalang99/examples/assert_for_each.c create mode 100644 test/external/metalang99/examples/binary_tree.c create mode 100644 test/external/metalang99/examples/demo.c create mode 100644 test/external/metalang99/examples/duffs_device.c create mode 100644 test/external/metalang99/examples/factorial.c create mode 100644 test/external/metalang99/examples/lambda_calculus.c create mode 100644 test/external/metalang99/examples/overload.c create mode 100644 test/external/metalang99/examples/rectangle.c (limited to 'test/external/metalang99/examples') diff --git a/test/external/metalang99/examples/.gitignore b/test/external/metalang99/examples/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/test/external/metalang99/examples/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/test/external/metalang99/examples/CMakeLists.txt b/test/external/metalang99/examples/CMakeLists.txt new file mode 100644 index 0000000..ed8e963 --- /dev/null +++ b/test/external/metalang99/examples/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.16) +project(examples LANGUAGES C) + +if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + add_compile_options(-Wall -Wextra -pedantic -std=c99 + -ftrack-macro-expansion=0) +elseif(CMAKE_C_COMPILER_ID STREQUAL "Clang") + add_compile_options("-fmacro-backtrace-limit=1") +elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + # Enable a standard-conforming C99/C11 preprocessor. + add_compile_options("/std:c11") +elseif(CMAKE_C_COMPILER_ID STREQUAL "TinyCC") + add_compile_definitions(ML99_ALLOW_POOR_DIAGNOSTICS) +endif() + +include_directories(../include) + +add_executable(ackermann ackermann.c) +add_executable(assert_for_each assert_for_each.c) +add_executable(binary_tree binary_tree.c) +add_executable(demo demo.c) +add_executable(duffs_device duffs_device.c) +add_executable(factorial factorial.c) +add_executable(overload overload.c) +add_executable(rectangle rectangle.c) +add_executable(lambda_calculus lambda_calculus.c) + +foreach(TARGET ${BUILDSYSTEM_TARGETS}) + set_target_properties(TARGET PROPERTIES C_STANDARD 99 C_STANDARD_REQUIRED ON) +endforeach() diff --git a/test/external/metalang99/examples/ackermann.c b/test/external/metalang99/examples/ackermann.c new file mode 100644 index 0000000..a3ea623 --- /dev/null +++ b/test/external/metalang99/examples/ackermann.c @@ -0,0 +1,22 @@ +#include + +#define ack(m, n) ML99_natMatchWithArgs(m, v(ack_), n) + +#define ack_Z_IMPL(n) ML99_inc(v(n)) +#define ack_S_IMPL(m, n) ML99_natMatchWithArgs(v(n), v(ack_S_), v(m)) +#define ack_S_Z_IMPL(m) ack(v(m), v(1)) +#define ack_S_S_IMPL(n, m) ack(v(m), ack(ML99_inc(v(m)), v(n))) + +ML99_ASSERT_EQ(ack(v(0), v(0)), v(1)); +ML99_ASSERT_EQ(ack(v(0), v(1)), v(2)); +ML99_ASSERT_EQ(ack(v(0), v(2)), v(3)); + +ML99_ASSERT_EQ(ack(v(1), v(0)), v(2)); +ML99_ASSERT_EQ(ack(v(1), v(1)), v(3)); +ML99_ASSERT_EQ(ack(v(1), v(2)), v(4)); + +ML99_ASSERT_EQ(ack(v(2), v(0)), v(3)); +ML99_ASSERT_EQ(ack(v(2), v(1)), v(5)); +ML99_ASSERT_EQ(ack(v(2), v(2)), v(7)); + +int main(void) {} diff --git a/test/external/metalang99/examples/assert_for_each.c b/test/external/metalang99/examples/assert_for_each.c new file mode 100644 index 0000000..3ba9127 --- /dev/null +++ b/test/external/metalang99/examples/assert_for_each.c @@ -0,0 +1,31 @@ +// Asserts multiple expressions at once. + +#include + +#include + +#define ASSERT_FOR_EACH(...) \ + do { \ + ML99_EVAL(ML99_variadicsForEach( \ + ML99_compose(v(ML99_semicoloned), ML99_reify(v(assert))), \ + v(__VA_ARGS__))) \ + } while (0) + +int main(void) { + ASSERT_FOR_EACH(123 == 123, 2 + 2 == 4, "foo"[1] == 'o'); + + /* + * If we combine multiple assertions with the && operator, we will not be able to distinguish + * them if one of them fails apparently: + * + * main: Assertion `123 == 321 && 2 + 2 == 4 && "foo"[1] == 'o' failed. + * assert(123 == 321 && 2 + 2 == 4 && "foo"[1] == 'o'); + */ + + /* + * ... unlike `ASSERT_FOR_EACH` telling us which one has failed: + * + * main: Assertion `123 == 321' failed. + * ASSERT_FOR_EACH(123 == 321, 2 + 2 == 4, "foo"[1] == 'o'); + */ +} diff --git a/test/external/metalang99/examples/binary_tree.c b/test/external/metalang99/examples/binary_tree.c new file mode 100644 index 0000000..8cd9177 --- /dev/null +++ b/test/external/metalang99/examples/binary_tree.c @@ -0,0 +1,25 @@ +// Sums all nodes of a binary tree, recursively. + +#include + +#define leaf(x) ML99_choice(v(leaf), x) +#define node(lhs, data, rhs) ML99_choice(v(node), lhs, data, rhs) + +#define sumTree(tree) ML99_match(tree, v(sumTree_)) +#define sumTree_leaf_IMPL(x) v(x) +#define sumTree_node_IMPL(lhs, data, rhs) ML99_add3(sumTree(v(lhs)), v(data), sumTree(v(rhs))) + +/* + * 4 + * / \ + * / \ + * / \ + * 2 6 + * / \ / \ + * 1 3 5 7 + */ +#define TREE node(node(leaf(v(1)), v(2), leaf(v(3))), v(4), node(leaf(v(5)), v(6), leaf(v(7)))) + +ML99_ASSERT_EQ(sumTree(TREE), v(28)); + +int main(void) {} diff --git a/test/external/metalang99/examples/demo.c b/test/external/metalang99/examples/demo.c new file mode 100644 index 0000000..4a209d9 --- /dev/null +++ b/test/external/metalang99/examples/demo.c @@ -0,0 +1,48 @@ +// `...` is sometimes used to workaround a TCC bug, see +// . + +#include + +// Compile-time list manipulation: + +// 3, 3, 3, 3, 3 +static int five_threes[] = { + ML99_LIST_EVAL_COMMA_SEP(ML99_listReplicate(v(5), v(3))), +}; + +// 5, 4, 3, 2, 1 +static int from_5_to_1[] = { + ML99_LIST_EVAL_COMMA_SEP(ML99_listReverse(ML99_list(v(1, 2, 3, 4, 5)))), +}; + +// 9, 2, 5 +static int lesser_than_10[] = { + ML99_LIST_EVAL_COMMA_SEP( + ML99_listFilter(ML99_appl(v(ML99_greater), v(10)), ML99_list(v(9, 2, 11, 13, 5)))), +}; + +// Macro recursion: +#define factorial(n) ML99_natMatch(n, v(factorial_)) +#define factorial_Z_IMPL(...) v(1) // `...` due to the TCC's bug. +#define factorial_S_IMPL(n) ML99_mul(ML99_inc(v(n)), factorial(v(n))) + +ML99_ASSERT_EQ(factorial(v(4)), v(24)); + +// Overloading on a number of arguments: +typedef struct { + double width, height; +} Rect; + +#define Rect_new(...) ML99_OVERLOAD(Rect_new_, __VA_ARGS__) +#define Rect_new_1(x) \ + { x, x } +#define Rect_new_2(x, y) \ + { x, y } + +static Rect _7x8 = Rect_new(7, 8), _10x10 = Rect_new(10); + +// ... and more! + +int main(void) { + // Yeah. All is done at compile time. +} diff --git a/test/external/metalang99/examples/duffs_device.c b/test/external/metalang99/examples/duffs_device.c new file mode 100644 index 0000000..cc5ade0 --- /dev/null +++ b/test/external/metalang99/examples/duffs_device.c @@ -0,0 +1,76 @@ +/** + * Duff's device [1] is a technique to implement loop unrolling through amalgamation of a switch + * statement with a do-while loop. + * + * In this example, we are going to implement automatic generation of Duff's device. + * + * [1]: https://en.wikipedia.org/wiki/Duff's_device + */ + +#include + +#include + +#define DUFFS_DEVICE(unrolling_factor, counter_ty, count, ...) \ + do { \ + if ((count) > 0) { \ + counter_ty DUFFS_DEVICE_n = ((count) + ML99_DEC(unrolling_factor)) / unrolling_factor; \ + switch ((count) % unrolling_factor) { \ + case 0: \ + do { \ + __VA_ARGS__ \ + ML99_EVAL(ML99_callUneval(genCases, ML99_DEC(unrolling_factor), __VA_ARGS__)) \ + } while (--DUFFS_DEVICE_n > 0); \ + } \ + } \ + } while (0) + +#define genCases_IMPL(i, ...) \ + ML99_IF( \ + ML99_NAT_EQ(i, 0), \ + ML99_empty(), \ + ML99_TERMS( \ + v(/* FALLTHROUGH */ case i \ + : __VA_ARGS__), \ + ML99_callUneval(genCases, ML99_DEC(i), __VA_ARGS__))) + +int main(void) { +#define ARRAY_LEN 50 +#define UNROLLING_FACTOR 3 + + int array[ARRAY_LEN] = { ML99_EVAL(ML99_times(v(ARRAY_LEN), v(5, ))) }; + int *n_ptr = array; + + // Square all the elements in the array. + DUFFS_DEVICE(UNROLLING_FACTOR, int, ARRAY_LEN, { + *n_ptr *= *n_ptr; + n_ptr++; + }); + + for (int i = 0; i < ARRAY_LEN; i++) { + assert(25 == array[i]); + } +} + +/* +The generated Duff's device: + +int DUFFS_DEVICE_n = ((50) + 2) / 3; +switch ((50) % 3) { +case 0: + do { + { + *n_ptr *= *n_ptr; + n_ptr++; + } + case 2: { + *n_ptr *= *n_ptr; + n_ptr++; + } + case 1: { + *n_ptr *= *n_ptr; + n_ptr++; + } + } while (--DUFFS_DEVICE_n > 0); +} +*/ diff --git a/test/external/metalang99/examples/factorial.c b/test/external/metalang99/examples/factorial.c new file mode 100644 index 0000000..ed381fa --- /dev/null +++ b/test/external/metalang99/examples/factorial.c @@ -0,0 +1,16 @@ +// `...` is sometimes used to workaround a TCC bug, see +// . + +#include + +#define factorial(n) ML99_natMatch(n, v(factorial_)) +#define factorial_Z_IMPL(...) v(1) // `...` due to the TCC's bug. +#define factorial_S_IMPL(n) ML99_mul(ML99_inc(v(n)), factorial(v(n))) + +ML99_ASSERT_EQ(factorial(v(0)), v(1)); +ML99_ASSERT_EQ(factorial(v(1)), v(1)); +ML99_ASSERT_EQ(factorial(v(2)), v(2)); +ML99_ASSERT_EQ(factorial(v(3)), v(6)); +ML99_ASSERT_EQ(factorial(v(4)), v(24)); + +int main(void) {} diff --git a/test/external/metalang99/examples/lambda_calculus.c b/test/external/metalang99/examples/lambda_calculus.c new file mode 100644 index 0000000..e300304 --- /dev/null +++ b/test/external/metalang99/examples/lambda_calculus.c @@ -0,0 +1,209 @@ +/* + * An untyped lambda calculus [1] interpreter using De Bruijn indices [2] and normal order + * evaluation strategy [3]. + * + * [1] https://en.wikipedia.org/wiki/Lambda_calculus + * [2] https://en.wikipedia.org/wiki/De_Bruijn_index + * [3] https://en.wikipedia.org/wiki/Evaluation_strategy#Normal_order + */ + +#include + +// Syntactic terms { + +#define var(i) ML99_call(var, i) +#define appl(M, N) ML99_call(appl, M, N) +#define lam(M) ML99_call(lam, M) + +#define var_IMPL(i) v(VAR(i)) +#define appl_IMPL(M, N) v(APPL(M, N)) +#define lam_IMPL(M) v(LAM(M)) + +#define VAR(i) ML99_CHOICE(var, i) +#define APPL(M, N) ML99_CHOICE(appl, M, N) +#define LAM(M) ML99_CHOICE(lam, M) +// } (Syntactic terms) + +// Variable substitution: `M[1=x]` { + +#define subst(M, x) ML99_call(subst, M, x) + +#define subst_IMPL(M, x) substAux_IMPL(M, x, 1) +#define substAux_IMPL(M, x, depth) ML99_callUneval(ML99_matchWithArgs, M, substAux_, x, depth) + +#define substAux_var_IMPL(i, x, depth) \ + ML99_IF( \ + ML99_NAT_EQ(i, depth), \ + v(x), \ + ML99_call(ML99_if, ML99_callUneval(ML99_greater, i, depth), v(VAR(ML99_DEC(i)), VAR(i)))) +#define substAux_appl_IMPL(M, N, x, depth) \ + appl(substAux_IMPL(M, x, depth), substAux_IMPL(N, x, depth)) +#define substAux_lam_IMPL(M, x, depth) \ + lam(ML99_call(substAux, v(M), incFreeVars_IMPL(x), v(ML99_INC(depth)))) +// } (Variable substitution) + +// Increment free variables in `M` { + +#define incFreeVars(M) ML99_call(incFreeVars, M) + +#define incFreeVars_IMPL(M) incFreeVarsAux_IMPL(M, 1) +#define incFreeVarsAux_IMPL(M, depth) ML99_callUneval(ML99_matchWithArgs, M, incFreeVarsAux_, depth) + +#define incFreeVarsAux_var_IMPL(i, depth) \ + ML99_call(ML99_if, ML99_callUneval(ML99_greaterEq, i, depth), v(VAR(ML99_INC(i)), VAR(i))) +#define incFreeVarsAux_appl_IMPL(M, N, depth) \ + appl(incFreeVarsAux_IMPL(M, depth), incFreeVarsAux_IMPL(N, depth)) +#define incFreeVarsAux_lam_IMPL(M, depth) lam(incFreeVarsAux_IMPL(M, ML99_INC(depth))) +// } (Increment free variables) + +// Evaluation { + +#define eval(M) ML99_call(eval, M) + +#define eval_IMPL(M) ML99_callUneval(ML99_match, M, eval_) +#define eval_var_IMPL(i) v(VAR(i)) +#define eval_appl_IMPL(M, N) ML99_callUneval(ML99_matchWithArgs, M, eval_appl_, N) +#define eval_lam_IMPL(M) lam(eval_IMPL(M)) + +#define eval_appl_var_IMPL(i, N) appl(v(VAR(i)), eval_IMPL(N)) +#define eval_appl_appl_IMPL(M, N, N1) \ + ML99_call(ML99_matchWithArgs, eval(appl_IMPL(M, N)), v(eval_appl_appl_, N1)) +#define eval_appl_lam_IMPL(M, N) eval(subst_IMPL(M, N)) + +#define eval_appl_appl_var_IMPL eval_appl_var_IMPL +#define eval_appl_appl_appl_IMPL(M, N, N1) appl(appl_IMPL(M, N), eval_IMPL(N1)) +#define eval_appl_appl_lam_IMPL eval_appl_lam_IMPL +// } (Evaluation) + +// Syntactical equality { + +#define termEq(lhs, rhs) ML99_matchWithArgs(lhs, v(termEq_), rhs) +#define termEq_var_IMPL(i, rhs) termEqPropagate(var, rhs, i) +#define termEq_appl_IMPL(M, N, rhs) termEqPropagate(appl, rhs, M, N) +#define termEq_lam_IMPL(M, rhs) termEqPropagate(lam, rhs, M) + +#define termEqPropagate(term_kind, rhs, ...) \ + ML99_IF( \ + ML99_IDENT_EQ(TERM_, ML99_CHOICE_TAG(rhs), term_kind), \ + ML99_matchWithArgs(v(rhs), v(termEq_##term_kind##_), v(__VA_ARGS__)), \ + ML99_false()) + +#define termEq_var_var_IMPL(j, i) v(ML99_NAT_EQ(i, j)) +#define termEq_appl_appl_IMPL(M, N, M1, N1) ML99_and(termEq(v(M), v(M1)), termEq(v(N), v(N1))) +#define termEq_lam_lam_IMPL(M, M1) termEq(v(M), v(M1)) + +#define TERM_var_var () +#define TERM_appl_appl () +#define TERM_lam_lam () +// } (Syntactical equality) + +#define ASSERT_REDUCES_TO(lhs, rhs) \ + /* Use two interpreter passes: one for `eval(lhs)`, one for `termEq`. Thereby we achieve more \ + * Metalang99 reduction steps available. */ \ + ML99_ASSERT_UNEVAL(ML99_EVAL(termEq(v(ML99_EVAL(eval(v(lhs)))), v(ML99_EVAL(eval(v(rhs))))))) + +// The identity combinator { + +#define I LAM(VAR(1)) + +ASSERT_REDUCES_TO(APPL(I, VAR(5)), VAR(5)); +// } (The identity combinator) + +// The K, S combinators { + +#define K LAM(LAM(VAR(2))) +#define S LAM(LAM(LAM(APPL(APPL(VAR(3), VAR(1)), APPL(VAR(2), VAR(1)))))) + +ASSERT_REDUCES_TO(APPL(APPL(S, K), K), I); +ASSERT_REDUCES_TO(APPL(APPL(APPL(S, K), S), K), K); + +ASSERT_REDUCES_TO(APPL(APPL(APPL(S, K), VAR(5)), VAR(6)), VAR(6)); +ASSERT_REDUCES_TO(APPL(APPL(K, VAR(5)), VAR(6)), VAR(5)); +// } (The K, S combinators) + +// Church booleans { + +#define T LAM(LAM(VAR(2))) +#define F LAM(LAM(VAR(1))) + +#define NOT LAM(APPL(APPL(VAR(1), F), T)) +#define AND LAM(LAM(APPL(APPL(VAR(2), VAR(1)), VAR(2)))) +#define OR LAM(LAM(APPL(APPL(VAR(2), VAR(2)), VAR(1)))) +#define XOR LAM(LAM(APPL(APPL(VAR(2), APPL(NOT, VAR(1))), VAR(1)))) + +#define IF LAM(LAM(LAM(APPL(APPL(VAR(3), VAR(2)), VAR(1))))) + +ASSERT_REDUCES_TO(APPL(NOT, T), F); +ASSERT_REDUCES_TO(APPL(NOT, F), T); +ASSERT_REDUCES_TO(APPL(NOT, APPL(NOT, T)), T); +ASSERT_REDUCES_TO(APPL(NOT, APPL(NOT, F)), F); + +ASSERT_REDUCES_TO(APPL(APPL(AND, T), T), T); +ASSERT_REDUCES_TO(APPL(APPL(AND, T), F), F); +ASSERT_REDUCES_TO(APPL(APPL(AND, F), T), F); +ASSERT_REDUCES_TO(APPL(APPL(AND, F), F), F); + +ASSERT_REDUCES_TO(APPL(APPL(OR, T), T), T); +ASSERT_REDUCES_TO(APPL(APPL(OR, T), F), T); +ASSERT_REDUCES_TO(APPL(APPL(OR, F), T), T); +ASSERT_REDUCES_TO(APPL(APPL(OR, F), F), F); + +ASSERT_REDUCES_TO(APPL(APPL(XOR, T), T), F); +ASSERT_REDUCES_TO(APPL(APPL(XOR, T), F), T); +ASSERT_REDUCES_TO(APPL(APPL(XOR, F), T), T); +ASSERT_REDUCES_TO(APPL(APPL(XOR, F), F), F); + +ASSERT_REDUCES_TO(APPL(APPL(APPL(IF, T), VAR(5)), VAR(6)), VAR(5)); +ASSERT_REDUCES_TO(APPL(APPL(APPL(IF, F), VAR(5)), VAR(6)), VAR(6)); +// } (Church booleans) + +// Church numerals { + +#define ZERO LAM(LAM(VAR(1))) +#define SUCC LAM(LAM(LAM(APPL(VAR(2), APPL(APPL(VAR(3), VAR(2)), VAR(1)))))) + +#define ONE APPL(SUCC, ZERO) +#define TWO APPL(SUCC, ONE) +#define THREE APPL(SUCC, TWO) +#define FOUR APPL(SUCC, THREE) + +#define ADD LAM(LAM(LAM(LAM(APPL(APPL(VAR(4), VAR(2)), APPL(APPL(VAR(3), VAR(2)), VAR(1))))))) +#define MUL LAM(LAM(LAM(LAM(APPL(APPL(VAR(4), APPL(VAR(3), VAR(2))), VAR(1)))))) + +ASSERT_REDUCES_TO(APPL(APPL(ADD, ZERO), ZERO), ZERO); +ASSERT_REDUCES_TO(APPL(APPL(ADD, ZERO), ONE), ONE); +ASSERT_REDUCES_TO(APPL(APPL(ADD, ONE), ZERO), ONE); +ASSERT_REDUCES_TO(APPL(APPL(ADD, ONE), TWO), THREE); + +ASSERT_REDUCES_TO(APPL(APPL(MUL, ZERO), ZERO), ZERO); +ASSERT_REDUCES_TO(APPL(APPL(MUL, ZERO), ONE), ZERO); +ASSERT_REDUCES_TO(APPL(APPL(MUL, ONE), ZERO), ZERO); +ASSERT_REDUCES_TO(APPL(APPL(MUL, TWO), TWO), FOUR); +// } (Church numerals) + +// Church pairs { + +#define PAIR LAM(LAM(LAM(APPL(APPL(VAR(1), VAR(3)), VAR(2))))) +#define FST LAM(APPL(VAR(1), T)) +#define SND LAM(APPL(VAR(1), F)) + +ASSERT_REDUCES_TO(APPL(FST, APPL(APPL(PAIR, VAR(5)), VAR(6))), VAR(5)); +ASSERT_REDUCES_TO(APPL(SND, APPL(APPL(PAIR, VAR(5)), VAR(6))), VAR(6)); +// } (Church pairs) + +// Church lists { + +#define NIL F +#define CONS PAIR +#define IS_NIL LAM(APPL(APPL(VAR(1), LAM(LAM(LAM(F)))), T)) + +#define LIST_1_2_3 APPL(APPL(CONS, VAR(1)), APPL(APPL(CONS, VAR(2)), APPL(APPL(CONS, VAR(3)), NIL))) + +ASSERT_REDUCES_TO(APPL(IS_NIL, NIL), T); +ASSERT_REDUCES_TO(APPL(IS_NIL, LIST_1_2_3), F); +// } (Church lists) + +// Recursion via self-application (or the Y combinator) is perfectly expressible, though when +// executed, it exhausts the Metalang99 recursion engine limit. + +int main(void) {} diff --git a/test/external/metalang99/examples/overload.c b/test/external/metalang99/examples/overload.c new file mode 100644 index 0000000..8b5d6fd --- /dev/null +++ b/test/external/metalang99/examples/overload.c @@ -0,0 +1,15 @@ +#include + +typedef struct { + double width, height; +} Rect; + +#define Rect_new(...) ML99_OVERLOAD(Rect_new_, __VA_ARGS__) +#define Rect_new_1(x) \ + { x, x } +#define Rect_new_2(x, y) \ + { x, y } + +static Rect _7x8 = Rect_new(7, 8), _10x10 = Rect_new(10); + +int main(void) {} diff --git a/test/external/metalang99/examples/rectangle.c b/test/external/metalang99/examples/rectangle.c new file mode 100644 index 0000000..1ab2bbf --- /dev/null +++ b/test/external/metalang99/examples/rectangle.c @@ -0,0 +1,25 @@ +// Computes the area of a rectangle. + +#include + +#define rect(width, height) ML99_tuple(width, height) +#define rectWidth ML99_tupleGet(0) +#define rectHeight ML99_tupleGet(1) + +#define rectArea(rect) ML99_mul(rectWidth(rect), rectHeight(rect)) + +/* + * 15 + * +------------------------------+ + * | | + * | | + * | | 7 + * | | + * | | + * +------------------------------+ + */ +#define RECTANGLE rect(v(15), v(7)) + +ML99_ASSERT_EQ(rectArea(RECTANGLE), v(15 * 7)); + +int main(void) {} -- cgit v1.2.3