make_virtuals.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. script_call = """ScriptInstance *_script_instance = ((Object *)(this))->get_script_instance();\\
  2. if (_script_instance) {\\
  3. Callable::CallError ce;\\
  4. $CALLSIARGS\\
  5. $CALLSIBEGIN_script_instance->callp(_gdvirtual_##$VARNAME##_sn, $CALLSIARGPASS, ce);\\
  6. if (ce.error == Callable::CallError::CALL_OK) {\\
  7. $CALLSIRET\\
  8. return true;\\
  9. }\\
  10. }"""
  11. script_has_method = """ScriptInstance *_script_instance = ((Object *)(this))->get_script_instance();\\
  12. if (_script_instance && _script_instance->has_method(_gdvirtual_##$VARNAME##_sn)) {\\
  13. return true;\\
  14. }"""
  15. proto = """#define GDVIRTUAL$VER($ALIAS $RET m_name $ARG)\\
  16. mutable void *_gdvirtual_##$VARNAME = nullptr;\\
  17. _FORCE_INLINE_ bool _gdvirtual_##$VARNAME##_call($CALLARGS) $CONST {\\
  18. static const StringName _gdvirtual_##$VARNAME##_sn = StringName(#m_name, true);\\
  19. $SCRIPTCALL\\
  20. if (_get_extension()) {\\
  21. if (unlikely(!_gdvirtual_##$VARNAME)) {\\
  22. _gdvirtual_init_method_ptr(_gdvirtual_##$VARNAME##_get_method_info().get_compatibility_hash(), _gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT);\\
  23. }\\
  24. if (_gdvirtual_##$VARNAME != reinterpret_cast<void*>(_INVALID_GDVIRTUAL_FUNC_ADDR)) {\\
  25. $CALLPTRARGS\\
  26. $CALLPTRRETDEF\\
  27. if (_get_extension()->call_virtual_with_data) {\\
  28. _get_extension()->call_virtual_with_data(_get_extension_instance(), &_gdvirtual_##$VARNAME##_sn, _gdvirtual_##$VARNAME, $CALLPTRARGPASS, $CALLPTRRETPASS);\\
  29. $CALLPTRRET\\
  30. } else {\\
  31. ((GDExtensionClassCallVirtual)_gdvirtual_##$VARNAME)(_get_extension_instance(), $CALLPTRARGPASS, $CALLPTRRETPASS);\\
  32. $CALLPTRRET\\
  33. }\\
  34. return true;\\
  35. }\\
  36. }\\
  37. $REQCHECK\\
  38. $RVOID\\
  39. return false;\\
  40. }\\
  41. _FORCE_INLINE_ bool _gdvirtual_##$VARNAME##_overridden() const {\\
  42. static const StringName _gdvirtual_##$VARNAME##_sn = StringName(#m_name, true);\\
  43. $SCRIPTHASMETHOD\\
  44. if (_get_extension()) {\\
  45. if (unlikely(!_gdvirtual_##$VARNAME)) {\\
  46. _gdvirtual_init_method_ptr(_gdvirtual_##$VARNAME##_get_method_info().get_compatibility_hash(), _gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT);\\
  47. }\\
  48. if (_gdvirtual_##$VARNAME != reinterpret_cast<void*>(_INVALID_GDVIRTUAL_FUNC_ADDR)) {\\
  49. return true;\\
  50. }\\
  51. }\\
  52. return false;\\
  53. }\\
  54. _FORCE_INLINE_ static MethodInfo _gdvirtual_##$VARNAME##_get_method_info() {\\
  55. MethodInfo method_info;\\
  56. method_info.name = #m_name;\\
  57. method_info.flags = $METHOD_FLAGS;\\
  58. $FILL_METHOD_INFO\\
  59. return method_info;\\
  60. }
  61. """
  62. def generate_version(argcount, const=False, returns=False, required=False, compat=False):
  63. s = proto
  64. if compat:
  65. s = s.replace("$SCRIPTCALL", "")
  66. s = s.replace("$SCRIPTHASMETHOD", "")
  67. else:
  68. s = s.replace("$SCRIPTCALL", script_call)
  69. s = s.replace("$SCRIPTHASMETHOD", script_has_method)
  70. sproto = str(argcount)
  71. method_info = ""
  72. method_flags = "METHOD_FLAG_VIRTUAL"
  73. if returns:
  74. sproto += "R"
  75. s = s.replace("$RET", "m_ret,")
  76. s = s.replace("$RVOID", "(void)r_ret;") # If required, may lead to uninitialized errors
  77. s = s.replace("$CALLPTRRETDEF", "PtrToArg<m_ret>::EncodeT ret;")
  78. method_info += "method_info.return_val = GetTypeInfo<m_ret>::get_class_info();\\\n"
  79. method_info += "\t\tmethod_info.return_val_metadata = GetTypeInfo<m_ret>::METADATA;"
  80. else:
  81. s = s.replace("$RET ", "")
  82. s = s.replace("\t\t$RVOID\\\n", "")
  83. s = s.replace("\t\t\t$CALLPTRRETDEF\\\n", "")
  84. if const:
  85. sproto += "C"
  86. method_flags += " | METHOD_FLAG_CONST"
  87. s = s.replace("$CONST", "const")
  88. else:
  89. s = s.replace("$CONST ", "")
  90. if required:
  91. sproto += "_REQUIRED"
  92. method_flags += " | METHOD_FLAG_VIRTUAL_REQUIRED"
  93. s = s.replace(
  94. "$REQCHECK",
  95. 'ERR_PRINT_ONCE("Required virtual method " + get_class() + "::" + #m_name + " must be overridden before calling.");',
  96. )
  97. else:
  98. s = s.replace("\t\t$REQCHECK\\\n", "")
  99. if compat:
  100. sproto += "_COMPAT"
  101. s = s.replace("$COMPAT", "true")
  102. s = s.replace("$ALIAS", "m_alias,")
  103. s = s.replace("$VARNAME", "m_alias")
  104. else:
  105. s = s.replace("$COMPAT", "false")
  106. s = s.replace("$ALIAS ", "")
  107. s = s.replace("$VARNAME", "m_name")
  108. s = s.replace("$METHOD_FLAGS", method_flags)
  109. s = s.replace("$VER", sproto)
  110. argtext = ""
  111. callargtext = ""
  112. callsiargs = ""
  113. callsiargptrs = ""
  114. callptrargsptr = ""
  115. if argcount > 0:
  116. argtext += ", "
  117. callsiargs = f"Variant vargs[{argcount}] = {{ "
  118. callsiargptrs = f"\t\t\tconst Variant *vargptrs[{argcount}] = {{ "
  119. callptrargsptr = f"\t\t\tGDExtensionConstTypePtr argptrs[{argcount}] = {{ "
  120. if method_info:
  121. method_info += "\\\n\t\t"
  122. method_info += (
  123. "_gdvirtual_set_method_info_args<"
  124. + ", ".join(f"m_type{i + 1}" for i in range(argcount))
  125. + ">(method_info);"
  126. )
  127. callptrargs = ""
  128. for i in range(argcount):
  129. if i > 0:
  130. argtext += ", "
  131. callargtext += ", "
  132. callsiargs += ", "
  133. callsiargptrs += ", "
  134. callptrargs += "\t\t\t"
  135. callptrargsptr += ", "
  136. argtext += f"m_type{i + 1}"
  137. callargtext += f"m_type{i + 1} arg{i + 1}"
  138. callsiargs += f"VariantInternal::make(arg{i + 1})"
  139. callsiargptrs += f"&vargs[{i}]"
  140. callptrargs += f"PtrToArg<m_type{i + 1}>::EncodeT argval{i + 1}; PtrToArg<m_type{i + 1}>::encode(arg{i + 1}, &argval{i + 1});\\\n"
  141. callptrargsptr += f"&argval{i + 1}"
  142. if argcount:
  143. callsiargs += " };\\\n"
  144. callsiargptrs += " };"
  145. s = s.replace("$CALLSIARGS", callsiargs + callsiargptrs)
  146. s = s.replace("$CALLSIARGPASS", f"(const Variant **)vargptrs, {argcount}")
  147. callptrargsptr += " };"
  148. s = s.replace("$CALLPTRARGS", callptrargs + callptrargsptr)
  149. s = s.replace("$CALLPTRARGPASS", "reinterpret_cast<GDExtensionConstTypePtr *>(argptrs)")
  150. else:
  151. s = s.replace("\t\t\t$CALLSIARGS\\\n", "")
  152. s = s.replace("$CALLSIARGPASS", "nullptr, 0")
  153. s = s.replace("\t\t\t$CALLPTRARGS\\\n", "")
  154. s = s.replace("$CALLPTRARGPASS", "nullptr")
  155. if returns:
  156. if argcount > 0:
  157. callargtext += ", "
  158. callargtext += "m_ret &r_ret"
  159. s = s.replace("$CALLSIBEGIN", "Variant ret = ")
  160. s = s.replace("$CALLSIRET", "r_ret = VariantCaster<m_ret>::cast(ret);")
  161. s = s.replace("$CALLPTRRETPASS", "&ret")
  162. s = s.replace("$CALLPTRRET", "r_ret = (m_ret)ret;")
  163. else:
  164. s = s.replace("$CALLSIBEGIN", "")
  165. s = s.replace("\t\t\t\t$CALLSIRET\\\n", "")
  166. s = s.replace("$CALLPTRRETPASS", "nullptr")
  167. s = s.replace("\t\t\t\t$CALLPTRRET\\\n", "")
  168. s = s.replace(" $ARG", argtext)
  169. s = s.replace("$CALLARGS", callargtext)
  170. if method_info:
  171. s = s.replace("$FILL_METHOD_INFO", method_info)
  172. else:
  173. s = s.replace("\t\t$FILL_METHOD_INFO\\\n", method_info)
  174. return s
  175. def run(target, source, env):
  176. max_versions = 12
  177. txt = """/* THIS FILE IS GENERATED DO NOT EDIT */
  178. #pragma once
  179. #include "core/object/script_instance.h"
  180. inline constexpr uintptr_t _INVALID_GDVIRTUAL_FUNC_ADDR = static_cast<uintptr_t>(-1);
  181. template <typename... Args>
  182. void _gdvirtual_set_method_info_args(MethodInfo &p_method_info) {
  183. p_method_info.arguments = { GetTypeInfo<Args>::get_class_info()... };
  184. p_method_info.arguments_metadata = { GetTypeInfo<Args>::METADATA... };
  185. }
  186. """
  187. for i in range(max_versions + 1):
  188. txt += f"/* {i} Arguments */\n\n"
  189. txt += generate_version(i, False, False)
  190. txt += generate_version(i, False, True)
  191. txt += generate_version(i, True, False)
  192. txt += generate_version(i, True, True)
  193. txt += generate_version(i, False, False, True)
  194. txt += generate_version(i, False, True, True)
  195. txt += generate_version(i, True, False, True)
  196. txt += generate_version(i, True, True, True)
  197. txt += generate_version(i, False, False, False, True)
  198. txt += generate_version(i, False, True, False, True)
  199. txt += generate_version(i, True, False, False, True)
  200. txt += generate_version(i, True, True, False, True)
  201. with open(str(target[0]), "w", encoding="utf-8", newline="\n") as f:
  202. f.write(txt)