diff options
author | glx <glx@openttd.org> | 2019-03-12 15:37:57 +0100 |
---|---|---|
committer | glx22 <glx22@users.noreply.github.com> | 2020-07-16 00:53:26 +0200 |
commit | 4079c47b6cd5d210bdc31eff2040fb5aeb0f10de (patch) | |
tree | d4b685a3709ee7f98bfac6ff352af405da8014ec /cmake/scripts | |
parent | 8794c61f25dfe055296ed500c54d22613fbcb73f (diff) | |
download | openttd-4079c47b6cd5d210bdc31eff2040fb5aeb0f10de.tar.xz |
Change: rewrote squirrel_export in CMake
Diffstat (limited to 'cmake/scripts')
-rw-r--r-- | cmake/scripts/SquirrelExport.cmake | 667 | ||||
-rw-r--r-- | cmake/scripts/SquirrelIncludes.cmake | 60 |
2 files changed, 727 insertions, 0 deletions
diff --git a/cmake/scripts/SquirrelExport.cmake b/cmake/scripts/SquirrelExport.cmake new file mode 100644 index 000000000..315be36c5 --- /dev/null +++ b/cmake/scripts/SquirrelExport.cmake @@ -0,0 +1,667 @@ +cmake_minimum_required(VERSION 3.5) + +if (NOT SCRIPT_API_SOURCE_FILE) + message(FATAL_ERROR "Script needs SCRIPT_API_SOURCE_FILE defined") +endif (NOT SCRIPT_API_SOURCE_FILE) +if (NOT SCRIPT_API_BINARY_FILE) + message(FATAL_ERROR "Script needs SCRIPT_API_BINARY_FILE defined") +endif (NOT SCRIPT_API_BINARY_FILE) +if (NOT SCRIPT_API_FILE) + message(FATAL_ERROR "Script needs SCRIPT_API_FILE defined") +endif (NOT SCRIPT_API_FILE) +if (NOT APIUC) + message(FATAL_ERROR "Script needs APIUC defined") +endif (NOT APIUC) +if (NOT APILC) + message(FATAL_ERROR "Script needs APILC defined") +endif (NOT APILC) + +macro(dump_fileheader) + get_filename_component(SCRIPT_API_FILE_NAME "${SCRIPT_API_FILE}" NAME) + string(APPEND SQUIRREL_EXPORT "\n#include \"../${SCRIPT_API_FILE_NAME}\"") + if (NOT "${APIUC}" STREQUAL "Template") + string(REPLACE "script_" "template_" SCRIPT_API_FILE_NAME "${SCRIPT_API_FILE_NAME}") + string(APPEND SQUIRREL_EXPORT "\n#include \"../template/${SCRIPT_API_FILE_NAME}.sq\"") + endif (NOT "${APIUC}" STREQUAL "Template") +endmacro(dump_fileheader) + +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, 0); 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, 0); return *(${NAME} *)instance; }") + string(APPEND SQUIRREL_EXPORT "\n template <> inline const ${NAME} *GetParam(ForceType<const ${NAME} *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (${NAME} *)instance; }") + string(APPEND SQUIRREL_EXPORT "\n template <> inline const ${NAME} &GetParam(ForceType<const ${NAME} &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); 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; }") + elseif ("${NAME}" STREQUAL "ScriptText") + string(APPEND SQUIRREL_EXPORT "\n") + string(APPEND SQUIRREL_EXPORT "\n template <> inline Text *GetParam(ForceType<Text *>, 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<ScriptText *>(), 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(GetParam(ForceType<const char *>(), vm, index, ptr));") + string(APPEND SQUIRREL_EXPORT "\n }") + string(APPEND SQUIRREL_EXPORT "\n return nullptr;") + 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; }") + endif () +endmacro(dump_class_templates) + +macro(reset_reader) + unset(ENUMS) + unset(ENUM_VALUES) + unset(CONST_VALUES) + unset(STRUCTS) + unset(ENUM_STRING_TO_ERRORS) + unset(ENUM_ERROR_TO_STRINGS) + unset(METHODS) + unset(STATIC_METHODS) + unset(CLS) + unset(START_SQUIRREL_DEFINE_ON_NEXT_LINE) + set(CLS_LEVEL 0) + unset(CLS_IN_API) +endmacro(reset_reader) + +reset_reader() + +file(STRINGS "${SCRIPT_API_FILE}" SOURCE_LINES) + +foreach(LINE IN LISTS SOURCE_LINES) + # Ignore special doxygen blocks + if ("${LINE}" MATCHES "^#ifndef DOXYGEN_API") + set(DOXYGEN_SKIP "next") + continue() + endif () + if ("${LINE}" MATCHES "^#ifdef DOXYGEN_API") + set(DOXYGEN_SKIP "true") + continue() + endif () + if ("${LINE}" MATCHES "^#endif /\\* DOXYGEN_API \\*/") + unset(DOXYGEN_SKIP) + continue() + endif () + if ("${LINE}" MATCHES "^#else") + if ("${DOXYGEN_SKIP}" STREQUAL "next") + set(DOXYGEN_SKIP "true") + else() + unset(DOXYGEN_SKIP) + endif() + continue() + endif () + if ("${DOXYGEN_SKIP}" STREQUAL "true") + continue() + endif() + + if ("${LINE}" MATCHES "^([ ]*)\\* @api (.*)$") + set(LINE ${CMAKE_MATCH_2}) + # By default, classes are not selected + if (NOT CLS_LEVEL) + set(API_SELECTED FALSE) + endif (NOT CLS_LEVEL) + + if ("${APIUC}" STREQUAL "Template") + set(API_SELECTED TRUE) + if ("${LINE}" STREQUAL "none" OR "${LINE}" STREQUAL "-all") + set(API_SELECTED FALSE) + endif ("${LINE}" STREQUAL "none" OR "${LINE}" STREQUAL "-all") + continue() + endif("${APIUC}" STREQUAL "Template") + + if ("${LINE}" STREQUAL "none" OR "${LINE}" STREQUAL "-all") + set(API_SELECTED FALSE) + elseif ("${LINE}" MATCHES "-${APILC}") + set(API_SELECTED FALSE) + elseif ("${LINE}" MATCHES "${APILC}") + set(API_SELECTED TRUE) + endif () + continue() + endif ("${LINE}" MATCHES "^([ ]*)\\* @api (.*)$") + + # Remove the old squirrel stuff + if ("${LINE}" MATCHES "#ifdef DEFINE_SQUIRREL_CLASS") + set(SQUIRREL_STUFF TRUE) + continue() + endif ("${LINE}" MATCHES "#ifdef DEFINE_SQUIRREL_CLASS") + if ("${LINE}" MATCHES "^#endif /\\* DEFINE_SQUIRREL_CLASS \\*/") + unset(SQUIRREL_STUFF) + continue() + endif ("${LINE}" MATCHES "^#endif /\\* DEFINE_SQUIRREL_CLASS \\*/") + if (SQUIRREL_STUFF) + continue() + endif (SQUIRREL_STUFF) + + # Ignore forward declarations of classes + if ("${LINE}" MATCHES "^( *)class(.*);") + continue() + endif ("${LINE}" MATCHES "^( *)class(.*);") + + # We only want to have public functions exported for now + if ("${LINE}" MATCHES "^( *)class (.*) (: public|: protected|: private|:) ([^ ]*)") + if (NOT CLS_LEVEL) + if (NOT DEFINED API_SELECTED) + message(WARNING "Class '${CMAKE_MATCH_2}' has no @api. It won't be published to any API.") + set(API_SELECTED FALSE) + endif (NOT DEFINED API_SELECTED) + unset(IS_PUBLIC) + unset(CLS_PARAM_0) + set(CLS_PARAM_1 1) + set(CLS_PARAM_2 "x") + set(CLS_IN_API ${API_SELECTED}) + unset(API_SELECTED) + set(CLS "${CMAKE_MATCH_2}") + set(SUPER_CLS "${CMAKE_MATCH_4}") + elseif (CLS_LEVEL EQUAL 1) + if (NOT DEFINED API_SELECTED) + set(API_SELECTED ${CLS_IN_API}) + endif (NOT API_SELECTED) + + if (API_SELECTED) + list(APPEND STRUCTS "${CLS}::${CMAKE_MATCH_2}") + endif (API_SELECTED) + unset(API_SELECTED) + endif () + math(EXPR CLS_LEVEL "${CLS_LEVEL} + 1") + continue() + endif ("${LINE}" MATCHES "^( *)class (.*) (: public|: protected|: private|:) ([^ ]*)") + if ("${LINE}" MATCHES "^( *)public") + if (CLS_LEVEL EQUAL 1) + set(IS_PUBLIC TRUE) + endif (CLS_LEVEL EQUAL 1) + continue() + endif ("${LINE}" MATCHES "^( *)public") + if ("${LINE}" MATCHES "^( *)protected") + if (CLS_LEVEL EQUAL 1) + unset(IS_PUBLIC) + endif (CLS_LEVEL EQUAL 1) + continue() + endif ("${LINE}" MATCHES "^( *)protected") + if ("${LINE}" MATCHES "^( *)private") + if (CLS_LEVEL EQUAL 1) + unset(IS_PUBLIC) + endif (CLS_LEVEL EQUAL 1) + continue() + endif ("${LINE}" MATCHES "^( *)private") + + # Ignore the comments + if ("${LINE}" MATCHES "^#") + continue() + endif ("${LINE}" MATCHES "^#") + if ("${LINE}" MATCHES "/\\*.*\\*/") + unset(COMMENT) + continue() + endif ("${LINE}" MATCHES "/\\*.*\\*/") + if ("${LINE}" MATCHES "/\\*") + set(COMMENT TRUE) + continue() + endif ("${LINE}" MATCHES "/\\*") + if ("${LINE}" MATCHES "\\*/") + unset(COMMENT) + continue() + endif ("${LINE}" MATCHES "\\*/") + if (COMMENT) + continue() + endif (COMMENT) + + # We need to make specialized conversions for structs + if ("${LINE}" MATCHES "^( *)struct ([^ ]*)") + math(EXPR CLS_LEVEL "${CLS_LEVEL} + 1") + + # Check if we want to publish this struct + if (NOT DEFINED API_SELECTED) + set(API_SELECTED ${CLS_IN_API}) + endif (NOT DEFINED API_SELECTED) + if (NOT API_SELECTED) + unset(API_SELECTED) + continue() + endif (NOT API_SELECTED) + unset(API_SELECTED) + + if (NOT IS_PUBLIC OR NOT CLS_LEVEL EQUAL 1) + continue() + endif (NOT IS_PUBLIC OR NOT CLS_LEVEL EQUAL 1) + + list(APPEND STRUCTS "${CLS}::${CMAKE_MATCH_2}") + continue() + endif ("${LINE}" MATCHES "^( *)struct ([^ ]*)") + + # We need to make specialized conversions for enums + if ("${LINE}" MATCHES "^( *)enum ([^ ]*)") + math(EXPR CLS_LEVEL "${CLS_LEVEL} + 1") + + # Check if we want to publish this enum + if (NOT DEFINED API_SELECTED) + set(API_SELECTED ${CLS_IN_API}) + endif (NOT DEFINED API_SELECTED) + if (NOT API_SELECTED) + unset(API_SELECTED) + continue() + endif (NOT API_SELECTED) + unset(API_SELECTED) + + if (NOT IS_PUBLIC) + continue() + endif (NOT IS_PUBLIC) + + set(IN_ENUM TRUE) + list(APPEND ENUMS "${CLS}::${CMAKE_MATCH_2}") + continue() + endif ("${LINE}" MATCHES "^( *)enum ([^ ]*)") + + # Maybe the end of the class, if so we can start with the Squirrel export pretty soon + if ("${LINE}" MATCHES "};") + math(EXPR CLS_LEVEL "${CLS_LEVEL} - 1") + if (CLS_LEVEL) + unset(IN_ENUM) + continue() + endif (CLS_LEVEL) + + if (CLS) + set(START_SQUIRREL_DEFINE_ON_NEXT_LINE TRUE) + endif (CLS) + continue() + endif ("${LINE}" MATCHES "};") + + # Empty/white lines. When we may do the Squirrel export, do that export. + if ("${LINE}" MATCHES "^([ ]*)$") + if (NOT START_SQUIRREL_DEFINE_ON_NEXT_LINE) + continue() + endif (NOT START_SQUIRREL_DEFINE_ON_NEXT_LINE) + + if (NOT CLS_IN_API) + reset_reader() + continue() + endif (NOT CLS_IN_API) + + if (NOT HAS_FILEHEADER) + dump_fileheader() + set(HAS_FILEHEADER TRUE) + endif (NOT HAS_FILEHEADER) + + unset(IS_PUBLIC) + unset(NAMESPACE_OPENED) + + string(REGEX REPLACE "^Script" "${APIUC}" API_CLS "${CLS}") + string(REGEX REPLACE "^Script" "${APIUC}" API_SUPER_CLS "${SUPER_CLS}") + + string(APPEND SQUIRREL_EXPORT "\n") + + if ("${APIUC}" STREQUAL "Template") + # First check whether we have enums to print + if (DEFINED ENUMS) + if (NOT NAMESPACE_OPENED) + string(APPEND SQUIRREL_EXPORT "\nnamespace SQConvert {") + set(NAMESPACE_OPENED TRUE) + endif (NOT NAMESPACE_OPENED) + 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, (int32)res); return 1; }") + endforeach(ENUM) + endif (DEFINED ENUMS) + + # Then check whether we have structs/classes to print + if (DEFINED STRUCTS) + if (NOT NAMESPACE_OPENED) + string(APPEND SQUIRREL_EXPORT "\nnamespace SQConvert {") + set(NAMESPACE_OPENED TRUE) + endif (NOT NAMESPACE_OPENED) + string(APPEND SQUIRREL_EXPORT "\n /* Allow inner classes/structs to be used as Squirrel parameters */") + foreach(STRUCT IN LISTS STRUCTS) + dump_class_templates(${STRUCT}) + endforeach(STRUCT) + endif (DEFINED STRUCTS) + + if (NOT NAMESPACE_OPENED) + string(APPEND SQUIRREL_EXPORT "\nnamespace SQConvert {") + set(NAMESPACE_OPENED TRUE) + else (NOT NAMESPACE_OPENED) + string(APPEND SQUIRREL_EXPORT "\n") + endif (NOT NAMESPACE_OPENED) + string(APPEND SQUIRREL_EXPORT "\n /* Allow ${CLS} to be used as Squirrel parameter */") + dump_class_templates(${CLS}) + + string(APPEND SQUIRREL_EXPORT "\n} // namespace SQConvert") + + reset_reader() + continue() + endif ("${APIUC}" STREQUAL "Template") + + string(APPEND SQUIRREL_EXPORT "\n") + string(APPEND SQUIRREL_EXPORT "\ntemplate <> const char *GetClassName<${CLS}, ST_${APIUC}>() { return \"${API_CLS}\"; }") + string(APPEND SQUIRREL_EXPORT "\n") + + # Then do the registration functions of the class. + string(APPEND SQUIRREL_EXPORT "\nvoid SQ${API_CLS}_Register(Squirrel *engine)") + string(APPEND SQUIRREL_EXPORT "\n{") + string(APPEND SQUIRREL_EXPORT "\n DefSQClass<${CLS}, ST_${APIUC}> SQ${API_CLS}(\"${API_CLS}\");") + if ("${SUPER_CLS}" STREQUAL "Text" OR "${SUPER_CLS}" STREQUAL "ScriptObject" OR "${SUPER_CLS}" STREQUAL "AIAbstractiveList::Valuator") + string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.PreRegister(engine);") + else ("${SUPER_CLS}" STREQUAL "Text" OR "${SUPER_CLS}" STREQUAL "ScriptObject" OR "${SUPER_CLS}" STREQUAL "AIAbstractiveList::Valuator") + string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.PreRegister(engine, \"${API_SUPER_CLS}\");") + endif ("${SUPER_CLS}" STREQUAL "Text" OR "${SUPER_CLS}" STREQUAL "ScriptObject" OR "${SUPER_CLS}" STREQUAL "AIAbstractiveList::Valuator") + if (NOT "${SUPER_CLS}" STREQUAL "ScriptEvent") + if ("${CLS_PARAM_2}" STREQUAL "v") + string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.AddSQAdvancedConstructor(engine);") + else ("${CLS_PARAM_2}" STREQUAL "v") + string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.AddConstructor<void (${CLS}::*)(${CLS_PARAM_0}), ${CLS_PARAM_1}>(engine, \"${CLS_PARAM_2}\");") + endif ("${CLS_PARAM_2}" STREQUAL "v") + endif (NOT "${SUPER_CLS}" STREQUAL "ScriptEvent") + string(APPEND SQUIRREL_EXPORT "\n") + + # Enum values + set(MLEN 0) + foreach(ENUM_VALUE IN LISTS ENUM_VALUES) + string(LENGTH "${ENUM_VALUE}" LEN) + if (MLEN LESS LEN) + set(MLEN ${LEN}) + endif (MLEN LESS LEN) + endforeach(ENUM_VALUE) + foreach(ENUM_VALUE IN LISTS ENUM_VALUES) + string(LENGTH "${ENUM_VALUE}" LEN) + math(EXPR LEN "${MLEN} - ${LEN}") + unset(SPACES) + foreach(i RANGE ${LEN}) + string(APPEND SPACES " ") + endforeach(i) + string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.DefSQConst(engine, ${CLS}::${ENUM_VALUE},${SPACES}\"${ENUM_VALUE}\");") + endforeach(ENUM_VALUE) + if (MLEN) + string(APPEND SQUIRREL_EXPORT "\n") + endif (MLEN) + + # Const values + set(MLEN 0) + foreach(CONST_VALUE IN LISTS CONST_VALUES) + string(LENGTH "${CONST_VALUE}" LEN) + if (MLEN LESS LEN) + set(MLEN ${LEN}) + endif (MLEN LESS LEN) + endforeach(CONST_VALUE) + foreach(CONST_VALUE IN LISTS CONST_VALUES) + string(LENGTH "${CONST_VALUE}" LEN) + math(EXPR LEN "${MLEN} - ${LEN}") + unset(SPACES) + foreach(i RANGE ${LEN}) + string(APPEND SPACES " ") + endforeach(i) + string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.DefSQConst(engine, ${CLS}::${CONST_VALUE},${SPACES}\"${CONST_VALUE}\");") + endforeach(CONST_VALUE) + if (MLEN) + string(APPEND SQUIRREL_EXPORT "\n") + endif (MLEN) + + # Mapping of OTTD strings to errors + set(MLEN 0) + foreach(ENUM_STRING_TO_ERROR IN LISTS ENUM_STRING_TO_ERRORS) + string(REPLACE ":" ";" ENUM_STRING_TO_ERROR "${ENUM_STRING_TO_ERROR}") + list(GET ENUM_STRING_TO_ERROR 0 ENUM_STRING) + string(LENGTH "${ENUM_STRING}" LEN) + if (MLEN LESS LEN) + set(MLEN ${LEN}) + endif (MLEN LESS LEN) + endforeach(ENUM_STRING_TO_ERROR) + foreach(ENUM_STRING_TO_ERROR IN LISTS ENUM_STRING_TO_ERRORS) + string(REPLACE ":" ";" ENUM_STRING_TO_ERROR "${ENUM_STRING_TO_ERROR}") + list(GET ENUM_STRING_TO_ERROR 0 ENUM_STRING) + list(GET ENUM_STRING_TO_ERROR 1 ENUM_ERROR) + string(LENGTH "${ENUM_STRING}" LEN) + math(EXPR LEN "${MLEN} - ${LEN}") + unset(SPACES) + foreach(i RANGE ${LEN}) + string(APPEND SPACES " ") + endforeach(i) + string(APPEND SQUIRREL_EXPORT "\n ScriptError::RegisterErrorMap(${ENUM_STRING},${SPACES}${CLS}::${ENUM_ERROR});") + endforeach(ENUM_STRING_TO_ERROR) + if (MLEN) + string(APPEND SQUIRREL_EXPORT "\n") + endif (MLEN) + + # Mapping of errors to human 'readable' strings. + set(MLEN 0) + foreach(ENUM_ERROR_TO_STRING IN LISTS ENUM_ERROR_TO_STRINGS) + string(LENGTH "${ENUM_ERROR_TO_STRING}" LEN) + if (MLEN LESS LEN) + set(MLEN ${LEN}) + endif (MLEN LESS LEN) + endforeach(ENUM_ERROR_TO_STRING) + foreach(ENUM_ERROR_TO_STRING IN LISTS ENUM_ERROR_TO_STRINGS) + string(LENGTH "${ENUM_ERROR_TO_STRING}" LEN) + math(EXPR LEN "${MLEN} - ${LEN}") + unset(SPACES) + foreach(i RANGE ${LEN}) + string(APPEND SPACES " ") + endforeach(i) + string(APPEND SQUIRREL_EXPORT "\n ScriptError::RegisterErrorMapString(${CLS}::${ENUM_ERROR_TO_STRING},${SPACES}\"${ENUM_ERROR_TO_STRING}\");") + endforeach(ENUM_ERROR_TO_STRING) + if (MLEN) + string(APPEND SQUIRREL_EXPORT "\n") + endif (MLEN) + + # Static methods + set(MLEN 0) + foreach(STATIC_METHOD IN LISTS STATIC_METHODS) + string(REPLACE ":" ";" STATIC_METHOD "${STATIC_METHOD}") + list(GET STATIC_METHOD 0 FUNCNAME) + string(LENGTH "${FUNCNAME}" LEN) + if (MLEN LESS LEN) + set(MLEN ${LEN}) + endif (MLEN LESS LEN) + endforeach(STATIC_METHOD) + foreach(STATIC_METHOD IN LISTS STATIC_METHODS) + string(REPLACE ":" ";" STATIC_METHOD "${STATIC_METHOD}") + list(GET STATIC_METHOD 0 FUNCNAME) + list(GET STATIC_METHOD 1 ARGC) + list(GET STATIC_METHOD 2 TYPES) + string(LENGTH "${FUNCNAME}" LEN) + math(EXPR LEN "${MLEN} - ${LEN}") + if ("${TYPES}" STREQUAL "v") + if (LEN GREATER 8) + math(EXPR LEN "${LEN} - 8") + else (LEN GREATER 8) + set(LEN 0) + endif (LEN GREATER 8) + endif ("${TYPES}" STREQUAL "v") + unset(SPACES) + foreach(i RANGE ${LEN}) + string(APPEND SPACES " ") + endforeach(i) + if ("${TYPES}" STREQUAL "v") + string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.DefSQAdvancedStaticMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\");") + else ("${TYPES}" STREQUAL "v") + string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.DefSQStaticMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\",${SPACES}${ARGC}, \"${TYPES}\");") + endif ("${TYPES}" STREQUAL "v") + endforeach(STATIC_METHOD) + if (MLEN) + string(APPEND SQUIRREL_EXPORT "\n") + endif (MLEN) + + # Non-static methods + set(MLEN 0) + foreach(METHOD IN LISTS METHODS) + string(REPLACE ":" ";" METHOD "${METHOD}") + list(GET METHOD 0 FUNCNAME) + string(LENGTH "${FUNCNAME}" LEN) + if (MLEN LESS LEN) + set(MLEN ${LEN}) + endif (MLEN LESS LEN) + endforeach(METHOD) + foreach(METHOD IN LISTS METHODS) + string(REPLACE ":" ";" METHOD "${METHOD}") + list(GET METHOD 0 FUNCNAME) + list(GET METHOD 1 ARGC) + list(GET METHOD 2 TYPES) + string(LENGTH "${FUNCNAME}" LEN) + math(EXPR LEN "${MLEN} - ${LEN}") + if ("${TYPES}" STREQUAL "v") + if (LEN GREATER 8) + math(EXPR LEN "${LEN} - 8") + else (LEN GREATER 8) + set(LEN 0) + endif (LEN GREATER 8) + endif ("${TYPES}" STREQUAL "v") + unset(SPACES) + foreach(i RANGE ${LEN}) + string(APPEND SPACES " ") + endforeach(i) + if ("${TYPES}" STREQUAL "v") + string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.DefSQAdvancedMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\");") + else ("${TYPES}" STREQUAL "v") + string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.DefSQMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\",${SPACES}${ARGC}, \"${TYPES}\");") + endif ("${TYPES}" STREQUAL "v") + endforeach(METHOD) + if (MLEN) + string(APPEND SQUIRREL_EXPORT "\n") + endif (MLEN) + + string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.PostRegister(engine);") + string(APPEND SQUIRREL_EXPORT "\n}") + + reset_reader() + + continue() + endif ("${LINE}" MATCHES "^([ ]*)$") + + # Skip non-public functions + if (NOT IS_PUBLIC) + continue() + endif (NOT IS_PUBLIC) + + # Add enums + if (IN_ENUM) + string(REGEX MATCH "([^, ]+)" ENUM_VALUE "${LINE}") + list(APPEND ENUM_VALUES "${ENUM_VALUE}") + + # Check if this a special error enum + list(GET ENUMS -1 ENUM) + if ("${ENUM}" MATCHES ".*::ErrorMessages") + # syntax: + # enum ErrorMessages { + # ERR_SOME_ERROR, // [STR_ITEM1, STR_ITEM2, ...] + # } + + # Set the mappings + if ("${LINE}" MATCHES "\\[(.*)\\]") + string(REGEX REPLACE "[ ]" "" MAPPINGS "${CMAKE_MATCH_1}") + string(REPLACE "," ";" MAPPINGS "${MAPPINGS}") + + foreach(MAPPING IN LISTS MAPPINGS) + list(APPEND ENUM_STRING_TO_ERRORS "${MAPPING}:${ENUM_VALUE}") + endforeach(MAPPING) + + list(APPEND ENUM_ERROR_TO_STRINGS "${ENUM_VALUE}") + endif ("${LINE}" MATCHES "\\[(.*)\\]") + endif ("${ENUM}" MATCHES ".*::ErrorMessages") + continue() + endif (IN_ENUM) + + # Add a const (non-enum) value + if ("${LINE}" MATCHES "^[ ]*static const [^ ]+ ([^ ]+) = -?\\(?[^ ]*\\)?[^ ]+;") + list(APPEND CONST_VALUES "${CMAKE_MATCH_1}") + continue() + endif ("${LINE}" MATCHES "^[ ]*static const [^ ]+ ([^ ]+) = -?\\(?[^ ]*\\)?[^ ]+;") + + # Add a method to the list + if ("${LINE}" MATCHES "^.*\\(.*\\).*$") + if (NOT CLS_LEVEL EQUAL 1) + continue() + endif (NOT CLS_LEVEL EQUAL 1) + if ("${LINE}" MATCHES "~") + if (DEFINED API_SELECTED) + message(WARNING "Destructor for '${CLS}' has @api. Tag ignored.") + unset(API_SELECTED) + endif (DEFINED API_SELECTED) + continue() + endif ("${LINE}" MATCHES "~") + + unset(IS_STATIC) + if ("${LINE}" MATCHES "static") + set(IS_STATIC TRUE) + endif ("${LINE}" MATCHES "static") + + string(REGEX REPLACE "(virtual|static|const)[ ]+" "" LINE "${LINE}") + string(REGEX REPLACE "{.*" "" LINE "${LINE}") + set(PARAM_S "${LINE}") + string(REGEX REPLACE "\\*" "" LINE "${LINE}") + string(REGEX REPLACE "\\(.*" "" LINE "${LINE}") + + string(REGEX REPLACE ".*\\(" "" PARAM_S "${PARAM_S}") + string(REGEX REPLACE "\\).*" "" PARAM_S "${PARAM_S}") + + string(REGEX MATCH "([^ ]+)( ([^ ]+))?" RESULT "${LINE}") + set(FUNCTYPE "${CMAKE_MATCH_1}") + set(FUNCNAME "${CMAKE_MATCH_3}") + if ("${FUNCTYPE}" STREQUAL "${CLS}" AND NOT FUNCNAME) + if (DEFINED API_SELECTED) + message(WARNING "Constructor for '${CLS}' has @api. Tag ignored.") + unset(API_SELECTED) + endif (DEFINED API_SELECTED) + set(CLS_PARAM_0 "${PARAM_S}") + if (NOT PARAM_S) + continue() + endif (NOT PARAM_S) + elseif (NOT FUNCNAME) + continue() + endif () + + string(REPLACE "," ";" PARAMS "${PARAM_S}") + if (IS_STATIC) + set(TYPES ".") + else (IS_STATIC) + set(TYPES "x") + endif (IS_STATIC) + + set(LEN 1) + foreach(PARAM IN LISTS PARAMS) + math(EXPR LEN "${LEN} + 1") + string(STRIP "${PARAM}" PARAM) + if ("${PARAM}" MATCHES "\\*|&") + if ("${PARAM}" MATCHES "^char") + # Many types can be converted to string, so use '.', not 's'. (handled by our glue code) + string(APPEND TYPES ".") + elseif ("${PARAM}" MATCHES "^void") + string(APPEND TYPES "p") + elseif ("${PARAM}" MATCHES "^Array") + string(APPEND TYPES "a") + elseif ("${PARAM}" MATCHES "^struct Array") + string(APPEND TYPES "a") + elseif ("${PARAM}" MATCHES "^Text") + string(APPEND TYPES ".") + else () + string(APPEND TYPES "x") + endif () + elseif ("${PARAM}" MATCHES "^bool") + string(APPEND TYPES "b") + elseif ("${PARAM}" MATCHES "^HSQUIRRELVM") + set(TYPES "v") + else () + string(APPEND TYPES "i") + endif () + endforeach(PARAM) + + # Check if we want to publish this function + if (NOT DEFINED API_SELECTED) + set(API_SELECTED ${CLS_IN_API}) + endif (NOT DEFINED API_SELECTED) + if (NOT API_SELECTED) + unset(API_SELECTED) + continue() + endif (NOT API_SELECTED) + unset(API_SELECTED) + + if ("${FUNCTYPE}" STREQUAL "${CLS}" AND NOT FUNCNAME) + set(CLS_PARAM_1 ${LEN}) + set(CLS_PARAM_2 "${TYPES}") + elseif ("${FUNCNAME}" MATCHES "^_" AND NOT "${TYPES}" STREQUAL "v") + elseif (IS_STATIC) + list(APPEND STATIC_METHODS "${FUNCNAME}:${LEN}:${TYPES}") + else () + list(APPEND METHODS "${FUNCNAME}:${LEN}:${TYPES}") + endif () + continue() + endif ("${LINE}" MATCHES "^.*\\(.*\\).*$") +endforeach(LINE) + +configure_file(${SCRIPT_API_SOURCE_FILE} ${SCRIPT_API_BINARY_FILE}) diff --git a/cmake/scripts/SquirrelIncludes.cmake b/cmake/scripts/SquirrelIncludes.cmake new file mode 100644 index 000000000..d6d8b8ec3 --- /dev/null +++ b/cmake/scripts/SquirrelIncludes.cmake @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 3.5) + +if (NOT INCLUDES_SOURCE_FILE) + message(FATAL_ERROR "Script needs INCLUDES_SOURCE_FILE defined") +endif (NOT INCLUDES_SOURCE_FILE) +if (NOT INCLUDES_BINARY_FILE) + message(FATAL_ERROR "Script needs INCLUDES_BINARY_FILE defined") +endif (NOT INCLUDES_BINARY_FILE) +if (NOT APILC) + message(FATAL_ERROR "Script needs APILC defined") +endif (NOT APILC) +if (NOT APIUC) + message(FATAL_ERROR "Script needs APIUC defined") +endif (NOT APIUC) + +set(ARGC 1) +set(ARG_READ NO) + +# Read all the arguments given to CMake; we are looking for -- and everything +# that follows. Those are our api files. +while(ARGC LESS CMAKE_ARGC) + set(ARG ${CMAKE_ARGV${ARGC}}) + + if (ARG_READ) + list(APPEND SCRIPT_API_BINARY_FILES "${ARG}") + endif (ARG_READ) + + if (ARG STREQUAL "--") + set(ARG_READ YES) + endif (ARG STREQUAL "--") + + math(EXPR ARGC "${ARGC} + 1") +endwhile() + +foreach(FILE IN LISTS SCRIPT_API_BINARY_FILES) + file(STRINGS "${FILE}" LINES REGEX "^void SQ${APIUC}.*_Register\\(Squirrel \\*engine\\)$") + if (LINES) + string(REGEX REPLACE ".*api/${APILC}/(.*)" "#include \"\\1\"" FILE "${FILE}") + list(APPEND SQUIRREL_INCLUDES "${FILE}") + foreach(LINE IN LISTS LINES) + if ("${LINE}" MATCHES "SQ${APIUC}(List|Controller)_Register") + continue() + endif ("${LINE}" MATCHES "SQ${APIUC}(List|Controller)_Register") + string(REGEX REPLACE "^.*void " " " LINE "${LINE}") + string(REGEX REPLACE "Squirrel \\*" "" LINE "${LINE}") + list(APPEND SQUIRREL_REGISTER "${LINE}") + endforeach(LINE) + endif (LINES) +endforeach(FILE) + +list(SORT SQUIRREL_INCLUDES) +string(REPLACE ";" "\n" SQUIRREL_INCLUDES "${SQUIRREL_INCLUDES}") + +string(REGEX REPLACE "_Register" "0000Register" SQUIRREL_REGISTER "${SQUIRREL_REGISTER}") +list(SORT SQUIRREL_REGISTER) +string(REGEX REPLACE "0000Register" "_Register" SQUIRREL_REGISTER "${SQUIRREL_REGISTER}") +string(REPLACE ";" ";\n" SQUIRREL_REGISTER "${SQUIRREL_REGISTER}") +set(SQUIRREL_REGISTER " SQ${APIUC}List_Register(engine);\n${SQUIRREL_REGISTER};") + +configure_file(${INCLUDES_SOURCE_FILE} ${INCLUDES_BINARY_FILE}) |