Codechange: replace "magic" trick with simpler straight forward code
[openttd-github.git] / cmake / scripts / SquirrelExport.cmake
blob5116a4c9d50d3317ef7c3ccf9894513804d23a8e
1 cmake_minimum_required(VERSION 3.5)
3 if(NOT SCRIPT_API_SOURCE_FILE)
4     message(FATAL_ERROR "Script needs SCRIPT_API_SOURCE_FILE defined")
5 endif()
6 if(NOT SCRIPT_API_BINARY_FILE)
7     message(FATAL_ERROR "Script needs SCRIPT_API_BINARY_FILE defined")
8 endif()
9 if(NOT SCRIPT_API_FILE)
10     message(FATAL_ERROR "Script needs SCRIPT_API_FILE defined")
11 endif()
12 if(NOT APIUC)
13     message(FATAL_ERROR "Script needs APIUC defined")
14 endif()
15 if(NOT APILC)
16     message(FATAL_ERROR "Script needs APILC defined")
17 endif()
19 macro(dump_fileheader)
20     get_filename_component(SCRIPT_API_FILE_NAME "${SCRIPT_API_FILE}" NAME)
21     string(APPEND SQUIRREL_EXPORT "\n#include \"../${SCRIPT_API_FILE_NAME}\"")
22     if(NOT "${APIUC}" STREQUAL "Template")
23         string(REPLACE "script_" "template_" SCRIPT_API_FILE_NAME "${SCRIPT_API_FILE_NAME}")
24         string(APPEND SQUIRREL_EXPORT "\n#include \"../template/${SCRIPT_API_FILE_NAME}.sq\"")
25     endif()
26 endmacro()
28 macro(dump_class_templates NAME)
29     string(REGEX REPLACE "^Script" "" REALNAME ${NAME})
31     string(APPEND SQUIRREL_EXPORT "\n   template <> struct Param<${NAME} *> { static inline ${NAME} *Get(HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return  (${NAME} *)instance; } };")
32     string(APPEND SQUIRREL_EXPORT "\n   template <> struct Param<${NAME} &> { static inline ${NAME} &Get(HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };")
33     string(APPEND SQUIRREL_EXPORT "\n   template <> struct Param<const ${NAME} *> { static inline const ${NAME} *Get(HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return  (${NAME} *)instance; } };")
34     string(APPEND SQUIRREL_EXPORT "\n   template <> struct Param<const ${NAME} &> { static inline const ${NAME} &Get(HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };")
35     if("${NAME}" STREQUAL "ScriptEvent")
36         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; } };")
37     elseif("${NAME}" STREQUAL "ScriptText")
38         string(APPEND SQUIRREL_EXPORT "\n")
39         string(APPEND SQUIRREL_EXPORT "\n       template <> struct Param<Text *> {")
40         string(APPEND SQUIRREL_EXPORT "\n               static inline Text *Get(HSQUIRRELVM vm, int index) {")
41         string(APPEND SQUIRREL_EXPORT "\n                       if (sq_gettype(vm, index) == OT_INSTANCE) {")
42         string(APPEND SQUIRREL_EXPORT "\n                               return Param<ScriptText *>::Get(vm, index);")
43         string(APPEND SQUIRREL_EXPORT "\n                       }")
44         string(APPEND SQUIRREL_EXPORT "\n                       if (sq_gettype(vm, index) == OT_STRING) {")
45         string(APPEND SQUIRREL_EXPORT "\n                               return new RawText(Param<const std::string &>::Get(vm, index));")
46         string(APPEND SQUIRREL_EXPORT "\n                       }")
47         string(APPEND SQUIRREL_EXPORT "\n                       return nullptr;")
48         string(APPEND SQUIRREL_EXPORT "\n               }")
49         string(APPEND SQUIRREL_EXPORT "\n       };")
50     else()
51         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; } };")
52     endif()
53 endmacro()
55 macro(reset_reader)
56     unset(ENUMS)
57     unset(ENUM_VALUES)
58     unset(CONST_VALUES)
59     unset(STRUCTS)
60     unset(ENUM_STRING_TO_ERRORS)
61     unset(ENUM_ERROR_TO_STRINGS)
62     unset(METHODS)
63     unset(STATIC_METHODS)
64     unset(CLS)
65     unset(START_SQUIRREL_DEFINE_ON_NEXT_LINE)
66     set(CLS_LEVEL 0)
67     unset(CLS_IN_API)
68 endmacro()
70 reset_reader()
72 file(STRINGS "${SCRIPT_API_FILE}" SOURCE_LINES)
74 set(NUM_LINE 0)
75 macro(doxygen_check)
76     if(NOT "${DOXYGEN_SKIP}" STREQUAL "")
77         message(FATAL_ERROR "${SCRIPT_API_FILE}:${NUM_LINE}: a DOXYGEN_API block was not properly closed")
78     endif()
79 endmacro()
81 foreach(LINE IN LISTS SOURCE_LINES)
82     math(EXPR NUM_LINE "${NUM_LINE} + 1")
83     # Ignore special doxygen blocks
84     if("${LINE}" MATCHES "^#ifndef DOXYGEN_API")
85         doxygen_check()
86         set(DOXYGEN_SKIP "next")
87         continue()
88     endif()
89     if("${LINE}" MATCHES "^#ifdef DOXYGEN_API")
90         doxygen_check()
91         set(DOXYGEN_SKIP "true")
92         continue()
93     endif()
94     if("${LINE}" MATCHES "^#endif /\\* DOXYGEN_API \\*/")
95         unset(DOXYGEN_SKIP)
96         continue()
97     endif()
98     if("${LINE}" MATCHES "^#else")
99         if(DOXYGEN_SKIP STREQUAL "next")
100             set(DOXYGEN_SKIP "true")
101         elseif(DOXYGEN_SKIP STREQUAL "true")
102             set(DOXYGEN_SKIP "false")
103         endif()
104         continue()
105     endif()
106     if("${DOXYGEN_SKIP}" STREQUAL "true")
107         continue()
108     endif()
110     if("${LINE}" MATCHES "^([    ]*)\\* @api (.*)$")
111         set(LINE ${CMAKE_MATCH_2})
112         # By default, classes are not selected
113         if(NOT CLS_LEVEL)
114             set(API_SELECTED FALSE)
115         endif()
117         if("${APIUC}" STREQUAL "Template")
118             set(API_SELECTED TRUE)
119             if("${LINE}" STREQUAL "none" OR "${LINE}" STREQUAL "-all")
120                 set(API_SELECTED FALSE)
121             endif()
122             continue()
123         endif()
125         if("${LINE}" STREQUAL "none" OR "${LINE}" STREQUAL "-all")
126             set(API_SELECTED FALSE)
127         elseif("${LINE}" MATCHES "-${APILC}")
128             set(API_SELECTED FALSE)
129         elseif("${LINE}" MATCHES "${APILC}")
130             set(API_SELECTED TRUE)
131         endif()
132         continue()
133     endif()
135     # Remove the old squirrel stuff
136     if("${LINE}" MATCHES "#ifdef DEFINE_SQUIRREL_CLASS")
137         set(SQUIRREL_STUFF TRUE)
138         continue()
139     endif()
140     if("${LINE}" MATCHES "^#endif /\\* DEFINE_SQUIRREL_CLASS \\*/")
141         unset(SQUIRREL_STUFF)
142         continue()
143     endif()
144     if(SQUIRREL_STUFF)
145         continue()
146     endif()
148     # Ignore forward declarations of classes
149     if("${LINE}" MATCHES "^(    *)class(.*);")
150         continue()
151     endif()
153     # We only want to have public functions exported for now
154     if("${LINE}" MATCHES "^(    *)class (.*) (: public|: protected|: private|:) ([^ ]*)")
155         if(NOT CLS_LEVEL)
156             if(NOT DEFINED API_SELECTED)
157                 message(WARNING "Class '${CMAKE_MATCH_2}' has no @api. It won't be published to any API.")
158                 set(API_SELECTED FALSE)
159             endif()
160             unset(IS_PUBLIC)
161             unset(CLS_PARAM_0)
162             set(CLS_PARAM_1 1)
163             set(CLS_PARAM_2 "x")
164             set(CLS_IN_API ${API_SELECTED})
165             unset(API_SELECTED)
166             set(CLS "${CMAKE_MATCH_2}")
167             set(SUPER_CLS "${CMAKE_MATCH_4}")
168         elseif(CLS_LEVEL EQUAL 1)
169             if(NOT DEFINED API_SELECTED)
170                 set(API_SELECTED ${CLS_IN_API})
171             endif()
173             if(API_SELECTED)
174                 list(APPEND STRUCTS "${CLS}::${CMAKE_MATCH_2}")
175             endif()
176             unset(API_SELECTED)
177         endif()
178         math(EXPR CLS_LEVEL "${CLS_LEVEL} + 1")
179         continue()
180     endif()
181     if("${LINE}" MATCHES "^(    *)public")
182         if(CLS_LEVEL EQUAL 1)
183             set(IS_PUBLIC TRUE)
184         endif()
185         continue()
186     endif()
187     if("${LINE}" MATCHES "^(    *)protected")
188         if(CLS_LEVEL EQUAL 1)
189             unset(IS_PUBLIC)
190         endif()
191         continue()
192     endif()
193     if("${LINE}" MATCHES "^(    *)private")
194         if(CLS_LEVEL EQUAL 1)
195             unset(IS_PUBLIC)
196         endif()
197         continue()
198     endif()
200     # Ignore the comments
201     if("${LINE}" MATCHES "^#")
202         continue()
203     endif()
204     if("${LINE}" MATCHES "/\\*.*\\*/")
205         unset(COMMENT)
206         continue()
207     endif()
208     if("${LINE}" MATCHES "/\\*")
209         set(COMMENT TRUE)
210         continue()
211     endif()
212     if("${LINE}" MATCHES "\\*/")
213         unset(COMMENT)
214         continue()
215     endif()
216     if(COMMENT)
217         continue()
218     endif()
220     # We need to make specialized conversions for structs
221     if("${LINE}" MATCHES "^(    *)struct ([^ ]*)")
222         math(EXPR CLS_LEVEL "${CLS_LEVEL} + 1")
224         # Check if we want to publish this struct
225         if(NOT DEFINED API_SELECTED)
226             set(API_SELECTED ${CLS_IN_API})
227         endif()
228         if(NOT API_SELECTED)
229             unset(API_SELECTED)
230             continue()
231         endif()
232         unset(API_SELECTED)
234         if(NOT IS_PUBLIC OR NOT CLS_LEVEL EQUAL 1)
235             continue()
236         endif()
238         list(APPEND STRUCTS "${CLS}::${CMAKE_MATCH_2}")
239         continue()
240     endif()
242     # We need to make specialized conversions for enums
243     if("${LINE}" MATCHES "^(    *)enum ([^ ]*)")
244         math(EXPR CLS_LEVEL "${CLS_LEVEL} + 1")
246         # Check if we want to publish this enum
247         if(NOT DEFINED API_SELECTED)
248             set(API_SELECTED ${CLS_IN_API})
249         endif()
250         if(NOT API_SELECTED)
251             unset(API_SELECTED)
252             continue()
253         endif()
254         unset(API_SELECTED)
256         if(NOT IS_PUBLIC)
257             continue()
258         endif()
260         set(IN_ENUM TRUE)
261         list(APPEND ENUMS "${CLS}::${CMAKE_MATCH_2}")
262         continue()
263     endif()
265     # Maybe the end of the class, if so we can start with the Squirrel export pretty soon
266     if("${LINE}" MATCHES "};")
267         math(EXPR CLS_LEVEL "${CLS_LEVEL} - 1")
268         if(CLS_LEVEL)
269             unset(IN_ENUM)
270             continue()
271         endif()
273         if(CLS)
274             set(START_SQUIRREL_DEFINE_ON_NEXT_LINE TRUE)
275         endif()
276         continue()
277     endif()
279     # Empty/white lines. When we may do the Squirrel export, do that export.
280     if("${LINE}" MATCHES "^([   ]*)$")
281         if(NOT START_SQUIRREL_DEFINE_ON_NEXT_LINE)
282             continue()
283         endif()
285         if(NOT CLS_IN_API)
286             reset_reader()
287             continue()
288         endif()
290         if(NOT HAS_FILEHEADER)
291             dump_fileheader()
292             set(HAS_FILEHEADER TRUE)
293         endif()
295         unset(IS_PUBLIC)
296         unset(NAMESPACE_OPENED)
298         string(REGEX REPLACE "^Script" "${APIUC}" API_CLS "${CLS}")
299         string(REGEX REPLACE "^Script" "${APIUC}" API_SUPER_CLS "${SUPER_CLS}")
301         string(APPEND SQUIRREL_EXPORT "\n")
303         if("${APIUC}" STREQUAL "Template")
304             # First check whether we have enums to print
305             if(DEFINED ENUMS)
306                 if(NOT NAMESPACE_OPENED)
307                     string(APPEND SQUIRREL_EXPORT "\nnamespace SQConvert {")
308                     set(NAMESPACE_OPENED TRUE)
309                 endif()
310                 string(APPEND SQUIRREL_EXPORT "\n       /* Allow enums to be used as Squirrel parameters */")
311                 foreach(ENUM IN LISTS ENUMS)
312                     string(APPEND SQUIRREL_EXPORT "\n   template <> struct Param<${ENUM}> { static inline ${ENUM} Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (${ENUM})tmp; } };")
313                     string(APPEND SQUIRREL_EXPORT "\n   template <> struct Return<${ENUM}> { static inline int Set(HSQUIRRELVM vm, ${ENUM} res) { sq_pushinteger(vm, res); return 1; } };")
314                 endforeach()
315             endif()
317             # Then check whether we have structs/classes to print
318             if(DEFINED STRUCTS)
319                 if(NOT NAMESPACE_OPENED)
320                     string(APPEND SQUIRREL_EXPORT "\nnamespace SQConvert {")
321                     set(NAMESPACE_OPENED TRUE)
322                 endif()
323                 string(APPEND SQUIRREL_EXPORT "\n       /* Allow inner classes/structs to be used as Squirrel parameters */")
324                 foreach(STRUCT IN LISTS STRUCTS)
325                     dump_class_templates(${STRUCT})
326                 endforeach()
327             endif()
329             if(NOT NAMESPACE_OPENED)
330                 string(APPEND SQUIRREL_EXPORT "\nnamespace SQConvert {")
331                 set(NAMESPACE_OPENED TRUE)
332             else()
333                 string(APPEND SQUIRREL_EXPORT "\n")
334             endif()
335             string(APPEND SQUIRREL_EXPORT "\n   /* Allow ${CLS} to be used as Squirrel parameter */")
336             dump_class_templates(${CLS})
338             string(APPEND SQUIRREL_EXPORT "\n} // namespace SQConvert")
340             reset_reader()
341             continue()
342         endif()
344         string(APPEND SQUIRREL_EXPORT "\n")
345         string(APPEND SQUIRREL_EXPORT "\ntemplate <> const char *GetClassName<${CLS}, ScriptType::${APIUC}>() { return \"${API_CLS}\"; }")
346         string(APPEND SQUIRREL_EXPORT "\n")
348         # Then do the registration functions of the class.
349         string(APPEND SQUIRREL_EXPORT "\nvoid SQ${API_CLS}_Register(Squirrel *engine)")
350         string(APPEND SQUIRREL_EXPORT "\n{")
351         string(APPEND SQUIRREL_EXPORT "\n       DefSQClass<${CLS}, ScriptType::${APIUC}> SQ${API_CLS}(\"${API_CLS}\");")
352         if("${SUPER_CLS}" STREQUAL "Text" OR "${SUPER_CLS}" STREQUAL "ScriptObject" OR "${SUPER_CLS}" STREQUAL "AIAbstractiveList::Valuator")
353             string(APPEND SQUIRREL_EXPORT "\n   SQ${API_CLS}.PreRegister(engine);")
354         else()
355             string(APPEND SQUIRREL_EXPORT "\n   SQ${API_CLS}.PreRegister(engine, \"${API_SUPER_CLS}\");")
356         endif()
357         if(NOT "${SUPER_CLS}" MATCHES "^ScriptEvent")
358             if("${CLS_PARAM_2}" STREQUAL "v")
359                 string(APPEND SQUIRREL_EXPORT "\n       SQ${API_CLS}.AddSQAdvancedConstructor(engine);")
360             else()
361                 string(APPEND SQUIRREL_EXPORT "\n       SQ${API_CLS}.AddConstructor<void (${CLS}::*)(${CLS_PARAM_0}), ${CLS_PARAM_1}>(engine, \"${CLS_PARAM_2}\");")
362             endif()
363         endif()
364         string(APPEND SQUIRREL_EXPORT "\n")
366         # Enum values
367         set(MLEN 0)
368         foreach(ENUM_VALUE IN LISTS ENUM_VALUES)
369             string(LENGTH "${ENUM_VALUE}" LEN)
370             if(MLEN LESS LEN)
371                 set(MLEN ${LEN})
372             endif()
373         endforeach()
374         foreach(ENUM_VALUE IN LISTS ENUM_VALUES)
375             string(LENGTH "${ENUM_VALUE}" LEN)
376             math(EXPR LEN "${MLEN} - ${LEN}")
377             unset(SPACES)
378             foreach(i RANGE ${LEN})
379                 string(APPEND SPACES " ")
380             endforeach()
381             string(APPEND SQUIRREL_EXPORT "\n   SQ${API_CLS}.DefSQConst(engine, ${CLS}::${ENUM_VALUE},${SPACES}\"${ENUM_VALUE}\");")
382         endforeach()
383         if(MLEN)
384             string(APPEND SQUIRREL_EXPORT "\n")
385         endif()
387         # Const values
388         set(MLEN 0)
389         foreach(CONST_VALUE IN LISTS CONST_VALUES)
390             string(LENGTH "${CONST_VALUE}" LEN)
391             if(MLEN LESS LEN)
392                 set(MLEN ${LEN})
393             endif()
394         endforeach()
395         foreach(CONST_VALUE IN LISTS CONST_VALUES)
396             string(LENGTH "${CONST_VALUE}" LEN)
397             math(EXPR LEN "${MLEN} - ${LEN}")
398             unset(SPACES)
399             foreach(i RANGE ${LEN})
400                 string(APPEND SPACES " ")
401             endforeach()
402             string(APPEND SQUIRREL_EXPORT "\n   SQ${API_CLS}.DefSQConst(engine, ${CLS}::${CONST_VALUE},${SPACES}\"${CONST_VALUE}\");")
403         endforeach()
404         if(MLEN)
405             string(APPEND SQUIRREL_EXPORT "\n")
406         endif()
408         # Mapping of OTTD strings to errors
409         set(MLEN 0)
410         foreach(ENUM_STRING_TO_ERROR IN LISTS ENUM_STRING_TO_ERRORS)
411             string(REPLACE ":" ";" ENUM_STRING_TO_ERROR "${ENUM_STRING_TO_ERROR}")
412             list(GET ENUM_STRING_TO_ERROR 0 ENUM_STRING)
413             string(LENGTH "${ENUM_STRING}" LEN)
414             if(MLEN LESS LEN)
415                 set(MLEN ${LEN})
416             endif()
417         endforeach()
418         foreach(ENUM_STRING_TO_ERROR IN LISTS ENUM_STRING_TO_ERRORS)
419             string(REPLACE ":" ";" ENUM_STRING_TO_ERROR "${ENUM_STRING_TO_ERROR}")
420             list(GET ENUM_STRING_TO_ERROR 0 ENUM_STRING)
421             list(GET ENUM_STRING_TO_ERROR 1 ENUM_ERROR)
422             string(LENGTH "${ENUM_STRING}" LEN)
423             math(EXPR LEN "${MLEN} - ${LEN}")
424             unset(SPACES)
425             foreach(i RANGE ${LEN})
426                 string(APPEND SPACES " ")
427             endforeach()
428             string(APPEND SQUIRREL_EXPORT "\n   ScriptError::RegisterErrorMap(${ENUM_STRING},${SPACES}${CLS}::${ENUM_ERROR});")
429         endforeach()
430         if(MLEN)
431             string(APPEND SQUIRREL_EXPORT "\n")
432         endif()
434         # Mapping of errors to human 'readable' strings.
435         set(MLEN 0)
436         foreach(ENUM_ERROR_TO_STRING IN LISTS ENUM_ERROR_TO_STRINGS)
437             string(LENGTH "${ENUM_ERROR_TO_STRING}" LEN)
438             if(MLEN LESS LEN)
439                 set(MLEN ${LEN})
440             endif()
441         endforeach()
442         foreach(ENUM_ERROR_TO_STRING IN LISTS ENUM_ERROR_TO_STRINGS)
443             string(LENGTH "${ENUM_ERROR_TO_STRING}" LEN)
444             math(EXPR LEN "${MLEN} - ${LEN}")
445             unset(SPACES)
446             foreach(i RANGE ${LEN})
447                 string(APPEND SPACES " ")
448             endforeach()
449             string(APPEND SQUIRREL_EXPORT "\n   ScriptError::RegisterErrorMapString(${CLS}::${ENUM_ERROR_TO_STRING},${SPACES}\"${ENUM_ERROR_TO_STRING}\");")
450         endforeach()
451         if(MLEN)
452             string(APPEND SQUIRREL_EXPORT "\n")
453         endif()
455         # Static methods
456         set(MLEN 0)
457         foreach(STATIC_METHOD IN LISTS STATIC_METHODS)
458             string(REPLACE ":" ";" STATIC_METHOD "${STATIC_METHOD}")
459             list(GET STATIC_METHOD 0 FUNCNAME)
460             string(LENGTH "${FUNCNAME}" LEN)
461             if(MLEN LESS LEN)
462                 set(MLEN ${LEN})
463             endif()
464         endforeach()
465         foreach(STATIC_METHOD IN LISTS STATIC_METHODS)
466             string(REPLACE ":" ";" STATIC_METHOD "${STATIC_METHOD}")
467             list(GET STATIC_METHOD 0 FUNCNAME)
468             list(GET STATIC_METHOD 1 ARGC)
469             list(GET STATIC_METHOD 2 TYPES)
470             string(LENGTH "${FUNCNAME}" LEN)
471             math(EXPR LEN "${MLEN} - ${LEN}")
472             if("${TYPES}" STREQUAL "v")
473                 if(LEN GREATER 8)
474                     math(EXPR LEN "${LEN} - 8")
475                 else()
476                     set(LEN 0)
477                 endif()
478             endif()
479             unset(SPACES)
480             foreach(i RANGE ${LEN})
481                 string(APPEND SPACES " ")
482             endforeach()
483             if("${TYPES}" STREQUAL "v")
484                 string(APPEND SQUIRREL_EXPORT "\n       SQ${API_CLS}.DefSQAdvancedStaticMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\");")
485             else()
486                 string(APPEND SQUIRREL_EXPORT "\n       SQ${API_CLS}.DefSQStaticMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\",${SPACES}${ARGC}, \"${TYPES}\");")
487             endif()
488         endforeach()
489         if(MLEN)
490             string(APPEND SQUIRREL_EXPORT "\n")
491         endif()
493         # Non-static methods
494         set(MLEN 0)
495         foreach(METHOD IN LISTS METHODS)
496             string(REPLACE ":" ";" METHOD "${METHOD}")
497             list(GET METHOD 0 FUNCNAME)
498             string(LENGTH "${FUNCNAME}" LEN)
499             if(MLEN LESS LEN)
500                 set(MLEN ${LEN})
501             endif()
502         endforeach()
503         foreach(METHOD IN LISTS METHODS)
504             string(REPLACE ":" ";" METHOD "${METHOD}")
505             list(GET METHOD 0 FUNCNAME)
506             list(GET METHOD 1 ARGC)
507             list(GET METHOD 2 TYPES)
508             string(LENGTH "${FUNCNAME}" LEN)
509             math(EXPR LEN "${MLEN} - ${LEN}")
510             if("${TYPES}" STREQUAL "v")
511                 if(LEN GREATER 8)
512                     math(EXPR LEN "${LEN} - 8")
513                 else()
514                     set(LEN 0)
515                 endif()
516             endif()
517             unset(SPACES)
518             foreach(i RANGE ${LEN})
519                 string(APPEND SPACES " ")
520             endforeach()
521             if("${TYPES}" STREQUAL "v")
522                 string(APPEND SQUIRREL_EXPORT "\n       SQ${API_CLS}.DefSQAdvancedMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\");")
523             else()
524                 string(APPEND SQUIRREL_EXPORT "\n       SQ${API_CLS}.DefSQMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\",${SPACES}${ARGC}, \"${TYPES}\");")
525             endif()
526         endforeach()
527         if(MLEN)
528             string(APPEND SQUIRREL_EXPORT "\n")
529         endif()
531         string(APPEND SQUIRREL_EXPORT "\n       SQ${API_CLS}.PostRegister(engine);")
532         string(APPEND SQUIRREL_EXPORT "\n}")
534         reset_reader()
536         continue()
537     endif()
539     # Skip non-public functions
540     if(NOT IS_PUBLIC)
541         continue()
542     endif()
544     # Add enums
545     if(IN_ENUM)
546         string(REGEX MATCH "([^,         ]+)" ENUM_VALUE "${LINE}")
547         list(APPEND ENUM_VALUES "${ENUM_VALUE}")
549         # Check if this a special error enum
550         list(GET ENUMS -1 ENUM)
551         if("${ENUM}" MATCHES ".*::ErrorMessages")
552             # syntax:
553             # enum ErrorMessages {
554             #   ERR_SOME_ERROR, // [STR_ITEM1, STR_ITEM2, ...]
555             # }
557             # Set the mappings
558             if("${LINE}" MATCHES "\\[(.*)\\]")
559                 string(REGEX REPLACE "[         ]" "" MAPPINGS "${CMAKE_MATCH_1}")
560                 string(REPLACE "," ";" MAPPINGS "${MAPPINGS}")
562                 foreach(MAPPING IN LISTS MAPPINGS)
563                     list(APPEND ENUM_STRING_TO_ERRORS "${MAPPING}:${ENUM_VALUE}")
564                 endforeach()
566                 list(APPEND ENUM_ERROR_TO_STRINGS "${ENUM_VALUE}")
567             endif()
568         endif()
569         continue()
570     endif()
572     # Add a const (non-enum) value
573     if("${LINE}" MATCHES "^[    ]*static const [^ ]+ ([^ ]+) = -?\\(?[^ ]*\\)?[^ ]+;")
574         list(APPEND CONST_VALUES "${CMAKE_MATCH_1}")
575         continue()
576     endif()
578     # Add a method to the list
579     if("${LINE}" MATCHES "^.*\\(.*\\).*$")
580         if(NOT CLS_LEVEL EQUAL 1)
581             continue()
582         endif()
583         if("${LINE}" MATCHES "~")
584             if(DEFINED API_SELECTED)
585                 message(WARNING "Destructor for '${CLS}' has @api. Tag ignored.")
586                 unset(API_SELECTED)
587             endif()
588             continue()
589         endif()
591         unset(IS_STATIC)
592         if("${LINE}" MATCHES "static")
593             set(IS_STATIC TRUE)
594         endif()
596         string(REGEX REPLACE "(virtual|static|const)[   ]+" "" LINE "${LINE}")
597         string(REGEX REPLACE "{.*" "" LINE "${LINE}")
598         set(PARAM_S "${LINE}")
599         string(REGEX REPLACE "\\*" "" LINE "${LINE}")
600         string(REGEX REPLACE "\\(.*" "" LINE "${LINE}")
602         string(REGEX REPLACE ".*\\(" "" PARAM_S "${PARAM_S}")
603         string(REGEX REPLACE "\\).*" "" PARAM_S "${PARAM_S}")
605         string(REGEX MATCH "([^         ]+)( ([^ ]+))?" RESULT "${LINE}")
606         set(FUNCTYPE "${CMAKE_MATCH_1}")
607         set(FUNCNAME "${CMAKE_MATCH_3}")
608         if("${FUNCTYPE}" STREQUAL "${CLS}" AND NOT FUNCNAME)
609             if(DEFINED API_SELECTED)
610                 message(WARNING "Constructor for '${CLS}' has @api. Tag ignored.")
611                 unset(API_SELECTED)
612             endif()
613             set(CLS_PARAM_0 "${PARAM_S}")
614             if(NOT PARAM_S)
615                 continue()
616             endif()
617         elseif(NOT FUNCNAME)
618             continue()
619                 endif()
621         string(REPLACE "," ";" PARAMS "${PARAM_S}")
622         if(IS_STATIC)
623             set(TYPES ".")
624         else()
625             set(TYPES "x")
626         endif()
628         set(LEN 1)
629         foreach(PARAM IN LISTS PARAMS)
630             math(EXPR LEN "${LEN} + 1")
631             string(STRIP "${PARAM}" PARAM)
632             if("${PARAM}" MATCHES "\\*|&")
633                 if("${PARAM}" MATCHES "^char")
634                     # Many types can be converted to string, so use '.', not 's'. (handled by our glue code)
635                     string(APPEND TYPES ".")
636                 elseif("${PARAM}" MATCHES "^void")
637                     string(APPEND TYPES "p")
638                 elseif("${PARAM}" MATCHES "^Array")
639                     string(APPEND TYPES "a")
640                 elseif("${PARAM}" MATCHES "^const Array")
641                     string(APPEND TYPES "a")
642                 elseif("${PARAM}" MATCHES "^Text")
643                     string(APPEND TYPES ".")
644                 elseif("${PARAM}" MATCHES "^std::string")
645                     string(APPEND TYPES ".")
646                 else()
647                     string(APPEND TYPES "x")
648                 endif()
649             elseif("${PARAM}" MATCHES "^bool")
650                 string(APPEND TYPES "b")
651             elseif("${PARAM}" MATCHES "^HSQUIRRELVM")
652                 set(TYPES "v")
653             else()
654                 string(APPEND TYPES "i")
655             endif()
656         endforeach()
658         # Check if we want to publish this function
659         if(NOT DEFINED API_SELECTED)
660             set(API_SELECTED ${CLS_IN_API})
661         endif()
662         if(NOT API_SELECTED)
663             unset(API_SELECTED)
664             continue()
665         endif()
666         unset(API_SELECTED)
668         if("${FUNCTYPE}" STREQUAL "${CLS}" AND NOT FUNCNAME)
669             set(CLS_PARAM_1 ${LEN})
670             set(CLS_PARAM_2 "${TYPES}")
671         elseif("${FUNCNAME}" MATCHES "^_" AND NOT "${TYPES}" STREQUAL "v")
672         elseif(IS_STATIC)
673             list(APPEND STATIC_METHODS "${FUNCNAME}:${LEN}:${TYPES}")
674         else()
675             list(APPEND METHODS "${FUNCNAME}:${LEN}:${TYPES}")
676         endif()
677         continue()
678     endif()
679 endforeach()
681 doxygen_check()
683 configure_file(${SCRIPT_API_SOURCE_FILE} ${SCRIPT_API_BINARY_FILE})