| @@ -0,0 +1,101 @@ |
| 1 | +#define M_C2I(a, ...) a ## __VA_ARGS__ |
| 2 | +#define M_C(a, ...) M_C2I(a, __VA_ARGS__) |
| 3 | +#define M_C3I(a, b, ...) a ## b ## __VA_ARGS__ |
| 4 | +#define M_C3(a, b, ...) M_C3I(a ,b, __VA_ARGS__) |
| 5 | + |
| 6 | +#define M_RETI_ARG2(a, b, ...) b |
| 7 | +#define M_RET_ARG2(...) M_RETI_ARG2(__VA_ARGS__) |
| 8 | +#define M_RETI_ARG27(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa, ...) aa |
| 9 | +#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__) |
| 10 | + |
| 11 | +#define M_TOBOOLI_0 1, 0, |
| 12 | +#define M_BOOL(x) M_RET_ARG2(M_C(M_TOBOOLI_, x), 1, useless) |
| 13 | + |
| 14 | +#define M_IFI_0(true_macro, ...) __VA_ARGS__ |
| 15 | +#define M_IFI_1(true_macro, ...) true_macro |
| 16 | +#define M_IF(c) M_C(M_IFI_, M_BOOL(c)) |
| 17 | + |
| 18 | +#define M_FLAT(...) __VA_ARGS__ |
| 19 | +#define M_INVI_0 1 |
| 20 | +#define M_INVI_1 0 |
| 21 | +#define M_INV(x) M_C(M_INVI_, x) |
| 22 | + |
| 23 | +#define M_ANDI_00 0 |
| 24 | +#define M_ANDI_01 0 |
| 25 | +#define M_ANDI_10 0 |
| 26 | +#define M_ANDI_11 1 |
| 27 | +#define M_AND(x,y) M_C3(M_ANDI_, x, y) |
| 28 | + |
| 29 | +#define M_ORI_00 0 |
| 30 | +#define M_ORI_01 1 |
| 31 | +#define M_ORI_10 1 |
| 32 | +#define M_ORI_11 1 |
| 33 | +#define M_OR(x,y) M_C3(M_ORI_, x, y) |
| 34 | + |
| 35 | +#define M_COMMA_P(...) M_RET_ARG27(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, useless) |
| 36 | + |
| 37 | +#define M_EMPTYI_DETECT(...) 0, 1, |
| 38 | +#define M_EMPTYI_P_C1(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__ ()) |
| 39 | +#define M_EMPTYI_P_C2(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__) |
| 40 | +#define M_EMPTYI_P_C3(...) M_COMMA_P(__VA_ARGS__ () ) |
| 41 | +#define M_EMPTY_P(...) M_AND(M_EMPTYI_P_C1(__VA_ARGS__), M_INV(M_OR(M_OR(M_EMPTYI_P_C2(__VA_ARGS__), M_COMMA_P(__VA_ARGS__)),M_EMPTYI_P_C3(__VA_ARGS__)))) |
| 42 | +#define M_APPLY_FUNC2B(func, arg1, arg2) \ |
| 43 | + M_IF(M_EMPTY_P(arg2))(,func(arg1, arg2)) |
| 44 | +#define M_MAP2B_0(func, data, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,...) \ |
| 45 | + M_APPLY_FUNC2B(func, data, a) M_APPLY_FUNC2B(func, data, b) M_APPLY_FUNC2B(func, data, c) \ |
| 46 | + M_APPLY_FUNC2B(func, data, d) M_APPLY_FUNC2B(func, data, e) M_APPLY_FUNC2B(func, data, f) \ |
| 47 | + M_APPLY_FUNC2B(func, data, g) M_APPLY_FUNC2B(func, data, h) M_APPLY_FUNC2B(func, data, i) \ |
| 48 | + M_APPLY_FUNC2B(func, data, j) M_APPLY_FUNC2B(func, data, k) M_APPLY_FUNC2B(func, data, l) \ |
| 49 | + M_APPLY_FUNC2B(func, data, m) M_APPLY_FUNC2B(func, data, n) M_APPLY_FUNC2B(func, data, o) \ |
| 50 | + M_APPLY_FUNC2B(func, data, p) M_APPLY_FUNC2B(func, data, q) M_APPLY_FUNC2B(func, data, r) \ |
| 51 | + M_APPLY_FUNC2B(func, data, s) M_APPLY_FUNC2B(func, data, t) M_APPLY_FUNC2B(func, data, u) \ |
| 52 | + M_APPLY_FUNC2B(func, data, v) M_APPLY_FUNC2B(func, data, w) M_APPLY_FUNC2B(func, data, x) \ |
| 53 | + M_APPLY_FUNC2B(func, data, y) M_APPLY_FUNC2B(func, data, z) |
| 54 | +#define M_MAP2B(f, ...) M_MAP2B_0(f, __VA_ARGS__, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ) |
| 55 | +#define M_INIT_INIT(a) ,a, |
| 56 | + |
| 57 | +#define M_GET_METHOD(method, method_default, ...) \ |
| 58 | + M_RET_ARG2 (M_MAP2B(M_C, M_C3(M_, method, _), __VA_ARGS__), method_default,) |
| 59 | + |
| 60 | +#define M_TEST_METHOD_P(method, oplist) \ |
| 61 | + M_BOOL(M_GET_METHOD (method, 0, M_FLAT oplist)) |
| 62 | + |
| 63 | +#define TRUE 1 |
| 64 | +#define TEST1(n) \ |
| 65 | + M_IF(n)(ok,nok) |
| 66 | +#define TEST2(op) \ |
| 67 | + M_TEST_METHOD_P(INIT, op) |
| 68 | +#define TEST3(op) \ |
| 69 | + M_IF(M_TEST_METHOD_P(INIT, op))(ok, nok) |
| 70 | +#define TEST4(op) \ |
| 71 | + TEST1(TEST2(op)) |
| 72 | +#define KO(a) ((void)1) |
| 73 | + |
| 74 | +/* This checks that the various expansions that ultimately lead to |
| 75 | + something like 'KO(arg,arg)', where 'KO' comes from a macro |
| 76 | + expansion reducing from a large macro chain do not are regarded |
| 77 | + as funclike macro invocation of KO. E.g. X93 and X94 expand to 'KO', |
| 78 | + but X95 must not consume the (a,b) arguments outside the M_IF() |
| 79 | + invocation to reduce the 'KO' macro to an invocation. Instead |
| 80 | + X95 should reduce via M_IF(KO)(a,b) to 'a'. |
| 81 | + |
| 82 | + The other lines here are variations on this scheme, with X1 to |
| 83 | + X6 coming from the bug report at |
| 84 | + http://lists.nongnu.org/archive/html/tinycc-devel/2017-07/msg00017.html */ |
| 85 | +X92 M_IF(KO) |
| 86 | +X93 M_GET_METHOD(INIT, 0, INIT(KO)) |
| 87 | +X94 M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))) |
| 88 | +X95 M_IF(M_GET_METHOD(INIT, 0, INIT(KO)))(a,b) |
| 89 | +X96 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO)))) |
| 90 | +X97 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))))(ok,nok) |
| 91 | +X98 (M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok) |
| 92 | +X99 M_IF(M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok) |
| 93 | +// test begins |
| 94 | +X1 TEST1(TRUE) // ==> expect ok, get ok |
| 95 | +// First test with a token which is not a macro |
| 96 | +X2 TEST2((INIT(ok))) // ==> expect 1, get 1 |
| 97 | +X3 TEST3((INIT(ok))) // ==> expect ok, get ok |
| 98 | +// Then test with a token which is a macro, but should not be expanded. |
| 99 | +X4 TEST2((INIT(KO))) // ==> expect 1, get 1 |
| 100 | +X5 TEST4(INIT(KO)) |
| 101 | +X6 TEST3((INIT(KO))) // ==> expect ok, get "error: macro 'KO' used with too many args" |