Commit 7ddee86d authored by David Gibson's avatar David Gibson

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: default avatarDavid Gibson <david@gibson.dropbear.id.au>
parent 395a2f84
......@@ -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 */
......@@ -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();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment