Search code examples
cluac-preprocessorvariadic-functionsvariadic-macros

How can I use DataTypes key as arguments


I have a macro that works as expected, but I want to make some changes to make it cleaner to use.

#define FuncCreate(func_name, func, ...) \
   int func_name(lua_State *ms) { \
     func(__VA_ARGS__); \
     return 0; \
   }


FuncCreate(appEvent, app_event, lua_touserdata(ms, 1), lua_tointeger(ms, 2), lua_tostring(ms, 3));
FuncCreate(GdEvent, gd_event, lua_touserdata(ms, 1), lua_touserdata(ms, 2), lua_tostring(ms, 3), lua_tointeger(ms, 4), lua_tostring(ms, 5));

I want to change the way I use arguments in the macro

I want to make use of key from data types e.g.

FuncCreate(appEvent, app_event, struct, int, const char*);
FuncCreate(GdEvent, gd_event, struct, int, const char*, int, const char*);

How can the macro take for example get the names

struct pass as argument to func the lua_touserdata pass int as an argument to func or lua_tointeger

Would it be better to create a variadic function? How can I do this ? Remembering that I want to use the key name of the data types


Solution

  • How can the macro take for example get the names

    You can use a _Generic to overload over type. Then you can overload a macro over variable number of arguments to pass each function to proper callback.

    #define LUA_TO(x) _Generic((x) \
        , int: lua_tointeger \
        , const char *: lua_tostring \
        , void *: lua_touserdata \
        )
    
    #define LUA_TO_FOREACH_1(ms,i,a)      LUA_TO(a)(ms,i)
    #define LUA_TO_FOREACH_2(ms,i,a,...)  LUA_TO_FOREACH_1(ms,i,a)  LUA_TO_FOREACH_1(ms,i+1,__VA_ARGS__)
    #define LUA_TO_FOREACH_3(ms,i,a,...)  LUA_TO_FOREACH_1(ms,i,a)  LUA_TO_FOREACH_2(ms,i+1,__VA_ARGS__)
    #define LUA_TO_FOREACH_4(ms,i,a,...)  LUA_TO_FOREACH_1(ms,i,a)  LUA_TO_FOREACH_3(ms,i+1,__VA_ARGS__)
    #define LUA_TO_FOREACH_N(_4,_3,_2,_1,N,...) LUA_TO_FOREACH##N
    #define LUA_TO_FOREACH(ms,...)  LUA_TO_FOREACH_N(__VA_ARGS__,_4,_3,_2,_1,__VA_ARGS__)(ms,1,__VA_ARGS__)
    
    #define FUNCCREATE(func_name, func, ...) \
       int func_name(lua_State *ms) { \
         func(LUA_TO_FOREACH(ms,__VA_ARGS__)); \
         return 0; \
       }
    
    FUNCCREATE(appEvent, app_event, int, const char*);
    // Results in: int appEvent(lua_State *ms) { app_event(_Generic((int) , int: lua_tointeger , const char *: lua_tostring , void *: lua_touserdata )(ms,1) _Generic((const char*) , int: lua_tointeger , const char *: lua_tostring , void *: lua_touserdata )(ms,1 +1)); return 0; };
    

    Would it be better to create a variadic function?

    C programming is statically typed and does not have reflection capability. Using a variadic function would lose the information about types, which seems to be of interest here.

    Overall, it would be better not to write such code. In C, you would type everything out, line by line. Writing such macro expansions to generate functions results in really hard to maintain and unreadable code that no one is ever able to fix or change later.