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