summaryrefslogtreecommitdiff
path: root/cmake/scripts
diff options
context:
space:
mode:
authorglx <glx@openttd.org>2019-03-12 15:37:57 +0100
committerglx22 <glx22@users.noreply.github.com>2020-07-16 00:53:26 +0200
commit4079c47b6cd5d210bdc31eff2040fb5aeb0f10de (patch)
treed4b685a3709ee7f98bfac6ff352af405da8014ec /cmake/scripts
parent8794c61f25dfe055296ed500c54d22613fbcb73f (diff)
downloadopenttd-4079c47b6cd5d210bdc31eff2040fb5aeb0f10de.tar.xz
Change: rewrote squirrel_export in CMake
Diffstat (limited to 'cmake/scripts')
-rw-r--r--cmake/scripts/SquirrelExport.cmake667
-rw-r--r--cmake/scripts/SquirrelIncludes.cmake60
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})