From 7ddee86d9ac424dbec04583e37e9584375bd6d74 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 26 Jan 2016 21:32:07 +1100 Subject: [PATCH] cppmagic: Allow multiple and deferred evaluation Recursion (and therefore iteration) in cpp is difficult, since the preprocessor explicitly looks for and inhibits recursion. But, it's possible to trick it, up to a point. CPPMAGIC_DEFER1() and CPPMAGIC_DEFER2() can "hide" a macro, preventing it from being expanded and being noticed as recursion. Along with that we need to cause extra expansion passes to be executed. There has to be a finite limit here - true recursion is impossible - but that number can be made very large pretty easily. CPPMAGIC_EVAL() multiply expands its argument(s) - up to 1024 times. Signed-off-by: David Gibson --- ccan/cppmagic/cppmagic.h | 35 +++++++++++++++++++++++++++++++++++ ccan/cppmagic/test/run.c | 9 ++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/ccan/cppmagic/cppmagic.h b/ccan/cppmagic/cppmagic.h index b5c35782..8acbba71 100644 --- a/ccan/cppmagic/cppmagic.h +++ b/ccan/cppmagic/cppmagic.h @@ -98,4 +98,39 @@ #define CPPMAGIC_IFELSE(cond_) \ _CPPMAGIC_IFELSE(CPPMAGIC_NONZERO(cond_)) +/** + * CPPMAGIC_EVAL - force multiple expansion passes + * + * Forces macros in the arguments to be expanded repeatedly (up to + * 1024 times) even when CPP would usually stop expanding. + */ +#define CPPMAGIC_EVAL1(...) __VA_ARGS__ +#define CPPMAGIC_EVAL2(...) \ + CPPMAGIC_EVAL1(CPPMAGIC_EVAL1(__VA_ARGS__)) +#define CPPMAGIC_EVAL4(...) \ + CPPMAGIC_EVAL2(CPPMAGIC_EVAL2(__VA_ARGS__)) +#define CPPMAGIC_EVAL8(...) \ + CPPMAGIC_EVAL4(CPPMAGIC_EVAL4(__VA_ARGS__)) +#define CPPMAGIC_EVAL16(...) \ + CPPMAGIC_EVAL8(CPPMAGIC_EVAL8(__VA_ARGS__)) +#define CPPMAGIC_EVAL32(...) \ + CPPMAGIC_EVAL16(CPPMAGIC_EVAL16(__VA_ARGS__)) +#define CPPMAGIC_EVAL64(...) \ + CPPMAGIC_EVAL32(CPPMAGIC_EVAL32(__VA_ARGS__)) +#define CPPMAGIC_EVAL128(...) \ + CPPMAGIC_EVAL64(CPPMAGIC_EVAL64(__VA_ARGS__)) +#define CPPMAGIC_EVAL256(...) \ + CPPMAGIC_EVAL128(CPPMAGIC_EVAL128(__VA_ARGS__)) +#define CPPMAGIC_EVAL512(...) \ + CPPMAGIC_EVAL256(CPPMAGIC_EVAL256(__VA_ARGS__)) +#define CPPMAGIC_EVAL1024(...) \ + CPPMAGIC_EVAL512(CPPMAGIC_EVAL512(__VA_ARGS__)) +#define CPPMAGIC_EVAL(...) CPPMAGIC_EVAL1024(__VA_ARGS__) + +/** + * CPPMAGIC_DEFER1, CPPMAGIC_DEFER2 - defer expansion + */ +#define CPPMAGIC_DEFER1(a_) a_ CPPMAGIC_NOTHING() +#define CPPMAGIC_DEFER2(a_) a_ CPPMAGIC_NOTHING CPPMAGIC_NOTHING()() + #endif /* CCAN_CPPMAGIC_H */ diff --git a/ccan/cppmagic/test/run.c b/ccan/cppmagic/test/run.c index 0f8917d6..2aa95303 100644 --- a/ccan/cppmagic/test/run.c +++ b/ccan/cppmagic/test/run.c @@ -15,9 +15,12 @@ static inline void check1(const char *orig, const char *expand, #define CHECK1(orig, match) \ check1(#orig, CPPMAGIC_STRINGIFY(orig), match) +#define TESTRECURSE() R CPPMAGIC_DEFER1(_TESTRECURSE)()() +#define _TESTRECURSE() TESTRECURSE + int main(void) { - plan_tests(24); + plan_tests(27); CHECK1(CPPMAGIC_NOTHING(), ""); CHECK1(CPPMAGIC_GLUE2(a, b), "ab"); @@ -51,6 +54,10 @@ int main(void) CHECK1(CPPMAGIC_IFELSE(1)(abc)(def), "abc"); CHECK1(CPPMAGIC_IFELSE(not zero)(abc)(def), "abc"); + CHECK1(TESTRECURSE(), "R R _TESTRECURSE ()()"); + CHECK1(CPPMAGIC_EVAL1(TESTRECURSE()), "R R R _TESTRECURSE ()()"); + CHECK1(CPPMAGIC_EVAL2(TESTRECURSE()), "R R R R R _TESTRECURSE ()()"); + /* This exits depending on whether all tests passed */ return exit_status(); } -- 2.39.2