1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
// `...` is sometimes used to workaround a TCC bug, see
// <https://github.com/hirrolot/datatype99/issues/10#issuecomment-830813172>.
#include <metalang99/assert.h>
#include <metalang99/util.h>
int main(void) {
ML99_ASSERT_EMPTY_UNEVAL(ML99_EVAL(v()));
#ifndef __TINYC__
#define F_IMPL() v(123)
#else
#define F_IMPL(...) v(123) // `...` due to the TCC's bug.
#endif
// A function with zero arguments
{
ML99_ASSERT_EQ(ML99_call(F, v()), v(123));
ML99_ASSERT_EQ(ML99_call(v(F), v()), v(123));
ML99_ASSERT_EQ(ML99_callUneval(F, ), v(123));
}
#undef F_IMPL
#define F_IMPL(x, y, z) v(x##y##z)
#define BAR_IMPL(x, y) v(x + y)
// Regular usage of the metalanguage
{
ML99_ASSERT_EQ(ML99_call(BAR, v(5), v(7)), v(5 + 7));
ML99_ASSERT_EQ(ML99_call(ML99_call(F, v(B), v(A), v(R)), v(6), v(11)), v(6 + 11));
ML99_ASSERT_EQ(ML99_call(BAR, v(5, 7)), v(5 + 7));
ML99_ASSERT_EQ(ML99_call(ML99_call(F, v(B, A, R)), v(6, 11)), v(6 + 11));
ML99_ASSERT_EQ(ML99_callUneval(BAR, 5, 7), v(5 + 7));
}
#undef F_IMPL
#undef BAR_IMPL
// Even if a term in the argument position evaluates to more than one terms, they should be appended
// to each other but not interspersed with a comma.
#define F_IMPL(...) ML99_TERMS(v(1), v(2), v(3)) // `...` due to the TCC's bug.
#define BAR_IMPL(x) v()
ML99_EVAL(ML99_call(BAR, ML99_call(F, v())))
#undef F_IMPL
#undef BAR_IMPL
// Recursion might arise from a higher-order macro, if `op` invokes `F`, but nonetheless the
// second call to `F` must be performed as expected.
#define F_IMPL(op) ML99_call(op, v(123))
#define OP_IMPL(x) ML99_call(F, v(ID))
#define ID_IMPL(x) v(x)
ML99_ASSERT_EQ(ML99_call(F, v(OP)), v(123));
#undef F_IMPL
#undef OP_IMPL
#undef ID_IMPL
// ML99_abort
{
ML99_ASSERT_EMPTY(ML99_abort(v()));
ML99_ASSERT_EQ(ML99_abort(v(815057)), v(815057));
ML99_ASSERT_UNEVAL(ML99_EVAL(v(~), ML99_abort(v(123)), v(~)) == 123);
// Ensure that `ML99_abort` also works correctly after some evaluations.
#define F_IMPL(...) ML99_call(G, v(1, 2), ML99_call(H, v(123))) // `...` due to the TCC's bug.
#define G_IMPL(_1, _2, _123_plus_1) \
ML99_abort(v(ML99_ASSERT_UNEVAL(_1 == 1 && _2 == 2 && _123_plus_1 == 123 + 1)))
#define H_IMPL(a) v(a + 1)
ML99_EVAL(ML99_call(F, v()));
#undef F_IMPL
#undef G_IMPL
#undef H_IMPL
// Ensure that `ML99_abort` immediately aborts interpretation even in an argument position.
ML99_ASSERT_EQ(ML99_call(NonExistingF, ML99_abort(v(123))), v(123));
}
// Partial application
{
#ifndef __TINYC__
#define F_IMPL() v(123)
#else
#define F_IMPL(...) v(123) // // `...` due to the TCC's bug.
#endif
#define F_ARITY 1
// The arity of a function with zero arguments must be 1
{ ML99_ASSERT_EQ(ML99_appl(v(F), v()), v(123)); }
#undef F_IMPL
#undef F_ARITY
#define F_IMPL(a, b, c, d) v(a##b##c##d)
#define F_ARITY 4
// Regular usage of partial application
{
ML99_ASSERT_EQ(
ML99_appl(ML99_appl(ML99_appl(ML99_appl(v(F), v(10)), v(5)), v(7)), v(8)),
v(10578));
ML99_ASSERT_EQ(
ML99_appl(ML99_appl(ML99_appl2(v(F), v(10), v(5)), v(7)), v(8)),
v(10578));
ML99_ASSERT_EQ(ML99_appl(ML99_appl3(v(F), v(10), v(5), v(7)), v(8)), v(10578));
ML99_ASSERT_EQ(ML99_appl4(v(F), v(10), v(5), v(7), v(8)), v(10578));
}
#undef F_IMPL
#undef F_ARITY
#define F_ARITY 255
// The maximum arity
{
ML99_EVAL(ML99_empty(ML99_appl(v(F), v(~))))
ML99_EVAL(ML99_empty(ML99_appl2(v(F), v(~), v(~))))
ML99_EVAL(ML99_empty(ML99_appl3(v(F), v(~), v(~), v(~))))
}
#undef F_ARITY
}
#define F_IMPL(x) v((x + 1))
#define G_IMPL(x) v((x * 8))
#define F_ARITY 1
#define G_ARITY 1
// ML99_compose
{ ML99_ASSERT_EQ(ML99_appl(ML99_compose(v(F), v(G)), v(3)), v((3 * 8) + 1)); }
#undef F_IMPL
#undef G_IMPL
#undef F_ARITY
#undef G_ARITY
#define F_IMPL(x) v(x)
#define PROG ML99_TERMS(v(1), v(, ), v(2), v(, ), ML99_call(F, v(7)))
#define CHECK(...) CHECK_AUX(__VA_ARGS__)
#define CHECK_AUX(a, b, c) ML99_ASSERT_UNEVAL(a == 1 && b == 2 && c == 7)
// ML99_QUOTE
{ CHECK(ML99_EVAL(ML99_EVAL(ML99_QUOTE(PROG)))); }
#undef F_IMPL
#undef PROG
#undef CHECK
#undef CHECK_AUX
}
|