├── README.md └── zlang.h /README.md: -------------------------------------------------------------------------------- 1 | ZLang 2 | ===== 3 | 4 | A plugin framework for namespace macros in C/C++. 5 | 6 | Synopsis 7 | -------- 8 | 9 | One problem with macros is that they invade the global namespace, and if we are not careful, can inadvertently replace an unrelated token. For example, if we were to define a `greet` macro like this: 10 | 11 | #define greet(x) Hello x 12 | 13 | Perhaps, another developer unaware of our `greet` macro decides to add a `greet` function: 14 | 15 | // This won't compile since the following line expands to: 16 | // 17 | // void hello const char * msg 18 | // 19 | // Which is not correct C/C++. 20 | // 21 | void greet(const char * msg) 22 | { 23 | ... 24 | } 25 | 26 | And if you aren't using gcc or clang, the developer will most likely be left with confusion why this fails with a compile error. So, in general, we use a convention such that our macro must be written with all caps, like this: 27 | 28 | #define GREET(x) Hello x 29 | 30 | Well this is starting to look ugly, but it helps a little, until we decide to use LibAmigo and it defines another `GREET` macro like this: 31 | 32 | #define GREET(x) Hola x 33 | 34 | Uh-oh, now we have two different behaviors depending on what files we include. This is could get suprising, so we decide to prefix all our macros with a unique namespace like `FOO` for example: 35 | 36 | #define FOO_GREET(x) Hello x 37 | 38 | Now, its gotten even uglier. Well ZLang can help solve these problems without uglifying macros like this. 39 | 40 | Usage 41 | ----- 42 | 43 | Lets start with our greeting macros: 44 | 45 | FOO_GREET(world) // Expands to Hello world 46 | 47 | ZLang provides a way to call this macro, like this: 48 | 49 | $(greet world) // Expands to Hello world 50 | 51 | or fully qualified like this: 52 | 53 | $(foo_greet world) // Expands to Hello world 54 | 55 | It uses the `$` as the entry point. If this can't be used(on a few legacy platforms the `$` is not supported), the `ZLANG` macro can be used instead: 56 | 57 | ZLANG(greet world) // Expands to Hello world 58 | 59 | To plug our `FOO_GREET` macro into ZLang we have to register it first. This is done by defining a macro by appending our name to the `ZLANG_` macro and then defining it to our macro with parenthesis around it, like this: 60 | 61 | // Notice the space between the macro name and the parenthesis. 62 | #define ZLANG_foo_greet (FOO_GREET) 63 | 64 | This will let us now use our macro like this: 65 | 66 | $(foo_greet world) // Expands to Hello world 67 | 68 | This is the fully qualified name, we can define `ZLANG_NS` to `foo`(perhaps during the build with `-DZLANG_NS=foo`), so we can now use: 69 | 70 | $(greet world) // Expands to Hello world 71 | 72 | Up to 8 namespaces can be specified, and it will search through them until it can find a matching name. It does this by prepending the name to the name given by the user. So say, `ZLANG_NS` was defined to `bar,foo` it will first see if `bar_greet` is valid and then it will try `foo_greet`, which is valid. 73 | 74 | Additionally, the `ZLANG_NS` can be overridden locally. This can be useful for libraries writers who want to define namespaces without overriding the user defined namespaces. To override, just define `ZLANG_USE` at the top of the file, and undefine it at the end of the file, like this for using namespace `bar` and `foo`: 75 | 76 | #define ZLANG_USE (bar,foo) 77 | 78 | $(greet world) 79 | 80 | #undef ZLANG_USE 81 | 82 | The `ZLANG_USE` macro does require parenthesis around the namespace definitions. 83 | 84 | Requirements 85 | ------------ 86 | 87 | This has been tested on gcc, clang, and msvc preprocessors. ZLang is one header, and has no dependencies. Also, to register macros does not require the ZLang header. Its only required for usage. This can allow a library to optionally register macros with ZLang, without needing a ZLang dependency. 88 | -------------------------------------------------------------------------------- /zlang.h: -------------------------------------------------------------------------------- 1 | /*============================================================================= 2 | Copyright (c) 2012 Paul Fultz II 3 | zlang.h 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | ==============================================================================*/ 7 | 8 | #ifndef ZLANG_GUARD_ZLANG_H 9 | #define ZLANG_GUARD_ZLANG_H 10 | 11 | #ifndef _MSC_VER 12 | #define Z_ZLANG_CAT_I(x, y) x ## y 13 | #else 14 | // MSVC workarounds 15 | #define Z_ZLANG_CAT_I(a, b) Z_ZLANG_CAT_X(~, a ## b) 16 | #define Z_ZLANG_CAT_X(p, x) x 17 | #endif 18 | #define Z_ZLANG_CAT(x, y) Z_ZLANG_CAT_I(x, y) 19 | 20 | #define Z_ZLANG_IF(c) Z_ZLANG_CAT(Z_ZLANG_IF_, c) 21 | #define Z_ZLANG_IF_0(t, f) f 22 | #define Z_ZLANG_IF_1(t, f) t 23 | 24 | #define Z_ZLANG_IF_INVOKE(m, ...) Z_ZLANG_IF(m(__VA_ARGS__)) 25 | #define Z_ZLANG_REM(...) __VA_ARGS__ 26 | 27 | 28 | #define Z_ZLANG_IS_PAREN(x) Z_ZLANG_IS_PAREN_CHECK(Z_ZLANG_IS_PAREN_PROBE x) 29 | #define Z_ZLANG_IS_PAREN_CHECK(...) Z_ZLANG_IS_PAREN_CHECK_N(__VA_ARGS__,0) 30 | #define Z_ZLANG_IS_PAREN_PROBE(...) ~, 1, 31 | #ifndef _MSC_VER 32 | #define Z_ZLANG_IS_PAREN_CHECK_N(x, n, ...) n 33 | #else 34 | // MSVC workarounds 35 | #define Z_ZLANG_IS_PAREN_CHECK_RES(x) x 36 | #define Z_ZLANG_IS_PAREN_CHECK_II(x, n, ...) n 37 | #define Z_ZLANG_IS_PAREN_CHECK_I(x) Z_ZLANG_IS_PAREN_CHECK_RES(Z_ZLANG_IS_PAREN_CHECK_II x) 38 | #define Z_ZLANG_IS_PAREN_CHECK_N(...) Z_ZLANG_IS_PAREN_CHECK_I((__VA_ARGS__)) 39 | #endif 40 | 41 | #define ZLANG__NIL (Z_ZLANG_ERROR_NOT_FOUND) 42 | #define ZLANG__OOB (Z_ZLANG_ERROR_TOO_MANY) 43 | 44 | // TODO: When a match is found it gets qualified twice, perhaps there is a way 45 | // to make sure we only call it once 46 | #define Z_ZLANG_QUALIFY(ns, x) Z_ZLANG_CAT(ZLANG_, Z_ZLANG_CAT(Z_ZLANG_CAT(ns, _), x)) 47 | 48 | #define Z_ZLANG_NOT_FOUND(ns, x) Z_ZLANG_CAT(ZLANG_, ns) Z_ZLANG_CAT(ZLANG__NAMESPACE__, x) 49 | #define Z_ZLANG_TRY_QUALIFY(ns, x) Z_ZLANG_IF(Z_ZLANG_IS_PAREN(Z_ZLANG_CAT(ZLANG_, ns)))(Z_ZLANG_NOT_FOUND, Z_ZLANG_QUALIFY)(ns, x) 50 | 51 | 52 | 53 | #define Z_ZLANG_FIND_FALSE(...) _NIL Z_ZLANG_FIND_FALSE_1 54 | #define Z_ZLANG_FIND_FALSE_1(...) Z_ZLANG_FIND_FALSE_2 55 | #define Z_ZLANG_FIND_FALSE_2(...) 56 | 57 | #define Z_ZLANG_FIND_TRUE(p, d, x, ...) x 58 | 59 | #define Z_ZLANG_DOMAIN(...) _OOB 60 | 61 | 62 | #ifndef _MSC_VER 63 | #define Z_ZLANG_FIND(p, d, ...) Z_ZLANG_FIND_1(p, d, ~, __VA_ARGS__, (), ()) 64 | #define Z_ZLANG_FIND_1(p, d, q, x, ...) Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_2)(p, d, x, __VA_ARGS__) 65 | #define Z_ZLANG_FIND_2(p, d, q, x, ...) Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_3)(p, d, x, __VA_ARGS__) 66 | #define Z_ZLANG_FIND_3(p, d, q, x, ...) Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_4)(p, d, x, __VA_ARGS__) 67 | #define Z_ZLANG_FIND_4(p, d, q, x, ...) Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_5)(p, d, x, __VA_ARGS__) 68 | #define Z_ZLANG_FIND_5(p, d, q, x, ...) Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_6)(p, d, x, __VA_ARGS__) 69 | #define Z_ZLANG_FIND_6(p, d, q, x, ...) Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_7)(p, d, x, __VA_ARGS__) 70 | #define Z_ZLANG_FIND_7(p, d, q, x, ...) Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_8)(p, d, x, __VA_ARGS__) 71 | #define Z_ZLANG_FIND_8(p, d, q, x, ...) Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_DOMAIN)(p, d, x, __VA_ARGS__) 72 | #else 73 | // MSVC workarounds 74 | #define Z_ZLANG_MSVC_INVOKE_0(m, args) Z_ZLANG_MSVC_INVOKE_X_0(m args) 75 | #define Z_ZLANG_MSVC_INVOKE_1(m, args) Z_ZLANG_MSVC_INVOKE_X_1(m args) 76 | #define Z_ZLANG_MSVC_INVOKE_2(m, args) Z_ZLANG_MSVC_INVOKE_X_2(m args) 77 | #define Z_ZLANG_MSVC_INVOKE_3(m, args) Z_ZLANG_MSVC_INVOKE_X_3(m args) 78 | #define Z_ZLANG_MSVC_INVOKE_4(m, args) Z_ZLANG_MSVC_INVOKE_X_4(m args) 79 | #define Z_ZLANG_MSVC_INVOKE_5(m, args) Z_ZLANG_MSVC_INVOKE_X_5(m args) 80 | #define Z_ZLANG_MSVC_INVOKE_6(m, args) Z_ZLANG_MSVC_INVOKE_X_6(m args) 81 | #define Z_ZLANG_MSVC_INVOKE_7(m, args) Z_ZLANG_MSVC_INVOKE_X_7(m args) 82 | #define Z_ZLANG_MSVC_INVOKE_8(m, args) Z_ZLANG_MSVC_INVOKE_X_8(m args) 83 | 84 | #define Z_ZLANG_MSVC_INVOKE_X_0(x) x 85 | #define Z_ZLANG_MSVC_INVOKE_X_1(x) x 86 | #define Z_ZLANG_MSVC_INVOKE_X_2(x) x 87 | #define Z_ZLANG_MSVC_INVOKE_X_3(x) x 88 | #define Z_ZLANG_MSVC_INVOKE_X_4(x) x 89 | #define Z_ZLANG_MSVC_INVOKE_X_5(x) x 90 | #define Z_ZLANG_MSVC_INVOKE_X_6(x) x 91 | #define Z_ZLANG_MSVC_INVOKE_X_7(x) x 92 | #define Z_ZLANG_MSVC_INVOKE_X_8(x) x 93 | 94 | #define Z_ZLANG_FIND(p, d, ...) Z_ZLANG_MSVC_INVOKE_0(Z_ZLANG_FIND_1,(p, d, ~, __VA_ARGS__, (), ())) 95 | #define Z_ZLANG_FIND_1(p, d, q, x, ...) Z_ZLANG_MSVC_INVOKE_1(Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_2), (p, d, x, __VA_ARGS__)) 96 | #define Z_ZLANG_FIND_2(p, d, q, x, ...) Z_ZLANG_MSVC_INVOKE_2(Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_3), (p, d, x, __VA_ARGS__)) 97 | #define Z_ZLANG_FIND_3(p, d, q, x, ...) Z_ZLANG_MSVC_INVOKE_3(Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_4), (p, d, x, __VA_ARGS__)) 98 | #define Z_ZLANG_FIND_4(p, d, q, x, ...) Z_ZLANG_MSVC_INVOKE_4(Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_5), (p, d, x, __VA_ARGS__)) 99 | #define Z_ZLANG_FIND_5(p, d, q, x, ...) Z_ZLANG_MSVC_INVOKE_5(Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_6), (p, d, x, __VA_ARGS__)) 100 | #define Z_ZLANG_FIND_6(p, d, q, x, ...) Z_ZLANG_MSVC_INVOKE_6(Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_7), (p, d, x, __VA_ARGS__)) 101 | #define Z_ZLANG_FIND_7(p, d, q, x, ...) Z_ZLANG_MSVC_INVOKE_7(Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_FIND_8), (p, d, x, __VA_ARGS__)) 102 | #define Z_ZLANG_FIND_8(p, d, q, x, ...) Z_ZLANG_MSVC_INVOKE_8(Z_ZLANG_IF(Z_ZLANG_IS_PAREN(x))(Z_ZLANG_FIND_FALSE, Z_ZLANG_IF_INVOKE)(p, d, x)(Z_ZLANG_FIND_TRUE, Z_ZLANG_DOMAIN), (p, d, x, __VA_ARGS__)) 103 | #endif 104 | 105 | 106 | 107 | 108 | 109 | #define Z_ZLANG_INVOKE_REM(m) m, 110 | 111 | #define Z_ZLANG_PRIMITIVE_INVOKE(m, x) m(x) 112 | #define Z_ZLANG_PRIMITIVE_INVOKE_I(x) Z_ZLANG_PRIMITIVE_INVOKE x 113 | 114 | #define Z_ZLANG_INVOKE(x) Z_ZLANG_PRIMITIVE_INVOKE_I((Z_ZLANG_INVOKE_REM x)) 115 | 116 | #define Z_ZLANG_SEARCH_PREDICATE(d, x) Z_ZLANG_IS_PAREN(Z_ZLANG_QUALIFY(x, d)) 117 | #define Z_ZLANG_SEARCH_SELECT_NS() Z_ZLANG_IF(Z_ZLANG_IS_PAREN(ZLANG_USE))(Z_ZLANG_REM ZLANG_USE, ZLANG_NS) 118 | #define Z_ZLANG_SEARCH_NS(m, x) Z_ZLANG_TRY_QUALIFY(Z_ZLANG_FIND(Z_ZLANG_SEARCH_PREDICATE, x, Z_ZLANG_SEARCH_SELECT_NS()), x) 119 | #define Z_ZLANG_SEARCH_FIRST(m, x) m 120 | #define Z_ZLANG_SEARCH_I(m, x) Z_ZLANG_IF(Z_ZLANG_IS_PAREN(m))(Z_ZLANG_SEARCH_FIRST, Z_ZLANG_SEARCH_NS)(m, x) 121 | #define Z_ZLANG_SEARCH(x) Z_ZLANG_SEARCH_I(Z_ZLANG_CAT(ZLANG_, x), x) 122 | 123 | #define ZLANG(x) Z_ZLANG_INVOKE(Z_ZLANG_SEARCH(x)) 124 | 125 | 126 | #ifndef ZLANG_DONT_USE_DOLLAR_SIGN 127 | #define $ ZLANG 128 | #endif 129 | 130 | // #define ZLANG_NS a, b, c, zlang 131 | // #define ZLANG_USE (a, b, zlang2) 132 | // #define TEST1(x) x 133 | // #define ZLANG_zlang_test (TEST1) 134 | 135 | // #define TEST2(x) 0 136 | // #define ZLANG_zlang2_test (TEST2) 137 | 138 | // $(test passed) 139 | // $(zlang_test passed) 140 | 141 | #endif 142 | 143 | --------------------------------------------------------------------------------