From 7ae50ea507a10ff99b269313064540019ad59004 Mon Sep 17 00:00:00 2001 From: Nephrite Date: Mon, 5 Feb 2024 04:28:27 +0900 Subject: [PATCH] Metaprogram (#3968) * metaprogram.h Created by Mr. Griffin. Removed non-relevant parts * Added DEFAULT/DEFAULT_2 macros Also added a demonstration in battle_main * Removed GET_ARGS * Expanded DEFAULT Because why not? * Added EXCEPT Expands to everything but the first x arguments. * Added BIT_INDEX (thanks to MGriffin) and COMPRESS_BIT macros These let you compress a bit up to a word in size inside a single byte and uncompress at the same time. BIT_INDEX just tells you where the bit is. * Updated HANDLE_EXPANDED_MOVE_NAME --------- Co-authored-by: Martin Griffin --- include/global.h | 14 +---- include/metaprogram.h | 131 ++++++++++++++++++++++++++++++++++++++++++ src/battle_main.c | 126 ++++++++++++++++++++-------------------- src/data/moves_info.h | 3 +- 4 files changed, 195 insertions(+), 79 deletions(-) create mode 100644 include/metaprogram.h diff --git a/include/global.h b/include/global.h index e9756df212..49095a5cd9 100644 --- a/include/global.h +++ b/include/global.h @@ -6,6 +6,7 @@ #include "config.h" // we need to define config before gba headers as print stuff needs the functions nulled before defines. #include "gba/gba.h" #include "fpmath.h" +#include "metaprogram.h" #include "constants/global.h" #include "constants/flags.h" #include "constants/vars.h" @@ -123,19 +124,6 @@ #define NUM_FLAG_BYTES ROUND_BITS_TO_BYTES(FLAGS_COUNT) #define NUM_TRENDY_SAYING_BYTES ROUND_BITS_TO_BYTES(NUM_TRENDY_SAYINGS) -// Calls m0/m1/.../m8 depending on how many arguments are passed. -#define VARARG_8(m, ...) CAT(m, NARG_8(__VA_ARGS__))(__VA_ARGS__) - -// This returns the number of arguments passed to it (up to 8). -#define NARG_8(...) NARG_8_(_, ##__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0) -#define NARG_8_(_, a, b, c, d, e, f, g, h, N, ...) N - -#define CAT(a, b) CAT_(a, b) -#define CAT_(a, b) a ## b - -#define STR(...) STR_(__VA_ARGS__) -#define STR_(...) #__VA_ARGS__ - // Converts a string to a compound literal, essentially making it a pointer to const u8 #define COMPOUND_STRING(str) (const u8[]) _(str) diff --git a/include/metaprogram.h b/include/metaprogram.h new file mode 100644 index 0000000000..f0d6d9a81f --- /dev/null +++ b/include/metaprogram.h @@ -0,0 +1,131 @@ +/* Macros to aid with metaprogramming. */ +#ifndef METAPROGRAM_H +#define METAPROGRAM_H + +/* Calls m0/m1/.../m8 depending on how many arguments are passed. */ +#define VARARG_8(m, ...) CAT(m, NARG_8(__VA_ARGS__))(__VA_ARGS__) + +/* Returns the number of arguments passed to it (up to 8). */ +#define NARG_8(...) NARG_8_(_, ##__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#define NARG_8_(_, a, b, c, d, e, f, g, h, N, ...) N + +/* Expands 'a' and 'b' and then concatenates them. */ +#define CAT(a, b) CAT_(a, b) +#define CAT_(a, b) a ## b + +/* Expands '__VA_ARGS__' and then stringizes them. */ +#define STR(...) STR_(__VA_ARGS__) +#define STR_(...) #__VA_ARGS__ + +/* Expands to the first/second/third/fourth argument. */ +#define FIRST(a, ...) a +#define SECOND(a, ...) __VA_OPT__(FIRST(__VA_ARGS__)) +#define THIRD(a, ...) __VA_OPT__(SECOND(__VA_ARGS__)) +#define FOURTH(a, ...) __VA_OPT__(THIRD(__VA_ARGS__)) + +/* Expands to everything but the first x arguments */ +#define EXCEPT_1(a, ...) __VA_OPT__(__VA_ARGS__) +#define EXCEPT_2(a, ...) __VA_OPT__(EXCEPT_1(__VA_ARGS__)) +#define EXCEPT_3(a, ...) __VA_OPT__(EXCEPT_2(__VA_ARGS__)) +#define EXCEPT_4(a, ...) __VA_OPT__(EXCEPT_3(__VA_ARGS__)) + +/* 'UNPACK (x, y, z)' expands to 'x, y, z'. + * Useful for passing arguments which may contain commas into a macro. */ +#define UNPACK(...) __VA_ARGS__ + +/* Expands to 'macro(...args, ...)'. */ +#define INVOKE_WITH(macro, args, ...) INVOKE_WITH_(macro, UNPACK args __VA_OPT__(, __VA_ARGS__)) +#define INVOKE_WITH_(macro, ...) macro(__VA_ARGS__) + +/* Recursive macros. + * Based on https://www.scs.stanford.edu/~dm/blog/va-opt.html + * + * Macros prefixed with R_ are recursive, to correctly expand them the + * top-level macro which references them should use 'RECURSIVELY' around + * them. 'RECURSIVELY' cannot be nested, hence the top-level macro must + * use it so that a recursive macro is able to reference another + * recursive macro. */ + +#define RECURSIVELY(...) RECURSIVELY_4(RECURSIVELY_4(RECURSIVELY_4(RECURSIVELY_4(__VA_ARGS__)))) +#define RECURSIVELY_4(...) RECURSIVELY_3(RECURSIVELY_3(RECURSIVELY_3(RECURSIVELY_3(__VA_ARGS__)))) +#define RECURSIVELY_3(...) RECURSIVELY_2(RECURSIVELY_2(RECURSIVELY_2(RECURSIVELY_2(__VA_ARGS__)))) +#define RECURSIVELY_2(...) RECURSIVELY_1(RECURSIVELY_1(RECURSIVELY_1(RECURSIVELY_1(__VA_ARGS__)))) +#define RECURSIVELY_1(...) __VA_ARGS__ + +/* Useful for deferring expansion until the second scan. See + * https://www.scs.stanford.edu/~dm/blog/va-opt.html for more info. */ +#define PARENS () + +/* Expands to 'macro(a)' for each 'a' in '...' */ +#define R_FOR_EACH(macro, ...) __VA_OPT__(R_FOR_EACH_(macro, __VA_ARGS__)) +#define R_FOR_EACH_(macro, a, ...) macro(a) __VA_OPT__(R_FOR_EACH_P PARENS (macro, __VA_ARGS__)) +#define R_FOR_EACH_P() R_FOR_EACH_ + +/* Expands to 'macro(...args, a)' for each 'a' in '...'. */ +#define R_FOR_EACH_WITH(macro, args, ...) __VA_OPT__(R_FOR_EACH_WITH_(macro, args, __VA_ARGS__)) +#define R_FOR_EACH_WITH_(macro, args, a, ...) INVOKE_WITH(macro, args, a) __VA_OPT__(R_FOR_EACH_WITH_P PARENS (macro, args, __VA_ARGS__)) +#define R_FOR_EACH_WITH_P() R_FOR_EACH_WITH_ + +/* Picks the xth VA_ARG if it exists, otherwise returns a default value */ +#define DEFAULT(_default, ...) FIRST(__VA_OPT__(__VA_ARGS__, ) _default) +#define DEFAULT_2(_default, ...) DEFAULT(_default __VA_OPT__(, SECOND(__VA_ARGS__))) +#define DEFAULT_3(_default, ...) DEFAULT(_default __VA_OPT__(, THIRD(__VA_ARGS__))) +#define DEFAULT_4(_default, ...) DEFAULT(_default __VA_OPT__(, FOURTH(__VA_ARGS__))) + +/* (Credit to MGriffin) A rather monstrous way of finding the set bit in a word. +Invalid input causes a compiler error. Sample: https://cexplore.karathan.at/z/x1hm7B */ +#define BIT_INDEX(n) \ + (n) == (1 << 0) ? 0 : \ + (n) == (1 << 1) ? 1 : \ + (n) == (1 << 2) ? 2 : \ + (n) == (1 << 3) ? 3 : \ + (n) == (1 << 4) ? 4 : \ + (n) == (1 << 5) ? 5 : \ + (n) == (1 << 6) ? 6 : \ + (n) == (1 << 7) ? 7 : \ + (n) == (1 << 8) ? 8 : \ + (n) == (1 << 9) ? 9 : \ + (n) == (1 << 10) ? 10 : \ + (n) == (1 << 11) ? 11 : \ + (n) == (1 << 12) ? 12 : \ + (n) == (1 << 13) ? 13 : \ + (n) == (1 << 14) ? 14 : \ + (n) == (1 << 15) ? 15 : \ + (n) == (1 << 16) ? 16 : \ + (n) == (1 << 17) ? 17 : \ + (n) == (1 << 18) ? 18 : \ + (n) == (1 << 19) ? 19 : \ + (n) == (1 << 20) ? 20 : \ + (n) == (1 << 21) ? 21 : \ + (n) == (1 << 22) ? 22 : \ + (n) == (1 << 23) ? 23 : \ + (n) == (1 << 24) ? 24 : \ + (n) == (1 << 25) ? 25 : \ + (n) == (1 << 26) ? 26 : \ + (n) == (1 << 27) ? 27 : \ + (n) == (1 << 28) ? 28 : \ + (n) == (1 << 29) ? 29 : \ + (n) == (1 << 30) ? 30 : \ + (n) == (1 << 31) ? 31 : \ + *(u32 *)NULL + +#define COMPRESS_BITS_0 0, 1 +#define COMPRESS_BITS_1 1, 1 +#define COMPRESS_BITS_2 2, 1 +#define COMPRESS_BITS_3 3, 1 +#define COMPRESS_BITS_4 4, 1 +#define COMPRESS_BITS_5 5, 1 +#define COMPRESS_BITS_6 6, 1 +#define COMPRESS_BITS_7 7, 1 + +/* Will try and compress a set bit (or up to three sequential bits) into a single byte +Input must be of the form (upper << lower) where upper can be up to 3, lower up to 31 */ +#define COMPRESS_BITS(_val) COMPRESS_BITS_STEP_2 _val +#define COMPRESS_BITS_STEP_2(_unpacked) COMPRESS_BITS_STEP_3(COMPRESS_BITS_## _unpacked) +#define COMPRESS_BITS_STEP_3(...) COMPRESS_BITS_STEP_4(__VA_ARGS__) +#define COMPRESS_BITS_STEP_4(upper, lower) (((upper % 8) << 5) + (BIT_INDEX(lower))) + +/* Will read a compressed bit stored by COMPRESS_BIT into a single byte */ +#define UNCOMPRESS_BITS(compressed) ((compressed >> 5) << (compressed & 0x1F)) + +#endif diff --git a/src/battle_main.c b/src/battle_main.c index e4c5c7a784..1764f3d6a5 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -322,85 +322,83 @@ const u8 gTypeNames[NUMBER_OF_MON_TYPES][TYPE_NAME_LENGTH + 1] = [TYPE_FAIRY] = _("Fairy"), }; -#define DEFAULT_MONEY 5 -#define DEFAULT_BALL ITEM_POKE_BALL - -#define TRAINER_CLASS(trainerClass, trainerName, trainerMoney, trainerBall) \ - [TRAINER_CLASS_##trainerClass] = \ - { \ - .name = _(trainerName), \ - .money = trainerMoney, \ - .ball = trainerBall, \ +// extra args are money and ball +#define TRAINER_CLASS(trainerClass, trainerName, ...) \ + [TRAINER_CLASS_##trainerClass] = \ + { \ + .name = _(trainerName), \ + .money = DEFAULT(5, __VA_ARGS__), \ + .ball = DEFAULT_2(ITEM_POKE_BALL, __VA_ARGS__), \ } const struct TrainerClass gTrainerClasses[TRAINER_CLASS_COUNT] = { - TRAINER_CLASS(PKMN_TRAINER_1, "{PKMN} TRAINER", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(PKMN_TRAINER_2, "{PKMN} TRAINER", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(HIKER, "HIKER", 10, DEFAULT_BALL), - TRAINER_CLASS(TEAM_AQUA, "TEAM AQUA", 5, DEFAULT_BALL), + TRAINER_CLASS(PKMN_TRAINER_1, "{PKMN} TRAINER"), + TRAINER_CLASS(PKMN_TRAINER_2, "{PKMN} TRAINER"), + TRAINER_CLASS(HIKER, "HIKER", 10), + TRAINER_CLASS(TEAM_AQUA, "TEAM AQUA"), TRAINER_CLASS(PKMN_BREEDER, "{PKMN} BREEDER", 10, B_TRAINER_CLASS_POKE_BALLS >= GEN_8 ? ITEM_HEAL_BALL : ITEM_FRIEND_BALL), TRAINER_CLASS(COOLTRAINER, "COOLTRAINER", 12, ITEM_ULTRA_BALL), - TRAINER_CLASS(BIRD_KEEPER, "BIRD KEEPER", 8, DEFAULT_BALL), + TRAINER_CLASS(BIRD_KEEPER, "BIRD KEEPER", 8), TRAINER_CLASS(COLLECTOR, "COLLECTOR", 15, ITEM_PREMIER_BALL), TRAINER_CLASS(SWIMMER_M, "SWIMMER♂", 2, ITEM_DIVE_BALL), - TRAINER_CLASS(TEAM_MAGMA, "TEAM MAGMA", 5, DEFAULT_BALL), - TRAINER_CLASS(EXPERT, "EXPERT", 10, DEFAULT_BALL), - TRAINER_CLASS(AQUA_ADMIN, "AQUA ADMIN", 10, DEFAULT_BALL), + TRAINER_CLASS(TEAM_MAGMA, "TEAM MAGMA"), + TRAINER_CLASS(EXPERT, "EXPERT", 10), + TRAINER_CLASS(AQUA_ADMIN, "AQUA ADMIN", 10), TRAINER_CLASS(BLACK_BELT, "BLACK BELT", 8, ITEM_ULTRA_BALL), TRAINER_CLASS(AQUA_LEADER, "AQUA LEADER", 20, ITEM_MASTER_BALL), - TRAINER_CLASS(HEX_MANIAC, "HEX MANIAC", 6, DEFAULT_BALL), - TRAINER_CLASS(AROMA_LADY, "AROMA LADY", 10, DEFAULT_BALL), - TRAINER_CLASS(RUIN_MANIAC, "RUIN MANIAC", 15, DEFAULT_BALL), - TRAINER_CLASS(INTERVIEWER, "INTERVIEWER", 12, DEFAULT_BALL), - TRAINER_CLASS(TUBER_F, "TUBER", 1, DEFAULT_BALL), - TRAINER_CLASS(TUBER_M, "TUBER", 1, DEFAULT_BALL), - TRAINER_CLASS(LADY, "LADY", 50, DEFAULT_BALL), - TRAINER_CLASS(BEAUTY, "BEAUTY", 20, DEFAULT_BALL), - TRAINER_CLASS(RICH_BOY, "RICH BOY", 50, DEFAULT_BALL), - TRAINER_CLASS(POKEMANIAC, "POKéMANIAC", 15, DEFAULT_BALL), - TRAINER_CLASS(GUITARIST, "GUITARIST", 8, DEFAULT_BALL), - TRAINER_CLASS(KINDLER, "KINDLER", 8, DEFAULT_BALL), - TRAINER_CLASS(CAMPER, "CAMPER", 4, DEFAULT_BALL), - TRAINER_CLASS(PICNICKER, "PICNICKER", 4, DEFAULT_BALL), - TRAINER_CLASS(BUG_MANIAC, "BUG MANIAC", 15, DEFAULT_BALL), - TRAINER_CLASS(PSYCHIC, "PSYCHIC", 6, DEFAULT_BALL), + TRAINER_CLASS(HEX_MANIAC, "HEX MANIAC", 6), + TRAINER_CLASS(AROMA_LADY, "AROMA LADY", 10), + TRAINER_CLASS(RUIN_MANIAC, "RUIN MANIAC", 15), + TRAINER_CLASS(INTERVIEWER, "INTERVIEWER", 12), + TRAINER_CLASS(TUBER_F, "TUBER", 1), + TRAINER_CLASS(TUBER_M, "TUBER", 1), + TRAINER_CLASS(LADY, "LADY", 50), + TRAINER_CLASS(BEAUTY, "BEAUTY", 20), + TRAINER_CLASS(RICH_BOY, "RICH BOY", 50), + TRAINER_CLASS(POKEMANIAC, "POKéMANIAC", 15), + TRAINER_CLASS(GUITARIST, "GUITARIST", 8), + TRAINER_CLASS(KINDLER, "KINDLER", 8), + TRAINER_CLASS(CAMPER, "CAMPER", 4), + TRAINER_CLASS(PICNICKER, "PICNICKER", 4), + TRAINER_CLASS(BUG_MANIAC, "BUG MANIAC", 15), + TRAINER_CLASS(PSYCHIC, "PSYCHIC", 6), TRAINER_CLASS(GENTLEMAN, "GENTLEMAN", 20, ITEM_LUXURY_BALL), TRAINER_CLASS(ELITE_FOUR, "ELITE FOUR", 25, ITEM_ULTRA_BALL), - TRAINER_CLASS(LEADER, "LEADER", 25, DEFAULT_BALL), - TRAINER_CLASS(SCHOOL_KID, "SCHOOL KID", 5, DEFAULT_BALL), - TRAINER_CLASS(SR_AND_JR, "SR. AND JR.", 4, DEFAULT_BALL), - TRAINER_CLASS(WINSTRATE, "WINSTRATE", 10, DEFAULT_BALL), - TRAINER_CLASS(POKEFAN, "POKéFAN", 20, DEFAULT_BALL), - TRAINER_CLASS(YOUNGSTER, "YOUNGSTER", 4, DEFAULT_BALL), - TRAINER_CLASS(CHAMPION, "CHAMPION", 50, DEFAULT_BALL), + TRAINER_CLASS(LEADER, "LEADER", 25), + TRAINER_CLASS(SCHOOL_KID, "SCHOOL KID"), + TRAINER_CLASS(SR_AND_JR, "SR. AND JR.", 4), + TRAINER_CLASS(WINSTRATE, "WINSTRATE", 10), + TRAINER_CLASS(POKEFAN, "POKéFAN", 20), + TRAINER_CLASS(YOUNGSTER, "YOUNGSTER", 4), + TRAINER_CLASS(CHAMPION, "CHAMPION", 50), TRAINER_CLASS(FISHERMAN, "FISHERMAN", 10, B_TRAINER_CLASS_POKE_BALLS >= GEN_8 ? ITEM_DIVE_BALL : ITEM_LURE_BALL), - TRAINER_CLASS(TRIATHLETE, "TRIATHLETE", 10, DEFAULT_BALL), - TRAINER_CLASS(DRAGON_TAMER, "DRAGON TAMER", 12, DEFAULT_BALL), - TRAINER_CLASS(NINJA_BOY, "NINJA BOY", 3, DEFAULT_BALL), - TRAINER_CLASS(BATTLE_GIRL, "BATTLE GIRL", 6, DEFAULT_BALL), - TRAINER_CLASS(PARASOL_LADY, "PARASOL LADY", 10, DEFAULT_BALL), + TRAINER_CLASS(TRIATHLETE, "TRIATHLETE", 10), + TRAINER_CLASS(DRAGON_TAMER, "DRAGON TAMER", 12), + TRAINER_CLASS(NINJA_BOY, "NINJA BOY", 3), + TRAINER_CLASS(BATTLE_GIRL, "BATTLE GIRL", 6), + TRAINER_CLASS(PARASOL_LADY, "PARASOL LADY", 10), TRAINER_CLASS(SWIMMER_F, "SWIMMER♀", 2, ITEM_DIVE_BALL), - TRAINER_CLASS(TWINS, "TWINS", 3, DEFAULT_BALL), - TRAINER_CLASS(SAILOR, "SAILOR", 8, DEFAULT_BALL), - TRAINER_CLASS(COOLTRAINER_2, "COOLTRAINER", DEFAULT_MONEY, ITEM_ULTRA_BALL), - TRAINER_CLASS(MAGMA_ADMIN, "MAGMA ADMIN", 10, DEFAULT_BALL), - TRAINER_CLASS(RIVAL, "{PKMN} TRAINER", 15, DEFAULT_BALL), - TRAINER_CLASS(BUG_CATCHER, "BUG CATCHER", 4, DEFAULT_BALL), - TRAINER_CLASS(PKMN_RANGER, "{PKMN} RANGER", 12, DEFAULT_BALL), + TRAINER_CLASS(TWINS, "TWINS", 3), + TRAINER_CLASS(SAILOR, "SAILOR", 8), + TRAINER_CLASS(COOLTRAINER_2, "COOLTRAINER", 5, ITEM_ULTRA_BALL), + TRAINER_CLASS(MAGMA_ADMIN, "MAGMA ADMIN", 10), + TRAINER_CLASS(RIVAL, "{PKMN} TRAINER", 15), + TRAINER_CLASS(BUG_CATCHER, "BUG CATCHER", 4), + TRAINER_CLASS(PKMN_RANGER, "{PKMN} RANGER", 12), TRAINER_CLASS(MAGMA_LEADER, "MAGMA LEADER", 20, ITEM_MASTER_BALL), - TRAINER_CLASS(LASS, "LASS", 4, DEFAULT_BALL), - TRAINER_CLASS(YOUNG_COUPLE, "YOUNG COUPLE", 8, DEFAULT_BALL), - TRAINER_CLASS(OLD_COUPLE, "OLD COUPLE", 10, DEFAULT_BALL), - TRAINER_CLASS(SIS_AND_BRO, "SIS AND BRO", 3, DEFAULT_BALL), - TRAINER_CLASS(SALON_MAIDEN, "SALON MAIDEN", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(DOME_ACE, "DOME ACE", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(PALACE_MAVEN, "PALACE MAVEN", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(ARENA_TYCOON, "ARENA TYCOON", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(FACTORY_HEAD, "FACTORY HEAD", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(PIKE_QUEEN, "PIKE QUEEN", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(PYRAMID_KING, "PYRAMID KING", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(RS_PROTAG, "{PKMN} TRAINER", DEFAULT_MONEY, DEFAULT_BALL), + TRAINER_CLASS(LASS, "LASS", 4), + TRAINER_CLASS(YOUNG_COUPLE, "YOUNG COUPLE", 8), + TRAINER_CLASS(OLD_COUPLE, "OLD COUPLE", 10), + TRAINER_CLASS(SIS_AND_BRO, "SIS AND BRO", 3), + TRAINER_CLASS(SALON_MAIDEN, "SALON MAIDEN"), + TRAINER_CLASS(DOME_ACE, "DOME ACE"), + TRAINER_CLASS(PALACE_MAVEN, "PALACE MAVEN"), + TRAINER_CLASS(ARENA_TYCOON, "ARENA TYCOON"), + TRAINER_CLASS(FACTORY_HEAD, "FACTORY HEAD"), + TRAINER_CLASS(PIKE_QUEEN, "PIKE QUEEN"), + TRAINER_CLASS(PYRAMID_KING, "PYRAMID KING"), + TRAINER_CLASS(RS_PROTAG, "{PKMN} TRAINER"), }; static void (* const sTurnActionsFuncsTable[])(void) = diff --git a/src/data/moves_info.h b/src/data/moves_info.h index b68aecb319..10cda85a43 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -9,9 +9,8 @@ // The Gen. 4+ contest data comes from urpg's contest movedex. -#define FIRST(a, ...) a #if B_EXPANDED_MOVE_NAMES == TRUE -#define HANDLE_EXPANDED_MOVE_NAME(_name, ...) COMPOUND_STRING(FIRST(__VA_OPT__(__VA_ARGS__, ) _name)) +#define HANDLE_EXPANDED_MOVE_NAME(_name, ...) COMPOUND_STRING(DEFAULT(_name, __VA_ARGS__)) #else #define HANDLE_EXPANDED_MOVE_NAME(_name, ...) COMPOUND_STRING(_name) #endif