diff --git a/cmake/scripts/SquirrelExport.cmake b/cmake/scripts/SquirrelExport.cmake index e5d83714b9..5c41618d6c 100644 --- a/cmake/scripts/SquirrelExport.cmake +++ b/cmake/scripts/SquirrelExport.cmake @@ -28,25 +28,27 @@ endmacro() macro(dump_class_templates NAME) string(REGEX REPLACE "^Script" "" REALNAME ${NAME}) - string(APPEND SQUIRREL_EXPORT "\n template <> inline ${NAME} *GetParam(ForceType<${NAME} *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; }") - string(APPEND SQUIRREL_EXPORT "\n template <> inline ${NAME} &GetParam(ForceType<${NAME} &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; }") - string(APPEND SQUIRREL_EXPORT "\n template <> inline const ${NAME} *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; }") - string(APPEND SQUIRREL_EXPORT "\n template <> inline const ${NAME} &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; }") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} *> { static inline ${NAME} *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; } };") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} &> { static inline ${NAME} &Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param { static inline const ${NAME} *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; } };") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param { static inline const ${NAME} &Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };") if("${NAME}" STREQUAL "ScriptEvent") - string(APPEND SQUIRREL_EXPORT "\n template <> inline int Return<${NAME} *>(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; }") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Return<${NAME} *> { static inline int Set(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; } };") elseif("${NAME}" STREQUAL "ScriptText") string(APPEND SQUIRREL_EXPORT "\n") - string(APPEND SQUIRREL_EXPORT "\n template <> inline Text *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) {") - string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_INSTANCE) {") - string(APPEND SQUIRREL_EXPORT "\n return GetParam(ForceType(), vm, index, ptr);") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param {") + string(APPEND SQUIRREL_EXPORT "\n static inline Text *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) {") + string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_INSTANCE) {") + string(APPEND SQUIRREL_EXPORT "\n return Param::Get(vm, index, ptr);") + string(APPEND SQUIRREL_EXPORT "\n }") + string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_STRING) {") + string(APPEND SQUIRREL_EXPORT "\n return new RawText(Param::Get(vm, index, ptr));") + string(APPEND SQUIRREL_EXPORT "\n }") + string(APPEND SQUIRREL_EXPORT "\n return nullptr;") string(APPEND SQUIRREL_EXPORT "\n }") - string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_STRING) {") - string(APPEND SQUIRREL_EXPORT "\n return new RawText(GetParam(ForceType(), vm, index, ptr));") - string(APPEND SQUIRREL_EXPORT "\n }") - string(APPEND SQUIRREL_EXPORT "\n return nullptr;") - string(APPEND SQUIRREL_EXPORT "\n }") + string(APPEND SQUIRREL_EXPORT "\n };") else() - string(APPEND SQUIRREL_EXPORT "\n template <> inline int Return<${NAME} *>(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; }") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Return<${NAME} *> { static inline int Set(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; } };") endif() endmacro() @@ -297,8 +299,8 @@ foreach(LINE IN LISTS SOURCE_LINES) endif() string(APPEND SQUIRREL_EXPORT "\n /* Allow enums to be used as Squirrel parameters */") foreach(ENUM IN LISTS ENUMS) - string(APPEND SQUIRREL_EXPORT "\n template <> inline ${ENUM} GetParam(ForceType<${ENUM}>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (${ENUM})tmp; }") - string(APPEND SQUIRREL_EXPORT "\n template <> inline int Return<${ENUM}>(HSQUIRRELVM vm, ${ENUM} res) { sq_pushinteger(vm, res); return 1; }") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${ENUM}> { static inline ${ENUM} Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (${ENUM})tmp; } };") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Return<${ENUM}> { static inline int Set(HSQUIRRELVM vm, ${ENUM} res) { sq_pushinteger(vm, res); return 1; } };") endforeach() endif() diff --git a/src/script/api/script_priorityqueue.cpp b/src/script/api/script_priorityqueue.cpp index fda452096a..96f36e10ee 100644 --- a/src/script/api/script_priorityqueue.cpp +++ b/src/script/api/script_priorityqueue.cpp @@ -45,7 +45,7 @@ SQInteger ScriptPriorityQueue::Insert(HSQUIRRELVM vm) this->queue.emplace_back(priority, item); std::push_heap(this->queue.begin(), this->queue.end(), this->comp); - return SQConvert::Return(vm, true); + return SQConvert::Return::Set(vm, true); } SQInteger ScriptPriorityQueue::Pop(HSQUIRRELVM vm) @@ -61,7 +61,7 @@ SQInteger ScriptPriorityQueue::Pop(HSQUIRRELVM vm) this->queue.pop_back(); /* Store the object on the Squirrel stack before releasing it to make sure the ref count can't drop to zero. */ - auto ret = SQConvert::Return(vm, item); + auto ret = SQConvert::Return::Set(vm, item); sq_release(vm, &item); return ret; } @@ -74,7 +74,7 @@ SQInteger ScriptPriorityQueue::Peek(HSQUIRRELVM vm) return 1; } - return SQConvert::Return(vm, this->queue.front().second); + return SQConvert::Return::Set(vm, this->queue.front().second); } SQInteger ScriptPriorityQueue::Exists(HSQUIRRELVM vm) @@ -83,7 +83,7 @@ SQInteger ScriptPriorityQueue::Exists(HSQUIRRELVM vm) sq_resetobject(&item); sq_getstackobj(vm, 2, &item); - return SQConvert::Return(vm, std::find(this->queue.cbegin(), this->queue.cend(), item) != this->queue.cend()); + return SQConvert::Return::Set(vm, std::find(this->queue.cbegin(), this->queue.cend(), item) != this->queue.cend()); } SQInteger ScriptPriorityQueue::Clear(HSQUIRRELVM vm) diff --git a/src/script/squirrel_helper.hpp b/src/script/squirrel_helper.hpp index e6ce02786c..a717fbdad5 100644 --- a/src/script/squirrel_helper.hpp +++ b/src/script/squirrel_helper.hpp @@ -37,92 +37,94 @@ namespace SQConvert { /** - * Special class to make it possible for the compiler to pick the correct GetParam(). + * To return a value to squirrel, we use this helper class. It converts to the right format. + * We use a class instead of a plain function to allow us to use partial template specializations. */ - template class ForceType { }; + template struct Return; + + template <> struct Return { static inline int Set(HSQUIRRELVM vm, uint8 res) { sq_pushinteger(vm, (int32)res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, uint16 res) { sq_pushinteger(vm, (int32)res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, uint32 res) { sq_pushinteger(vm, (int32)res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, int8 res) { sq_pushinteger(vm, res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, int16 res) { sq_pushinteger(vm, res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, int32 res) { sq_pushinteger(vm, res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, int64 res) { sq_pushinteger(vm, res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, Money res) { sq_pushinteger(vm, res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, TileIndex res) { sq_pushinteger(vm, (int32)res.value); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, bool res) { sq_pushbool (vm, res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); free(res); } return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, const char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); } return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, void *res) { sq_pushuserpointer(vm, res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, HSQOBJECT res) { sq_pushobject(vm, res); return 1; } }; /** - * To return a value to squirrel, we call this function. It converts to the right format. + * To get a param from squirrel, we use this helper class. It converts to the right format. + * We use a class instead of a plain function to allow us to use partial template specializations. */ - template static int Return(HSQUIRRELVM vm, T t); + template struct Param; - template <> inline int Return (HSQUIRRELVM vm, uint8 res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, uint16 res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, uint32 res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, int8 res) { sq_pushinteger(vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, int16 res) { sq_pushinteger(vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, int32 res) { sq_pushinteger(vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, int64 res) { sq_pushinteger(vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, Money res) { sq_pushinteger(vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, TileIndex res) { sq_pushinteger(vm, (int32)res.value); return 1; } - template <> inline int Return (HSQUIRRELVM vm, bool res) { sq_pushbool (vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); free(res); } return 1; } - template <> inline int Return(HSQUIRRELVM vm, const char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); } return 1; } - template <> inline int Return (HSQUIRRELVM vm, void *res) { sq_pushuserpointer(vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, HSQOBJECT res) { sq_pushobject(vm, res); return 1; } + template <> struct Param { static inline uint8 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline uint16 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline uint32 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline int8 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline int16 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline int32 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline int64 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline TileIndex Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return TileIndex((uint32)(int32)tmp); } }; + template <> struct Param { static inline Money Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline bool Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQBool tmp; sq_getbool (vm, index, &tmp); return tmp != 0; } }; + template <> struct Param { static inline void *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer tmp; sq_getuserpointer(vm, index, &tmp); return tmp; } }; - /** - * To get a param from squirrel, we call this function. It converts to the right format. - */ - template static T GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr); + template <> struct Param { + static inline const char *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) + { + /* Convert what-ever there is as parameter to a string */ + sq_tostring(vm, index); - template <> inline uint8 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline uint16 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline uint32 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline int8 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline int16 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline int32 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline int64 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline TileIndex GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return TileIndex((uint32)(int32)tmp); } - template <> inline Money GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline bool GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQBool tmp; sq_getbool (vm, index, &tmp); return tmp != 0; } - template <> inline void *GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer tmp; sq_getuserpointer(vm, index, &tmp); return tmp; } - template <> inline const char *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) - { - /* Convert what-ever there is as parameter to a string */ - sq_tostring(vm, index); - - const SQChar *tmp; - sq_getstring(vm, -1, &tmp); - char *tmp_str = stredup(tmp); - sq_poptop(vm); - ptr->push_back((void *)tmp_str); - StrMakeValidInPlace(tmp_str); - return tmp_str; - } - - template <> inline Array *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) - { - /* Sanity check of the size. */ - if (sq_getsize(vm, index) > UINT16_MAX) throw sq_throwerror(vm, "an array used as parameter to a function is too large"); - - SQObject obj; - sq_getstackobj(vm, index, &obj); - sq_pushobject(vm, obj); - sq_pushnull(vm); - - std::vector data; - - while (SQ_SUCCEEDED(sq_next(vm, -2))) { - SQInteger tmp; - if (SQ_SUCCEEDED(sq_getinteger(vm, -1, &tmp))) { - data.push_back((int32)tmp); - } else { - sq_pop(vm, 4); - throw sq_throwerror(vm, "a member of an array used as parameter to a function is not numeric"); - } - - sq_pop(vm, 2); + const SQChar *tmp; + sq_getstring(vm, -1, &tmp); + char *tmp_str = stredup(tmp); + sq_poptop(vm); + ptr->push_back((void *)tmp_str); + StrMakeValidInPlace(tmp_str); + return tmp_str; } - sq_pop(vm, 2); + }; - Array *arr = (Array*)MallocT(sizeof(Array) + sizeof(int32) * data.size()); - arr->size = data.size(); - memcpy(arr->array, data.data(), sizeof(int32) * data.size()); + template <> struct Param { + static inline Array *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) + { + /* Sanity check of the size. */ + if (sq_getsize(vm, index) > UINT16_MAX) throw sq_throwerror(vm, "an array used as parameter to a function is too large"); - ptr->push_back(arr); - return arr; - } + SQObject obj; + sq_getstackobj(vm, index, &obj); + sq_pushobject(vm, obj); + sq_pushnull(vm); + + std::vector data; + + while (SQ_SUCCEEDED(sq_next(vm, -2))) { + SQInteger tmp; + if (SQ_SUCCEEDED(sq_getinteger(vm, -1, &tmp))) { + data.push_back((int32)tmp); + } else { + sq_pop(vm, 4); + throw sq_throwerror(vm, "a member of an array used as parameter to a function is not numeric"); + } + + sq_pop(vm, 2); + } + sq_pop(vm, 2); + + Array *arr = (Array *)MallocT(sizeof(Array) + sizeof(int32) * data.size()); + arr->size = data.size(); + memcpy(arr->array, data.data(), sizeof(int32) * data.size()); + + ptr->push_back(arr); + return arr; + } + }; /** * Helper class to recognize the function type (retval type, args) and use the proper specialization @@ -148,14 +150,14 @@ namespace SQConvert { [[maybe_unused]] SQAutoFreePointers ptr; if constexpr (std::is_void_v) { (*func)( - GetParam(ForceType(), vm, 2 + i, &ptr)... + Param::Get(vm, 2 + i, &ptr)... ); return 0; } else { Tretval ret = (*func)( - GetParam(ForceType(), vm, 2 + i, &ptr)... + Param::Get(vm, 2 + i, &ptr)... ); - return Return(vm, ret); + return Return::Set(vm, ret); } } }; @@ -182,14 +184,14 @@ namespace SQConvert { [[maybe_unused]] SQAutoFreePointers ptr; if constexpr (std::is_void_v) { (instance->*func)( - GetParam(ForceType(), vm, 2 + i, &ptr)... + Param::Get(vm, 2 + i, &ptr)... ); return 0; } else { Tretval ret = (instance->*func)( - GetParam(ForceType(), vm, 2 + i, &ptr)... + Param::Get(vm, 2 + i, &ptr)... ); - return Return(vm, ret); + return Return::Set(vm, ret); } } @@ -198,7 +200,7 @@ namespace SQConvert { { [[maybe_unused]] SQAutoFreePointers ptr; Tcls *inst = new Tcls( - GetParam(ForceType(), vm, 2 + i, &ptr)... + Param::Get(vm, 2 + i, &ptr)... ); return inst;