alliedmodders / sourcepawn

A small, statically typed scripting language.
Other
369 stars 63 forks source link

[Request] Macro concatenation #866

Closed b0ink closed 1 year ago

b0ink commented 1 year ago

While sourcepawn has some concatenation/embedding of variables with macros (#define), it is limited from concatenating two macros into a new macro. It would be nice to have such feature similar to how it is in C, where two ## will use the defined macro into the new macro.

For example:

Main,sp

#include <sourcemod>

#define BASEPREFIX public void Effect_
#define STARTSUFFIX _START
#define RESETSUFFIX _RESET

// ...

Setup.sp

#undef START
#undef RESET

#define START BASEPREFIX##NAMEOFEFFECT##STARTSUFFIX
#define RESET BASEPREFIX##NAMEOFEFFECT##RESETSUFFIX

// ...

SpawnMoney,sp (1 of 100 .sp files)

#define NAMEOFEFFECT SpawnMoney
#include "Setup.sp"

START(){
    /* Code.. */
}

RESET(){
    /* Code.. */
}

// ...

#undef NAMEOFEFFECT

Which would compile into:

public void Effect_SpawnMoney_START(){

}

public void Effect_SpawnMoney_RESET(){

}

For my use case I have a SP project with 100+ .sp files that I want to all follow the same function convention. Each file would only need to re-define the NAMEOFEFFECT macro, then I could use the same START(), RESET(), SETUP(), INIT() functions that would be uniquely built off of the NAMEOFFEFFECT macro (which would be done through an include that would #undef then #define all those functions). (The functions are then called dynamically via GetFunctionByName())

assyrianic commented 1 year ago

the equivalent for ##XYZ would be to just use macro args like %0~%9.

b0ink commented 1 year ago

the equivalent for ##XYZ would be to just use macro args like %0~%9.

The limitation with those is that already defined macros can't be passed as an argument.

Can't quite remember exactly what i tested a few days back but it was something like:

#define EFFECTNAME SpawnMoney

#define BUILD(%1,%2) public void Effect_%1%2
#define START BUILD(EFFECTNAME,_START)
#define RESET BUILD(EFFECTNAME,_RESET)

START(){

}

RESET(){

}

This would end up compiling as:

public void Effect_EFFECTNAME_START(){

}

public void Effect_EFFECTNAME_RESET(){

}

The BUILD, START, RESET macros would (in my case) be declared in that Setup.sp example so that it stays constant and the only macro i would need to declare is the EFFECTNAME.

To also add, ... is available to concatenate at compile but only works for strings.


Edit: Saying "already defined macros can't be passed as an argument" isn't accurate as the following works:

#define EFFECTNAME SpawnMoney
#define BUILD(%0) public void %0
#define START BUILD(EFFECTNAME)

START(){

}

Will compile into:

public void SpawnMoney(){

}

This issue seems to be adding anything to %0 that prevents it from recognising it as a macro

dvander commented 1 year ago

Macros are discouraged. Need a very compelling use case for changes to the preprocessor.