1/**************************************************************************/
2/* gdscript_compiler.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "gdscript_compiler.h"
32
33#include "gdscript.h"
34#include "gdscript_byte_codegen.h"
35#include "gdscript_cache.h"
36#include "gdscript_utility_functions.h"
37
38#include "core/config/engine.h"
39#include "core/config/project_settings.h"
40
41bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) {
42 if (codegen.function_node && codegen.function_node->is_static) {
43 return false;
44 }
45
46 if (_is_local_or_parameter(codegen, p_name)) {
47 return false; //shadowed
48 }
49
50 return _is_class_member_property(codegen.script, p_name);
51}
52
53bool GDScriptCompiler::_is_class_member_property(GDScript *owner, const StringName &p_name) {
54 GDScript *scr = owner;
55 GDScriptNativeClass *nc = nullptr;
56 while (scr) {
57 if (scr->native.is_valid()) {
58 nc = scr->native.ptr();
59 }
60 scr = scr->_base;
61 }
62
63 ERR_FAIL_COND_V(!nc, false);
64
65 return ClassDB::has_property(nc->get_name(), p_name);
66}
67
68bool GDScriptCompiler::_is_local_or_parameter(CodeGen &codegen, const StringName &p_name) {
69 return codegen.parameters.has(p_name) || codegen.locals.has(p_name);
70}
71
72void GDScriptCompiler::_set_error(const String &p_error, const GDScriptParser::Node *p_node) {
73 if (!error.is_empty()) {
74 return;
75 }
76
77 error = p_error;
78 if (p_node) {
79 err_line = p_node->start_line;
80 err_column = p_node->leftmost_column;
81 } else {
82 err_line = 0;
83 err_column = 0;
84 }
85}
86
87GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::DataType &p_datatype, GDScript *p_owner, bool p_handle_metatype) {
88 if (!p_datatype.is_set() || !p_datatype.is_hard_type() || p_datatype.is_coroutine) {
89 return GDScriptDataType();
90 }
91
92 GDScriptDataType result;
93 result.has_type = true;
94
95 switch (p_datatype.kind) {
96 case GDScriptParser::DataType::VARIANT: {
97 result.has_type = false;
98 } break;
99 case GDScriptParser::DataType::BUILTIN: {
100 result.kind = GDScriptDataType::BUILTIN;
101 result.builtin_type = p_datatype.builtin_type;
102 } break;
103 case GDScriptParser::DataType::NATIVE: {
104 if (p_handle_metatype && p_datatype.is_meta_type) {
105 result.kind = GDScriptDataType::NATIVE;
106 result.builtin_type = Variant::OBJECT;
107 result.native_type = GDScriptNativeClass::get_class_static();
108 break;
109 }
110
111 result.kind = GDScriptDataType::NATIVE;
112 result.native_type = p_datatype.native_type;
113 result.builtin_type = p_datatype.builtin_type;
114 } break;
115 case GDScriptParser::DataType::SCRIPT: {
116 if (p_handle_metatype && p_datatype.is_meta_type) {
117 result.kind = GDScriptDataType::NATIVE;
118 result.builtin_type = Variant::OBJECT;
119 result.native_type = p_datatype.script_type.is_valid() ? p_datatype.script_type->get_class() : Script::get_class_static();
120 break;
121 }
122
123 result.kind = GDScriptDataType::SCRIPT;
124 result.builtin_type = p_datatype.builtin_type;
125 result.script_type_ref = p_datatype.script_type;
126 result.script_type = result.script_type_ref.ptr();
127 result.native_type = p_datatype.native_type;
128 } break;
129 case GDScriptParser::DataType::CLASS: {
130 if (p_handle_metatype && p_datatype.is_meta_type) {
131 result.kind = GDScriptDataType::NATIVE;
132 result.builtin_type = Variant::OBJECT;
133 result.native_type = GDScript::get_class_static();
134 break;
135 }
136
137 result.kind = GDScriptDataType::GDSCRIPT;
138 result.builtin_type = p_datatype.builtin_type;
139 result.native_type = p_datatype.native_type;
140
141 bool is_local_class = parser->has_class(p_datatype.class_type);
142
143 Ref<GDScript> script;
144 if (is_local_class) {
145 script = Ref<GDScript>(main_script);
146 } else {
147 Error err = OK;
148 script = GDScriptCache::get_shallow_script(p_datatype.script_path, err, p_owner->path);
149 if (err) {
150 _set_error(vformat(R"(Could not find script "%s": %s)", p_datatype.script_path, error_names[err]), nullptr);
151 }
152 }
153
154 if (script.is_valid()) {
155 script = Ref<GDScript>(script->find_class(p_datatype.class_type->fqcn));
156 }
157
158 if (script.is_null()) {
159 _set_error(vformat(R"(Could not find class "%s" in "%s".)", p_datatype.class_type->fqcn, p_datatype.script_path), nullptr);
160 return GDScriptDataType();
161 } else {
162 // Only hold a strong reference if the owner of the element qualified with this type is not local, to avoid cyclic references (leaks).
163 // TODO: Might lead to use after free if script_type is a subclass and is used after its parent is freed.
164 if (!is_local_class) {
165 result.script_type_ref = script;
166 }
167 result.script_type = script.ptr();
168 result.native_type = p_datatype.native_type;
169 }
170 } break;
171 case GDScriptParser::DataType::ENUM:
172 if (p_handle_metatype && p_datatype.is_meta_type) {
173 result.kind = GDScriptDataType::BUILTIN;
174 result.builtin_type = Variant::DICTIONARY;
175 break;
176 }
177
178 result.kind = GDScriptDataType::BUILTIN;
179 result.builtin_type = p_datatype.builtin_type;
180 break;
181 case GDScriptParser::DataType::RESOLVING:
182 case GDScriptParser::DataType::UNRESOLVED: {
183 ERR_PRINT("Parser bug: converting unresolved type.");
184 return GDScriptDataType();
185 }
186 }
187
188 if (p_datatype.has_container_element_type()) {
189 result.set_container_element_type(_gdtype_from_datatype(p_datatype.get_container_element_type(), p_owner, false));
190 }
191
192 return result;
193}
194
195static bool _is_exact_type(const PropertyInfo &p_par_type, const GDScriptDataType &p_arg_type) {
196 if (!p_arg_type.has_type) {
197 return false;
198 }
199 if (p_par_type.type == Variant::NIL) {
200 return false;
201 }
202 if (p_par_type.type == Variant::OBJECT) {
203 if (p_arg_type.kind == GDScriptDataType::BUILTIN) {
204 return false;
205 }
206 StringName class_name;
207 if (p_arg_type.kind == GDScriptDataType::NATIVE) {
208 class_name = p_arg_type.native_type;
209 } else {
210 class_name = p_arg_type.native_type == StringName() ? p_arg_type.script_type->get_instance_base_type() : p_arg_type.native_type;
211 }
212 return p_par_type.class_name == class_name || ClassDB::is_parent_class(class_name, p_par_type.class_name);
213 } else {
214 if (p_arg_type.kind != GDScriptDataType::BUILTIN) {
215 return false;
216 }
217 return p_par_type.type == p_arg_type.builtin_type;
218 }
219}
220
221static bool _can_use_ptrcall(const MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) {
222 if (p_method->is_vararg()) {
223 // ptrcall won't work with vararg methods.
224 return false;
225 }
226 if (p_method->get_argument_count() != p_arguments.size()) {
227 // ptrcall won't work with default arguments.
228 return false;
229 }
230 MethodInfo info;
231 ClassDB::get_method_info(p_method->get_instance_class(), p_method->get_name(), &info);
232 for (int i = 0; i < p_arguments.size(); i++) {
233 const PropertyInfo &prop = info.arguments[i];
234 if (!_is_exact_type(prop, p_arguments[i].type)) {
235 return false;
236 }
237 }
238 return true;
239}
240
241GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root, bool p_initializer, const GDScriptCodeGenerator::Address &p_index_addr) {
242 if (p_expression->is_constant && !(p_expression->get_datatype().is_meta_type && p_expression->get_datatype().kind == GDScriptParser::DataType::CLASS)) {
243 return codegen.add_constant(p_expression->reduced_value);
244 }
245
246 GDScriptCodeGenerator *gen = codegen.generator;
247
248 switch (p_expression->type) {
249 case GDScriptParser::Node::IDENTIFIER: {
250 // Look for identifiers in current scope.
251 const GDScriptParser::IdentifierNode *in = static_cast<const GDScriptParser::IdentifierNode *>(p_expression);
252
253 StringName identifier = in->name;
254
255 switch (in->source) {
256 // LOCALS.
257 case GDScriptParser::IdentifierNode::FUNCTION_PARAMETER:
258 case GDScriptParser::IdentifierNode::LOCAL_VARIABLE:
259 case GDScriptParser::IdentifierNode::LOCAL_CONSTANT:
260 case GDScriptParser::IdentifierNode::LOCAL_ITERATOR:
261 case GDScriptParser::IdentifierNode::LOCAL_BIND: {
262 // Try function parameters.
263 if (codegen.parameters.has(identifier)) {
264 return codegen.parameters[identifier];
265 }
266
267 // Try local variables and constants.
268 if (!p_initializer && codegen.locals.has(identifier)) {
269 return codegen.locals[identifier];
270 }
271 } break;
272
273 // MEMBERS.
274 case GDScriptParser::IdentifierNode::MEMBER_VARIABLE:
275 case GDScriptParser::IdentifierNode::MEMBER_FUNCTION:
276 case GDScriptParser::IdentifierNode::MEMBER_SIGNAL:
277 case GDScriptParser::IdentifierNode::INHERITED_VARIABLE: {
278 // Try class members.
279 if (_is_class_member_property(codegen, identifier)) {
280 // Get property.
281 GDScriptCodeGenerator::Address temp = codegen.add_temporary(_gdtype_from_datatype(p_expression->get_datatype(), codegen.script));
282 gen->write_get_member(temp, identifier);
283 return temp;
284 }
285
286 // Try members.
287 if (!codegen.function_node || !codegen.function_node->is_static) {
288 // Try member variables.
289 if (codegen.script->member_indices.has(identifier)) {
290 if (codegen.script->member_indices[identifier].getter != StringName() && codegen.script->member_indices[identifier].getter != codegen.function_name) {
291 // Perform getter.
292 GDScriptCodeGenerator::Address temp = codegen.add_temporary(codegen.script->member_indices[identifier].data_type);
293 Vector<GDScriptCodeGenerator::Address> args; // No argument needed.
294 gen->write_call_self(temp, codegen.script->member_indices[identifier].getter, args);
295 return temp;
296 } else {
297 // No getter or inside getter: direct member access.
298 int idx = codegen.script->member_indices[identifier].index;
299 return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::MEMBER, idx, codegen.script->get_member_type(identifier));
300 }
301 }
302 }
303
304 // Try methods and signals (can be Callable and Signal).
305 {
306 // Search upwards through parent classes:
307 const GDScriptParser::ClassNode *base_class = codegen.class_node;
308 while (base_class != nullptr) {
309 if (base_class->has_member(identifier)) {
310 const GDScriptParser::ClassNode::Member &member = base_class->get_member(identifier);
311 if (member.type == GDScriptParser::ClassNode::Member::FUNCTION || member.type == GDScriptParser::ClassNode::Member::SIGNAL) {
312 // Get like it was a property.
313 GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here.
314 GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF);
315
316 gen->write_get_named(temp, identifier, self);
317 return temp;
318 }
319 }
320 base_class = base_class->base_type.class_type;
321 }
322
323 // Try in native base.
324 GDScript *scr = codegen.script;
325 GDScriptNativeClass *nc = nullptr;
326 while (scr) {
327 if (scr->native.is_valid()) {
328 nc = scr->native.ptr();
329 }
330 scr = scr->_base;
331 }
332
333 if (nc && (ClassDB::has_signal(nc->get_name(), identifier) || ClassDB::has_method(nc->get_name(), identifier))) {
334 // Get like it was a property.
335 GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here.
336 GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF);
337
338 gen->write_get_named(temp, identifier, self);
339 return temp;
340 }
341 }
342 } break;
343 case GDScriptParser::IdentifierNode::MEMBER_CONSTANT:
344 case GDScriptParser::IdentifierNode::MEMBER_CLASS: {
345 // Try class constants.
346 GDScript *owner = codegen.script;
347 while (owner) {
348 GDScript *scr = owner;
349 GDScriptNativeClass *nc = nullptr;
350
351 while (scr) {
352 if (scr->constants.has(identifier)) {
353 return codegen.add_constant(scr->constants[identifier]); // TODO: Get type here.
354 }
355 if (scr->native.is_valid()) {
356 nc = scr->native.ptr();
357 }
358 scr = scr->_base;
359 }
360
361 // Class C++ integer constant.
362 if (nc) {
363 bool success = false;
364 int64_t constant = ClassDB::get_integer_constant(nc->get_name(), identifier, &success);
365 if (success) {
366 return codegen.add_constant(constant);
367 }
368 }
369
370 owner = owner->_owner;
371 }
372 } break;
373 case GDScriptParser::IdentifierNode::STATIC_VARIABLE: {
374 // Try static variables.
375 GDScript *scr = codegen.script;
376 while (scr) {
377 if (scr->static_variables_indices.has(identifier)) {
378 if (scr->static_variables_indices[identifier].getter != StringName() && scr->static_variables_indices[identifier].getter != codegen.function_name) {
379 // Perform getter.
380 GDScriptCodeGenerator::Address temp = codegen.add_temporary(scr->static_variables_indices[identifier].data_type);
381 GDScriptCodeGenerator::Address class_addr(GDScriptCodeGenerator::Address::CLASS);
382 Vector<GDScriptCodeGenerator::Address> args; // No argument needed.
383 gen->write_call(temp, class_addr, scr->static_variables_indices[identifier].getter, args);
384 return temp;
385 } else {
386 // No getter or inside getter: direct variable access.
387 GDScriptCodeGenerator::Address temp = codegen.add_temporary(scr->static_variables_indices[identifier].data_type);
388 GDScriptCodeGenerator::Address _class = codegen.add_constant(scr);
389 int index = scr->static_variables_indices[identifier].index;
390 gen->write_get_static_variable(temp, _class, index);
391 return temp;
392 }
393 }
394 scr = scr->_base;
395 }
396 } break;
397
398 // GLOBALS.
399 case GDScriptParser::IdentifierNode::UNDEFINED_SOURCE: {
400 // Try globals.
401 if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
402 // If it's an autoload singleton, we postpone to load it at runtime.
403 // This is so one autoload doesn't try to load another before it's compiled.
404 HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
405 if (autoloads.has(identifier) && autoloads[identifier].is_singleton) {
406 GDScriptCodeGenerator::Address global = codegen.add_temporary(_gdtype_from_datatype(in->get_datatype(), codegen.script));
407 int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
408 gen->write_store_global(global, idx);
409 return global;
410 } else {
411 int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
412 Variant global = GDScriptLanguage::get_singleton()->get_global_array()[idx];
413 return codegen.add_constant(global);
414 }
415 }
416
417 // Try global classes.
418 if (ScriptServer::is_global_class(identifier)) {
419 const GDScriptParser::ClassNode *class_node = codegen.class_node;
420 while (class_node->outer) {
421 class_node = class_node->outer;
422 }
423
424 Ref<Resource> res;
425
426 if (class_node->identifier && class_node->identifier->name == identifier) {
427 res = Ref<GDScript>(main_script);
428 } else {
429 String global_class_path = ScriptServer::get_global_class_path(identifier);
430 if (ResourceLoader::get_resource_type(global_class_path) == "GDScript") {
431 Error err = OK;
432 // Should not need to pass p_owner since analyzer will already have done it.
433 res = GDScriptCache::get_shallow_script(global_class_path, err);
434 if (err != OK) {
435 _set_error("Can't load global class " + String(identifier), p_expression);
436 r_error = ERR_COMPILATION_FAILED;
437 return GDScriptCodeGenerator::Address();
438 }
439 } else {
440 res = ResourceLoader::load(global_class_path);
441 if (res.is_null()) {
442 _set_error("Can't load global class " + String(identifier) + ", cyclic reference?", p_expression);
443 r_error = ERR_COMPILATION_FAILED;
444 return GDScriptCodeGenerator::Address();
445 }
446 }
447 }
448
449 return codegen.add_constant(res);
450 }
451
452#ifdef TOOLS_ENABLED
453 if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) {
454 GDScriptCodeGenerator::Address global = codegen.add_temporary(); // TODO: Get type.
455 gen->write_store_named_global(global, identifier);
456 return global;
457 }
458#endif
459
460 } break;
461 }
462
463 // Not found, error.
464 _set_error("Identifier not found: " + String(identifier), p_expression);
465 r_error = ERR_COMPILATION_FAILED;
466 return GDScriptCodeGenerator::Address();
467 } break;
468 case GDScriptParser::Node::LITERAL: {
469 // Return constant.
470 const GDScriptParser::LiteralNode *cn = static_cast<const GDScriptParser::LiteralNode *>(p_expression);
471
472 return codegen.add_constant(cn->value);
473 } break;
474 case GDScriptParser::Node::SELF: {
475 //return constant
476 if (codegen.function_node && codegen.function_node->is_static) {
477 _set_error("'self' not present in static function!", p_expression);
478 r_error = ERR_COMPILATION_FAILED;
479 return GDScriptCodeGenerator::Address();
480 }
481 return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF);
482 } break;
483 case GDScriptParser::Node::ARRAY: {
484 const GDScriptParser::ArrayNode *an = static_cast<const GDScriptParser::ArrayNode *>(p_expression);
485 Vector<GDScriptCodeGenerator::Address> values;
486
487 // Create the result temporary first since it's the last to be killed.
488 GDScriptDataType array_type = _gdtype_from_datatype(an->get_datatype(), codegen.script);
489 GDScriptCodeGenerator::Address result = codegen.add_temporary(array_type);
490
491 for (int i = 0; i < an->elements.size(); i++) {
492 GDScriptCodeGenerator::Address val = _parse_expression(codegen, r_error, an->elements[i]);
493 if (r_error) {
494 return GDScriptCodeGenerator::Address();
495 }
496 values.push_back(val);
497 }
498
499 if (array_type.has_container_element_type()) {
500 gen->write_construct_typed_array(result, array_type.get_container_element_type(), values);
501 } else {
502 gen->write_construct_array(result, values);
503 }
504
505 for (int i = 0; i < values.size(); i++) {
506 if (values[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
507 gen->pop_temporary();
508 }
509 }
510
511 return result;
512 } break;
513 case GDScriptParser::Node::DICTIONARY: {
514 const GDScriptParser::DictionaryNode *dn = static_cast<const GDScriptParser::DictionaryNode *>(p_expression);
515 Vector<GDScriptCodeGenerator::Address> elements;
516
517 // Create the result temporary first since it's the last to be killed.
518 GDScriptDataType dict_type;
519 dict_type.has_type = true;
520 dict_type.kind = GDScriptDataType::BUILTIN;
521 dict_type.builtin_type = Variant::DICTIONARY;
522 GDScriptCodeGenerator::Address result = codegen.add_temporary(dict_type);
523
524 for (int i = 0; i < dn->elements.size(); i++) {
525 // Key.
526 GDScriptCodeGenerator::Address element;
527 switch (dn->style) {
528 case GDScriptParser::DictionaryNode::PYTHON_DICT:
529 // Python-style: key is any expression.
530 element = _parse_expression(codegen, r_error, dn->elements[i].key);
531 if (r_error) {
532 return GDScriptCodeGenerator::Address();
533 }
534 break;
535 case GDScriptParser::DictionaryNode::LUA_TABLE:
536 // Lua-style: key is an identifier interpreted as StringName.
537 StringName key = dn->elements[i].key->reduced_value.operator StringName();
538 element = codegen.add_constant(key);
539 break;
540 }
541
542 elements.push_back(element);
543
544 element = _parse_expression(codegen, r_error, dn->elements[i].value);
545 if (r_error) {
546 return GDScriptCodeGenerator::Address();
547 }
548
549 elements.push_back(element);
550 }
551
552 gen->write_construct_dictionary(result, elements);
553
554 for (int i = 0; i < elements.size(); i++) {
555 if (elements[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
556 gen->pop_temporary();
557 }
558 }
559
560 return result;
561 } break;
562 case GDScriptParser::Node::CAST: {
563 const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression);
564 GDScriptDataType cast_type = _gdtype_from_datatype(cn->get_datatype(), codegen.script, false);
565
566 GDScriptCodeGenerator::Address result;
567 if (cast_type.has_type) {
568 // Create temporary for result first since it will be deleted last.
569 result = codegen.add_temporary(cast_type);
570
571 GDScriptCodeGenerator::Address src = _parse_expression(codegen, r_error, cn->operand);
572
573 gen->write_cast(result, src, cast_type);
574
575 if (src.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
576 gen->pop_temporary();
577 }
578 } else {
579 result = _parse_expression(codegen, r_error, cn->operand);
580 }
581
582 return result;
583 } break;
584 case GDScriptParser::Node::CALL: {
585 const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_expression);
586 bool is_awaited = p_expression == awaited_node;
587 GDScriptDataType type = _gdtype_from_datatype(call->get_datatype(), codegen.script);
588 GDScriptCodeGenerator::Address result;
589 if (p_root) {
590 result = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NIL);
591 } else {
592 result = codegen.add_temporary(type);
593 }
594
595 Vector<GDScriptCodeGenerator::Address> arguments;
596 for (int i = 0; i < call->arguments.size(); i++) {
597 GDScriptCodeGenerator::Address arg = _parse_expression(codegen, r_error, call->arguments[i]);
598 if (r_error) {
599 return GDScriptCodeGenerator::Address();
600 }
601 arguments.push_back(arg);
602 }
603
604 if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(call->function_name) != Variant::VARIANT_MAX) {
605 // Construct a built-in type.
606 Variant::Type vtype = GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
607
608 gen->write_construct(result, vtype, arguments);
609 } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && Variant::has_utility_function(call->function_name)) {
610 // Variant utility function.
611 gen->write_call_utility(result, call->function_name, arguments);
612 } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptUtilityFunctions::function_exists(call->function_name)) {
613 // GDScript utility function.
614 gen->write_call_gdscript_utility(result, call->function_name, arguments);
615 } else {
616 // Regular function.
617 const GDScriptParser::ExpressionNode *callee = call->callee;
618
619 if (call->is_super) {
620 // Super call.
621 gen->write_super_call(result, call->function_name, arguments);
622 } else {
623 if (callee->type == GDScriptParser::Node::IDENTIFIER) {
624 // Self function call.
625 if (ClassDB::has_method(codegen.script->native->get_name(), call->function_name)) {
626 // Native method, use faster path.
627 GDScriptCodeGenerator::Address self;
628 self.mode = GDScriptCodeGenerator::Address::SELF;
629 MethodBind *method = ClassDB::get_method(codegen.script->native->get_name(), call->function_name);
630
631 if (_can_use_ptrcall(method, arguments)) {
632 // Exact arguments, use ptrcall.
633 gen->write_call_ptrcall(result, self, method, arguments);
634 } else {
635 // Not exact arguments, but still can use method bind call.
636 gen->write_call_method_bind(result, self, method, arguments);
637 }
638 } else if (codegen.is_static || (codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
639 GDScriptCodeGenerator::Address self;
640 self.mode = GDScriptCodeGenerator::Address::CLASS;
641 if (is_awaited) {
642 gen->write_call_async(result, self, call->function_name, arguments);
643 } else {
644 gen->write_call(result, self, call->function_name, arguments);
645 }
646 } else {
647 if (is_awaited) {
648 gen->write_call_self_async(result, call->function_name, arguments);
649 } else {
650 gen->write_call_self(result, call->function_name, arguments);
651 }
652 }
653 } else if (callee->type == GDScriptParser::Node::SUBSCRIPT) {
654 const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee);
655
656 if (subscript->is_attribute) {
657 // May be static built-in method call.
658 if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) {
659 gen->write_call_builtin_type_static(result, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments);
660 } else if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && call->function_name != SNAME("new") &&
661 ClassDB::class_exists(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) && !Engine::get_singleton()->has_singleton(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name)) {
662 // It's a static native method call.
663 gen->write_call_native_static(result, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments);
664 } else {
665 GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
666 if (r_error) {
667 return GDScriptCodeGenerator::Address();
668 }
669 if (is_awaited) {
670 gen->write_call_async(result, base, call->function_name, arguments);
671 } else if (base.type.has_type && base.type.kind != GDScriptDataType::BUILTIN) {
672 // Native method, use faster path.
673 StringName class_name;
674 if (base.type.kind == GDScriptDataType::NATIVE) {
675 class_name = base.type.native_type;
676 } else {
677 class_name = base.type.native_type == StringName() ? base.type.script_type->get_instance_base_type() : base.type.native_type;
678 }
679 if (ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) {
680 MethodBind *method = ClassDB::get_method(class_name, call->function_name);
681 if (_can_use_ptrcall(method, arguments)) {
682 // Exact arguments, use ptrcall.
683 gen->write_call_ptrcall(result, base, method, arguments);
684 } else {
685 // Not exact arguments, but still can use method bind call.
686 gen->write_call_method_bind(result, base, method, arguments);
687 }
688 } else {
689 gen->write_call(result, base, call->function_name, arguments);
690 }
691 } else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) {
692 gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments);
693 } else {
694 gen->write_call(result, base, call->function_name, arguments);
695 }
696 if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
697 gen->pop_temporary();
698 }
699 }
700 } else {
701 _set_error("Cannot call something that isn't a function.", call->callee);
702 r_error = ERR_COMPILATION_FAILED;
703 return GDScriptCodeGenerator::Address();
704 }
705 } else {
706 r_error = ERR_COMPILATION_FAILED;
707 return GDScriptCodeGenerator::Address();
708 }
709 }
710 }
711
712 for (int i = 0; i < arguments.size(); i++) {
713 if (arguments[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
714 gen->pop_temporary();
715 }
716 }
717 return result;
718 } break;
719 case GDScriptParser::Node::GET_NODE: {
720 const GDScriptParser::GetNodeNode *get_node = static_cast<const GDScriptParser::GetNodeNode *>(p_expression);
721
722 Vector<GDScriptCodeGenerator::Address> args;
723 args.push_back(codegen.add_constant(NodePath(get_node->full_path)));
724
725 GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(get_node->get_datatype(), codegen.script));
726
727 MethodBind *get_node_method = ClassDB::get_method("Node", "get_node");
728 gen->write_call_ptrcall(result, GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), get_node_method, args);
729
730 return result;
731 } break;
732 case GDScriptParser::Node::PRELOAD: {
733 const GDScriptParser::PreloadNode *preload = static_cast<const GDScriptParser::PreloadNode *>(p_expression);
734
735 // Add resource as constant.
736 return codegen.add_constant(preload->resource);
737 } break;
738 case GDScriptParser::Node::AWAIT: {
739 const GDScriptParser::AwaitNode *await = static_cast<const GDScriptParser::AwaitNode *>(p_expression);
740
741 GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(p_expression->get_datatype(), codegen.script));
742 GDScriptParser::ExpressionNode *previous_awaited_node = awaited_node;
743 awaited_node = await->to_await;
744 GDScriptCodeGenerator::Address argument = _parse_expression(codegen, r_error, await->to_await);
745 awaited_node = previous_awaited_node;
746 if (r_error) {
747 return GDScriptCodeGenerator::Address();
748 }
749
750 gen->write_await(result, argument);
751
752 if (argument.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
753 gen->pop_temporary();
754 }
755
756 return result;
757 } break;
758 // Indexing operator.
759 case GDScriptParser::Node::SUBSCRIPT: {
760 const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(p_expression);
761 GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(subscript->get_datatype(), codegen.script));
762
763 GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
764 if (r_error) {
765 return GDScriptCodeGenerator::Address();
766 }
767
768 bool named = subscript->is_attribute;
769 StringName name;
770 GDScriptCodeGenerator::Address index;
771 if (p_index_addr.mode != GDScriptCodeGenerator::Address::NIL) {
772 index = p_index_addr;
773 } else if (subscript->is_attribute) {
774 if (subscript->base->type == GDScriptParser::Node::SELF && codegen.script) {
775 GDScriptParser::IdentifierNode *identifier = subscript->attribute;
776 HashMap<StringName, GDScript::MemberInfo>::Iterator MI = codegen.script->member_indices.find(identifier->name);
777
778#ifdef DEBUG_ENABLED
779 if (MI && MI->value.getter == codegen.function_name) {
780 String n = identifier->name;
781 _set_error("Must use '" + n + "' instead of 'self." + n + "' in getter.", identifier);
782 r_error = ERR_COMPILATION_FAILED;
783 return GDScriptCodeGenerator::Address();
784 }
785#endif
786
787 if (MI && MI->value.getter == "") {
788 // Remove result temp as we don't need it.
789 gen->pop_temporary();
790 // Faster than indexing self (as if no self. had been used).
791 return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::MEMBER, MI->value.index, _gdtype_from_datatype(subscript->get_datatype(), codegen.script));
792 }
793 }
794
795 name = subscript->attribute->name;
796 named = true;
797 } else {
798 if (subscript->index->is_constant && subscript->index->reduced_value.get_type() == Variant::STRING_NAME) {
799 // Also, somehow, named (speed up anyway).
800 name = subscript->index->reduced_value;
801 named = true;
802 } else {
803 // Regular indexing.
804 index = _parse_expression(codegen, r_error, subscript->index);
805 if (r_error) {
806 return GDScriptCodeGenerator::Address();
807 }
808 }
809 }
810
811 if (named) {
812 gen->write_get_named(result, name, base);
813 } else {
814 gen->write_get(result, index, base);
815 }
816
817 if (index.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
818 gen->pop_temporary();
819 }
820 if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
821 gen->pop_temporary();
822 }
823
824 return result;
825 } break;
826 case GDScriptParser::Node::UNARY_OPERATOR: {
827 const GDScriptParser::UnaryOpNode *unary = static_cast<const GDScriptParser::UnaryOpNode *>(p_expression);
828
829 GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(unary->get_datatype(), codegen.script));
830
831 GDScriptCodeGenerator::Address operand = _parse_expression(codegen, r_error, unary->operand);
832 if (r_error) {
833 return GDScriptCodeGenerator::Address();
834 }
835
836 gen->write_unary_operator(result, unary->variant_op, operand);
837
838 if (operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
839 gen->pop_temporary();
840 }
841
842 return result;
843 }
844 case GDScriptParser::Node::BINARY_OPERATOR: {
845 const GDScriptParser::BinaryOpNode *binary = static_cast<const GDScriptParser::BinaryOpNode *>(p_expression);
846
847 GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(binary->get_datatype(), codegen.script));
848
849 switch (binary->operation) {
850 case GDScriptParser::BinaryOpNode::OP_LOGIC_AND: {
851 // AND operator with early out on failure.
852 GDScriptCodeGenerator::Address left_operand = _parse_expression(codegen, r_error, binary->left_operand);
853 gen->write_and_left_operand(left_operand);
854 GDScriptCodeGenerator::Address right_operand = _parse_expression(codegen, r_error, binary->right_operand);
855 gen->write_and_right_operand(right_operand);
856
857 gen->write_end_and(result);
858
859 if (right_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
860 gen->pop_temporary();
861 }
862 if (left_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
863 gen->pop_temporary();
864 }
865 } break;
866 case GDScriptParser::BinaryOpNode::OP_LOGIC_OR: {
867 // OR operator with early out on success.
868 GDScriptCodeGenerator::Address left_operand = _parse_expression(codegen, r_error, binary->left_operand);
869 gen->write_or_left_operand(left_operand);
870 GDScriptCodeGenerator::Address right_operand = _parse_expression(codegen, r_error, binary->right_operand);
871 gen->write_or_right_operand(right_operand);
872
873 gen->write_end_or(result);
874
875 if (right_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
876 gen->pop_temporary();
877 }
878 if (left_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
879 gen->pop_temporary();
880 }
881 } break;
882 default: {
883 GDScriptCodeGenerator::Address left_operand = _parse_expression(codegen, r_error, binary->left_operand);
884 GDScriptCodeGenerator::Address right_operand = _parse_expression(codegen, r_error, binary->right_operand);
885
886 gen->write_binary_operator(result, binary->variant_op, left_operand, right_operand);
887
888 if (right_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
889 gen->pop_temporary();
890 }
891 if (left_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
892 gen->pop_temporary();
893 }
894 }
895 }
896 return result;
897 } break;
898 case GDScriptParser::Node::TERNARY_OPERATOR: {
899 // x IF a ELSE y operator with early out on failure.
900 const GDScriptParser::TernaryOpNode *ternary = static_cast<const GDScriptParser::TernaryOpNode *>(p_expression);
901 GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(ternary->get_datatype(), codegen.script));
902
903 gen->write_start_ternary(result);
904
905 GDScriptCodeGenerator::Address condition = _parse_expression(codegen, r_error, ternary->condition);
906 if (r_error) {
907 return GDScriptCodeGenerator::Address();
908 }
909 gen->write_ternary_condition(condition);
910
911 if (condition.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
912 gen->pop_temporary();
913 }
914
915 GDScriptCodeGenerator::Address true_expr = _parse_expression(codegen, r_error, ternary->true_expr);
916 if (r_error) {
917 return GDScriptCodeGenerator::Address();
918 }
919 gen->write_ternary_true_expr(true_expr);
920 if (true_expr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
921 gen->pop_temporary();
922 }
923
924 GDScriptCodeGenerator::Address false_expr = _parse_expression(codegen, r_error, ternary->false_expr);
925 if (r_error) {
926 return GDScriptCodeGenerator::Address();
927 }
928 gen->write_ternary_false_expr(false_expr);
929 if (false_expr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
930 gen->pop_temporary();
931 }
932
933 gen->write_end_ternary();
934
935 return result;
936 } break;
937 case GDScriptParser::Node::TYPE_TEST: {
938 const GDScriptParser::TypeTestNode *type_test = static_cast<const GDScriptParser::TypeTestNode *>(p_expression);
939 GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(type_test->get_datatype(), codegen.script));
940
941 GDScriptCodeGenerator::Address operand = _parse_expression(codegen, r_error, type_test->operand);
942 GDScriptDataType test_type = _gdtype_from_datatype(type_test->test_datatype, codegen.script, false);
943 if (r_error) {
944 return GDScriptCodeGenerator::Address();
945 }
946
947 if (test_type.has_type) {
948 gen->write_type_test(result, operand, test_type);
949 } else {
950 gen->write_assign_true(result);
951 }
952
953 if (operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
954 gen->pop_temporary();
955 }
956
957 return result;
958 } break;
959 case GDScriptParser::Node::ASSIGNMENT: {
960 const GDScriptParser::AssignmentNode *assignment = static_cast<const GDScriptParser::AssignmentNode *>(p_expression);
961
962 if (assignment->assignee->type == GDScriptParser::Node::SUBSCRIPT) {
963 // SET (chained) MODE!
964 const GDScriptParser::SubscriptNode *subscript = static_cast<GDScriptParser::SubscriptNode *>(assignment->assignee);
965#ifdef DEBUG_ENABLED
966 if (subscript->is_attribute && subscript->base->type == GDScriptParser::Node::SELF && codegen.script) {
967 HashMap<StringName, GDScript::MemberInfo>::Iterator MI = codegen.script->member_indices.find(subscript->attribute->name);
968 if (MI && MI->value.setter == codegen.function_name) {
969 String n = subscript->attribute->name;
970 _set_error("Must use '" + n + "' instead of 'self." + n + "' in setter.", subscript);
971 r_error = ERR_COMPILATION_FAILED;
972 return GDScriptCodeGenerator::Address();
973 }
974 }
975#endif
976 /* Find chain of sets */
977
978 StringName assign_class_member_property;
979
980 GDScriptCodeGenerator::Address target_member_property;
981 bool is_member_property = false;
982 bool member_property_has_setter = false;
983 bool member_property_is_in_setter = false;
984 bool is_static = false;
985 GDScriptCodeGenerator::Address static_var_class;
986 int static_var_index = 0;
987 GDScriptDataType static_var_data_type;
988 StringName var_name;
989 StringName member_property_setter_function;
990
991 List<const GDScriptParser::SubscriptNode *> chain;
992
993 {
994 // Create get/set chain.
995 const GDScriptParser::SubscriptNode *n = subscript;
996 while (true) {
997 chain.push_back(n);
998 if (n->base->type != GDScriptParser::Node::SUBSCRIPT) {
999 // Check for a property.
1000 if (n->base->type == GDScriptParser::Node::IDENTIFIER) {
1001 GDScriptParser::IdentifierNode *identifier = static_cast<GDScriptParser::IdentifierNode *>(n->base);
1002 var_name = identifier->name;
1003 if (_is_class_member_property(codegen, var_name)) {
1004 assign_class_member_property = var_name;
1005 } else if (!_is_local_or_parameter(codegen, var_name)) {
1006 if (codegen.script->member_indices.has(var_name)) {
1007 is_member_property = true;
1008 is_static = false;
1009 const GDScript::MemberInfo &minfo = codegen.script->member_indices[var_name];
1010 member_property_setter_function = minfo.setter;
1011 member_property_has_setter = member_property_setter_function != StringName();
1012 member_property_is_in_setter = member_property_has_setter && member_property_setter_function == codegen.function_name;
1013 target_member_property.mode = GDScriptCodeGenerator::Address::MEMBER;
1014 target_member_property.address = minfo.index;
1015 target_member_property.type = minfo.data_type;
1016 } else {
1017 // Try static variables.
1018 GDScript *scr = codegen.script;
1019 while (scr) {
1020 if (scr->static_variables_indices.has(var_name)) {
1021 is_member_property = true;
1022 is_static = true;
1023 const GDScript::MemberInfo &minfo = scr->static_variables_indices[var_name];
1024 member_property_setter_function = minfo.setter;
1025 member_property_has_setter = member_property_setter_function != StringName();
1026 member_property_is_in_setter = member_property_has_setter && member_property_setter_function == codegen.function_name;
1027 static_var_class = codegen.add_constant(scr);
1028 static_var_index = minfo.index;
1029 static_var_data_type = minfo.data_type;
1030 break;
1031 }
1032 scr = scr->_base;
1033 }
1034 }
1035 }
1036 }
1037 break;
1038 }
1039 n = static_cast<const GDScriptParser::SubscriptNode *>(n->base);
1040 }
1041 }
1042
1043 /* Chain of gets */
1044
1045 // Get at (potential) root stack pos, so it can be returned.
1046 GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, chain.back()->get()->base);
1047 if (r_error) {
1048 return GDScriptCodeGenerator::Address();
1049 }
1050
1051 GDScriptCodeGenerator::Address prev_base = base;
1052
1053 struct ChainInfo {
1054 bool is_named = false;
1055 GDScriptCodeGenerator::Address base;
1056 GDScriptCodeGenerator::Address key;
1057 StringName name;
1058 };
1059
1060 List<ChainInfo> set_chain;
1061
1062 for (List<const GDScriptParser::SubscriptNode *>::Element *E = chain.back(); E; E = E->prev()) {
1063 if (E == chain.front()) {
1064 // Skip the main subscript, since we'll assign to that.
1065 break;
1066 }
1067 const GDScriptParser::SubscriptNode *subscript_elem = E->get();
1068 GDScriptCodeGenerator::Address value = codegen.add_temporary(_gdtype_from_datatype(subscript_elem->get_datatype(), codegen.script));
1069 GDScriptCodeGenerator::Address key;
1070 StringName name;
1071
1072 if (subscript_elem->is_attribute) {
1073 name = subscript_elem->attribute->name;
1074 gen->write_get_named(value, name, prev_base);
1075 } else {
1076 key = _parse_expression(codegen, r_error, subscript_elem->index);
1077 if (r_error) {
1078 return GDScriptCodeGenerator::Address();
1079 }
1080 gen->write_get(value, key, prev_base);
1081 }
1082
1083 // Store base and key for setting it back later.
1084 set_chain.push_front({ subscript_elem->is_attribute, prev_base, key, name }); // Push to front to invert the list.
1085 prev_base = value;
1086 }
1087
1088 // Get value to assign.
1089 GDScriptCodeGenerator::Address assigned = _parse_expression(codegen, r_error, assignment->assigned_value);
1090 if (r_error) {
1091 return GDScriptCodeGenerator::Address();
1092 }
1093 // Get the key if needed.
1094 GDScriptCodeGenerator::Address key;
1095 StringName name;
1096 if (subscript->is_attribute) {
1097 name = subscript->attribute->name;
1098 } else {
1099 key = _parse_expression(codegen, r_error, subscript->index);
1100 if (r_error) {
1101 return GDScriptCodeGenerator::Address();
1102 }
1103 }
1104
1105 // Perform operator if any.
1106 if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
1107 GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype(), codegen.script));
1108 GDScriptCodeGenerator::Address value = codegen.add_temporary(_gdtype_from_datatype(subscript->get_datatype(), codegen.script));
1109 if (subscript->is_attribute) {
1110 gen->write_get_named(value, name, prev_base);
1111 } else {
1112 gen->write_get(value, key, prev_base);
1113 }
1114 gen->write_binary_operator(op_result, assignment->variant_op, value, assigned);
1115 gen->pop_temporary();
1116 if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1117 gen->pop_temporary();
1118 }
1119 assigned = op_result;
1120 }
1121
1122 // Perform assignment.
1123 if (subscript->is_attribute) {
1124 gen->write_set_named(prev_base, name, assigned);
1125 } else {
1126 gen->write_set(prev_base, key, assigned);
1127 }
1128 if (key.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1129 gen->pop_temporary();
1130 }
1131 if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1132 gen->pop_temporary();
1133 }
1134
1135 assigned = prev_base;
1136
1137 // Set back the values into their bases.
1138 for (const ChainInfo &info : set_chain) {
1139 bool known_type = assigned.type.has_type;
1140 bool is_shared = Variant::is_type_shared(assigned.type.builtin_type);
1141
1142 if (!known_type || !is_shared) {
1143 if (!known_type) {
1144 // Jump shared values since they are already updated in-place.
1145 gen->write_jump_if_shared(assigned);
1146 }
1147 if (!info.is_named) {
1148 gen->write_set(info.base, info.key, assigned);
1149 } else {
1150 gen->write_set_named(info.base, info.name, assigned);
1151 }
1152 if (!known_type) {
1153 gen->write_end_jump_if_shared();
1154 }
1155 }
1156 if (!info.is_named && info.key.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1157 gen->pop_temporary();
1158 }
1159 if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1160 gen->pop_temporary();
1161 }
1162 assigned = info.base;
1163 }
1164
1165 bool known_type = assigned.type.has_type;
1166 bool is_shared = Variant::is_type_shared(assigned.type.builtin_type);
1167
1168 if (!known_type || !is_shared) {
1169 // If this is a class member property, also assign to it.
1170 // This allow things like: position.x += 2.0
1171 if (assign_class_member_property != StringName()) {
1172 if (!known_type) {
1173 gen->write_jump_if_shared(assigned);
1174 }
1175 gen->write_set_member(assigned, assign_class_member_property);
1176 if (!known_type) {
1177 gen->write_end_jump_if_shared();
1178 }
1179 } else if (is_member_property) {
1180 // Same as above but for script members.
1181 if (!known_type) {
1182 gen->write_jump_if_shared(assigned);
1183 }
1184 if (member_property_has_setter && !member_property_is_in_setter) {
1185 Vector<GDScriptCodeGenerator::Address> args;
1186 args.push_back(assigned);
1187 GDScriptCodeGenerator::Address call_base = is_static ? GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS) : GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF);
1188 gen->write_call(GDScriptCodeGenerator::Address(), call_base, member_property_setter_function, args);
1189 } else if (is_static) {
1190 GDScriptCodeGenerator::Address temp = codegen.add_temporary(static_var_data_type);
1191 gen->write_assign(temp, assigned);
1192 gen->write_set_static_variable(temp, static_var_class, static_var_index);
1193 gen->pop_temporary();
1194 } else {
1195 gen->write_assign(target_member_property, assigned);
1196 }
1197 if (!known_type) {
1198 gen->write_end_jump_if_shared();
1199 }
1200 }
1201 }
1202
1203 if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1204 gen->pop_temporary();
1205 }
1206 } else if (assignment->assignee->type == GDScriptParser::Node::IDENTIFIER && _is_class_member_property(codegen, static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name)) {
1207 // Assignment to member property.
1208 GDScriptCodeGenerator::Address assigned_value = _parse_expression(codegen, r_error, assignment->assigned_value);
1209 if (r_error) {
1210 return GDScriptCodeGenerator::Address();
1211 }
1212
1213 GDScriptCodeGenerator::Address to_assign = assigned_value;
1214 bool has_operation = assignment->operation != GDScriptParser::AssignmentNode::OP_NONE;
1215
1216 StringName name = static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name;
1217
1218 if (has_operation) {
1219 GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype(), codegen.script));
1220 GDScriptCodeGenerator::Address member = codegen.add_temporary(_gdtype_from_datatype(assignment->assignee->get_datatype(), codegen.script));
1221 gen->write_get_member(member, name);
1222 gen->write_binary_operator(op_result, assignment->variant_op, member, assigned_value);
1223 gen->pop_temporary(); // Pop member temp.
1224 to_assign = op_result;
1225 }
1226
1227 gen->write_set_member(to_assign, name);
1228
1229 if (to_assign.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1230 gen->pop_temporary(); // Pop the assigned expression or the temp result if it has operation.
1231 }
1232 if (has_operation && assigned_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1233 gen->pop_temporary(); // Pop the assigned expression if not done before.
1234 }
1235 } else {
1236 // Regular assignment.
1237 ERR_FAIL_COND_V_MSG(assignment->assignee->type != GDScriptParser::Node::IDENTIFIER, GDScriptCodeGenerator::Address(), "Expected the assignee to be an identifier here.");
1238 GDScriptCodeGenerator::Address member;
1239 bool is_member = false;
1240 bool has_setter = false;
1241 bool is_in_setter = false;
1242 bool is_static = false;
1243 GDScriptCodeGenerator::Address static_var_class;
1244 int static_var_index = 0;
1245 GDScriptDataType static_var_data_type;
1246 StringName var_name;
1247 StringName setter_function;
1248 var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name;
1249 if (!_is_local_or_parameter(codegen, var_name)) {
1250 if (codegen.script->member_indices.has(var_name)) {
1251 is_member = true;
1252 is_static = false;
1253 GDScript::MemberInfo &minfo = codegen.script->member_indices[var_name];
1254 setter_function = minfo.setter;
1255 has_setter = setter_function != StringName();
1256 is_in_setter = has_setter && setter_function == codegen.function_name;
1257 member.mode = GDScriptCodeGenerator::Address::MEMBER;
1258 member.address = minfo.index;
1259 member.type = minfo.data_type;
1260 } else {
1261 // Try static variables.
1262 GDScript *scr = codegen.script;
1263 while (scr) {
1264 if (scr->static_variables_indices.has(var_name)) {
1265 is_member = true;
1266 is_static = true;
1267 GDScript::MemberInfo &minfo = scr->static_variables_indices[var_name];
1268 setter_function = minfo.setter;
1269 has_setter = setter_function != StringName();
1270 is_in_setter = has_setter && setter_function == codegen.function_name;
1271 static_var_class = codegen.add_constant(scr);
1272 static_var_index = minfo.index;
1273 static_var_data_type = minfo.data_type;
1274 break;
1275 }
1276 scr = scr->_base;
1277 }
1278 }
1279 }
1280
1281 GDScriptCodeGenerator::Address target;
1282 if (is_member) {
1283 target = member; // _parse_expression could call its getter, but we want to know the actual address
1284 } else {
1285 target = _parse_expression(codegen, r_error, assignment->assignee);
1286 if (r_error) {
1287 return GDScriptCodeGenerator::Address();
1288 }
1289 }
1290
1291 GDScriptCodeGenerator::Address assigned_value = _parse_expression(codegen, r_error, assignment->assigned_value);
1292 if (r_error) {
1293 return GDScriptCodeGenerator::Address();
1294 }
1295
1296 GDScriptCodeGenerator::Address to_assign;
1297 bool has_operation = assignment->operation != GDScriptParser::AssignmentNode::OP_NONE;
1298 if (has_operation) {
1299 // Perform operation.
1300 GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype(), codegen.script));
1301 GDScriptCodeGenerator::Address og_value = _parse_expression(codegen, r_error, assignment->assignee);
1302 gen->write_binary_operator(op_result, assignment->variant_op, og_value, assigned_value);
1303 to_assign = op_result;
1304
1305 if (og_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1306 gen->pop_temporary();
1307 }
1308 } else {
1309 to_assign = assigned_value;
1310 }
1311
1312 if (has_setter && !is_in_setter) {
1313 // Call setter.
1314 Vector<GDScriptCodeGenerator::Address> args;
1315 args.push_back(to_assign);
1316 GDScriptCodeGenerator::Address call_base = is_static ? GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS) : GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF);
1317 gen->write_call(GDScriptCodeGenerator::Address(), call_base, setter_function, args);
1318 } else if (is_static) {
1319 GDScriptCodeGenerator::Address temp = codegen.add_temporary(static_var_data_type);
1320 if (assignment->use_conversion_assign) {
1321 gen->write_assign_with_conversion(temp, to_assign);
1322 } else {
1323 gen->write_assign(temp, to_assign);
1324 }
1325 gen->write_set_static_variable(temp, static_var_class, static_var_index);
1326 gen->pop_temporary();
1327 } else {
1328 // Just assign.
1329 if (assignment->use_conversion_assign) {
1330 gen->write_assign_with_conversion(target, to_assign);
1331 } else {
1332 gen->write_assign(target, to_assign);
1333 }
1334 }
1335
1336 if (to_assign.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1337 gen->pop_temporary(); // Pop assigned value or temp operation result.
1338 }
1339 if (has_operation && assigned_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1340 gen->pop_temporary(); // Pop assigned value if not done before.
1341 }
1342 if (target.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1343 gen->pop_temporary(); // Pop the target to assignment.
1344 }
1345 }
1346 return GDScriptCodeGenerator::Address(); // Assignment does not return a value.
1347 } break;
1348 case GDScriptParser::Node::LAMBDA: {
1349 const GDScriptParser::LambdaNode *lambda = static_cast<const GDScriptParser::LambdaNode *>(p_expression);
1350 GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(lambda->get_datatype(), codegen.script));
1351
1352 Vector<GDScriptCodeGenerator::Address> captures;
1353 captures.resize(lambda->captures.size());
1354 for (int i = 0; i < lambda->captures.size(); i++) {
1355 captures.write[i] = _parse_expression(codegen, r_error, lambda->captures[i]);
1356 if (r_error) {
1357 return GDScriptCodeGenerator::Address();
1358 }
1359 }
1360
1361 GDScriptFunction *function = _parse_function(r_error, codegen.script, codegen.class_node, lambda->function, false, true);
1362 if (r_error) {
1363 return GDScriptCodeGenerator::Address();
1364 }
1365
1366 gen->write_lambda(result, function, captures, lambda->use_self);
1367
1368 for (int i = 0; i < captures.size(); i++) {
1369 if (captures[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1370 gen->pop_temporary();
1371 }
1372 }
1373
1374 return result;
1375 } break;
1376 default: {
1377 ERR_FAIL_V_MSG(GDScriptCodeGenerator::Address(), "Bug in bytecode compiler, unexpected node in parse tree while parsing expression."); // Unreachable code.
1378 } break;
1379 }
1380}
1381
1382GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &codegen, Error &r_error, const GDScriptParser::PatternNode *p_pattern, const GDScriptCodeGenerator::Address &p_value_addr, const GDScriptCodeGenerator::Address &p_type_addr, const GDScriptCodeGenerator::Address &p_previous_test, bool p_is_first, bool p_is_nested) {
1383 switch (p_pattern->pattern_type) {
1384 case GDScriptParser::PatternNode::PT_LITERAL: {
1385 if (p_is_nested) {
1386 codegen.generator->write_and_left_operand(p_previous_test);
1387 } else if (!p_is_first) {
1388 codegen.generator->write_or_left_operand(p_previous_test);
1389 }
1390
1391 // Get literal type into constant map.
1392 Variant::Type literal_type = p_pattern->literal->value.get_type();
1393 GDScriptCodeGenerator::Address literal_type_addr = codegen.add_constant(literal_type);
1394
1395 // Equality is always a boolean.
1396 GDScriptDataType equality_type;
1397 equality_type.has_type = true;
1398 equality_type.kind = GDScriptDataType::BUILTIN;
1399 equality_type.builtin_type = Variant::BOOL;
1400
1401 // Check type equality.
1402 GDScriptCodeGenerator::Address type_equality_addr = codegen.add_temporary(equality_type);
1403 codegen.generator->write_binary_operator(type_equality_addr, Variant::OP_EQUAL, p_type_addr, literal_type_addr);
1404
1405 if (literal_type == Variant::STRING) {
1406 GDScriptCodeGenerator::Address type_stringname_addr = codegen.add_constant(Variant::STRING_NAME);
1407
1408 // Check StringName <-> String type equality.
1409 GDScriptCodeGenerator::Address tmp_comp_addr = codegen.add_temporary(equality_type);
1410
1411 codegen.generator->write_binary_operator(tmp_comp_addr, Variant::OP_EQUAL, p_type_addr, type_stringname_addr);
1412 codegen.generator->write_binary_operator(type_equality_addr, Variant::OP_OR, type_equality_addr, tmp_comp_addr);
1413
1414 codegen.generator->pop_temporary(); // Remove tmp_comp_addr from stack.
1415 } else if (literal_type == Variant::STRING_NAME) {
1416 GDScriptCodeGenerator::Address type_string_addr = codegen.add_constant(Variant::STRING);
1417
1418 // Check String <-> StringName type equality.
1419 GDScriptCodeGenerator::Address tmp_comp_addr = codegen.add_temporary(equality_type);
1420
1421 codegen.generator->write_binary_operator(tmp_comp_addr, Variant::OP_EQUAL, p_type_addr, type_string_addr);
1422 codegen.generator->write_binary_operator(type_equality_addr, Variant::OP_OR, type_equality_addr, tmp_comp_addr);
1423
1424 codegen.generator->pop_temporary(); // Remove tmp_comp_addr from stack.
1425 }
1426
1427 codegen.generator->write_and_left_operand(type_equality_addr);
1428
1429 // Get literal.
1430 GDScriptCodeGenerator::Address literal_addr = _parse_expression(codegen, r_error, p_pattern->literal);
1431 if (r_error) {
1432 return GDScriptCodeGenerator::Address();
1433 }
1434
1435 // Check value equality.
1436 GDScriptCodeGenerator::Address equality_addr = codegen.add_temporary(equality_type);
1437 codegen.generator->write_binary_operator(equality_addr, Variant::OP_EQUAL, p_value_addr, literal_addr);
1438 codegen.generator->write_and_right_operand(equality_addr);
1439
1440 // AND both together (reuse temporary location).
1441 codegen.generator->write_end_and(type_equality_addr);
1442
1443 codegen.generator->pop_temporary(); // Remove equality_addr from stack.
1444
1445 if (literal_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1446 codegen.generator->pop_temporary();
1447 }
1448
1449 // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
1450 if (p_is_nested) {
1451 // Use the previous value as target, since we only need one temporary variable.
1452 codegen.generator->write_and_right_operand(type_equality_addr);
1453 codegen.generator->write_end_and(p_previous_test);
1454 } else if (!p_is_first) {
1455 // Use the previous value as target, since we only need one temporary variable.
1456 codegen.generator->write_or_right_operand(type_equality_addr);
1457 codegen.generator->write_end_or(p_previous_test);
1458 } else {
1459 // Just assign this value to the accumulator temporary.
1460 codegen.generator->write_assign(p_previous_test, type_equality_addr);
1461 }
1462 codegen.generator->pop_temporary(); // Remove type_equality_addr.
1463
1464 return p_previous_test;
1465 } break;
1466 case GDScriptParser::PatternNode::PT_EXPRESSION: {
1467 if (p_is_nested) {
1468 codegen.generator->write_and_left_operand(p_previous_test);
1469 } else if (!p_is_first) {
1470 codegen.generator->write_or_left_operand(p_previous_test);
1471 }
1472
1473 GDScriptCodeGenerator::Address type_string_addr = codegen.add_constant(Variant::STRING);
1474 GDScriptCodeGenerator::Address type_stringname_addr = codegen.add_constant(Variant::STRING_NAME);
1475
1476 // Equality is always a boolean.
1477 GDScriptDataType equality_type;
1478 equality_type.has_type = true;
1479 equality_type.kind = GDScriptDataType::BUILTIN;
1480 equality_type.builtin_type = Variant::BOOL;
1481
1482 // Create the result temps first since it's the last to go away.
1483 GDScriptCodeGenerator::Address result_addr = codegen.add_temporary(equality_type);
1484 GDScriptCodeGenerator::Address equality_test_addr = codegen.add_temporary(equality_type);
1485 GDScriptCodeGenerator::Address stringy_comp_addr = codegen.add_temporary(equality_type);
1486 GDScriptCodeGenerator::Address stringy_comp_addr_2 = codegen.add_temporary(equality_type);
1487 GDScriptCodeGenerator::Address expr_type_addr = codegen.add_temporary();
1488
1489 // Evaluate expression.
1490 GDScriptCodeGenerator::Address expr_addr;
1491 expr_addr = _parse_expression(codegen, r_error, p_pattern->expression);
1492 if (r_error) {
1493 return GDScriptCodeGenerator::Address();
1494 }
1495
1496 // Evaluate expression type.
1497 Vector<GDScriptCodeGenerator::Address> typeof_args;
1498 typeof_args.push_back(expr_addr);
1499 codegen.generator->write_call_utility(expr_type_addr, "typeof", typeof_args);
1500
1501 // Check type equality.
1502 codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_type_addr, expr_type_addr);
1503
1504 // Check for String <-> StringName comparison.
1505 codegen.generator->write_binary_operator(stringy_comp_addr, Variant::OP_EQUAL, p_type_addr, type_string_addr);
1506 codegen.generator->write_binary_operator(stringy_comp_addr_2, Variant::OP_EQUAL, expr_type_addr, type_stringname_addr);
1507 codegen.generator->write_binary_operator(stringy_comp_addr, Variant::OP_AND, stringy_comp_addr, stringy_comp_addr_2);
1508 codegen.generator->write_binary_operator(result_addr, Variant::OP_OR, result_addr, stringy_comp_addr);
1509
1510 // Check for StringName <-> String comparison.
1511 codegen.generator->write_binary_operator(stringy_comp_addr, Variant::OP_EQUAL, p_type_addr, type_stringname_addr);
1512 codegen.generator->write_binary_operator(stringy_comp_addr_2, Variant::OP_EQUAL, expr_type_addr, type_string_addr);
1513 codegen.generator->write_binary_operator(stringy_comp_addr, Variant::OP_AND, stringy_comp_addr, stringy_comp_addr_2);
1514 codegen.generator->write_binary_operator(result_addr, Variant::OP_OR, result_addr, stringy_comp_addr);
1515
1516 codegen.generator->pop_temporary(); // Remove expr_type_addr from stack.
1517 codegen.generator->pop_temporary(); // Remove stringy_comp_addr_2 from stack.
1518 codegen.generator->pop_temporary(); // Remove stringy_comp_addr from stack.
1519
1520 codegen.generator->write_and_left_operand(result_addr);
1521
1522 // Check value equality.
1523 codegen.generator->write_binary_operator(equality_test_addr, Variant::OP_EQUAL, p_value_addr, expr_addr);
1524 codegen.generator->write_and_right_operand(equality_test_addr);
1525
1526 // AND both type and value equality.
1527 codegen.generator->write_end_and(result_addr);
1528
1529 // We don't need the expression temporary anymore.
1530 if (expr_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1531 codegen.generator->pop_temporary();
1532 }
1533 codegen.generator->pop_temporary(); // Remove equality_test_addr from stack.
1534
1535 // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
1536 if (p_is_nested) {
1537 // Use the previous value as target, since we only need one temporary variable.
1538 codegen.generator->write_and_right_operand(result_addr);
1539 codegen.generator->write_end_and(p_previous_test);
1540 } else if (!p_is_first) {
1541 // Use the previous value as target, since we only need one temporary variable.
1542 codegen.generator->write_or_right_operand(result_addr);
1543 codegen.generator->write_end_or(p_previous_test);
1544 } else {
1545 // Just assign this value to the accumulator temporary.
1546 codegen.generator->write_assign(p_previous_test, result_addr);
1547 }
1548 codegen.generator->pop_temporary(); // Remove temp result addr.
1549
1550 return p_previous_test;
1551 } break;
1552 case GDScriptParser::PatternNode::PT_ARRAY: {
1553 if (p_is_nested) {
1554 codegen.generator->write_and_left_operand(p_previous_test);
1555 } else if (!p_is_first) {
1556 codegen.generator->write_or_left_operand(p_previous_test);
1557 }
1558 // Get array type into constant map.
1559 GDScriptCodeGenerator::Address array_type_addr = codegen.add_constant((int)Variant::ARRAY);
1560
1561 // Equality is always a boolean.
1562 GDScriptDataType temp_type;
1563 temp_type.has_type = true;
1564 temp_type.kind = GDScriptDataType::BUILTIN;
1565 temp_type.builtin_type = Variant::BOOL;
1566
1567 // Check type equality.
1568 GDScriptCodeGenerator::Address result_addr = codegen.add_temporary(temp_type);
1569 codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_type_addr, array_type_addr);
1570 codegen.generator->write_and_left_operand(result_addr);
1571
1572 // Store pattern length in constant map.
1573 GDScriptCodeGenerator::Address array_length_addr = codegen.add_constant(p_pattern->rest_used ? p_pattern->array.size() - 1 : p_pattern->array.size());
1574
1575 // Get value length.
1576 temp_type.builtin_type = Variant::INT;
1577 GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type);
1578 Vector<GDScriptCodeGenerator::Address> len_args;
1579 len_args.push_back(p_value_addr);
1580 codegen.generator->write_call_gdscript_utility(value_length_addr, "len", len_args);
1581
1582 // Test length compatibility.
1583 temp_type.builtin_type = Variant::BOOL;
1584 GDScriptCodeGenerator::Address length_compat_addr = codegen.add_temporary(temp_type);
1585 codegen.generator->write_binary_operator(length_compat_addr, p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL, value_length_addr, array_length_addr);
1586 codegen.generator->write_and_right_operand(length_compat_addr);
1587
1588 // AND type and length check.
1589 codegen.generator->write_end_and(result_addr);
1590
1591 // Remove length temporaries.
1592 codegen.generator->pop_temporary();
1593 codegen.generator->pop_temporary();
1594
1595 // Create temporaries outside the loop so they can be reused.
1596 GDScriptCodeGenerator::Address element_addr = codegen.add_temporary();
1597 GDScriptCodeGenerator::Address element_type_addr = codegen.add_temporary();
1598
1599 // Evaluate element by element.
1600 for (int i = 0; i < p_pattern->array.size(); i++) {
1601 if (p_pattern->array[i]->pattern_type == GDScriptParser::PatternNode::PT_REST) {
1602 // Don't want to access an extra element of the user array.
1603 break;
1604 }
1605
1606 // Use AND here too, as we don't want to be checking elements if previous test failed (which means this might be an invalid get).
1607 codegen.generator->write_and_left_operand(result_addr);
1608
1609 // Add index to constant map.
1610 GDScriptCodeGenerator::Address index_addr = codegen.add_constant(i);
1611
1612 // Get the actual element from the user-sent array.
1613 codegen.generator->write_get(element_addr, index_addr, p_value_addr);
1614
1615 // Also get type of element.
1616 Vector<GDScriptCodeGenerator::Address> typeof_args;
1617 typeof_args.push_back(element_addr);
1618 codegen.generator->write_call_utility(element_type_addr, "typeof", typeof_args);
1619
1620 // Try the pattern inside the element.
1621 result_addr = _parse_match_pattern(codegen, r_error, p_pattern->array[i], element_addr, element_type_addr, result_addr, false, true);
1622 if (r_error != OK) {
1623 return GDScriptCodeGenerator::Address();
1624 }
1625
1626 codegen.generator->write_and_right_operand(result_addr);
1627 codegen.generator->write_end_and(result_addr);
1628 }
1629 // Remove element temporaries.
1630 codegen.generator->pop_temporary();
1631 codegen.generator->pop_temporary();
1632
1633 // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
1634 if (p_is_nested) {
1635 // Use the previous value as target, since we only need one temporary variable.
1636 codegen.generator->write_and_right_operand(result_addr);
1637 codegen.generator->write_end_and(p_previous_test);
1638 } else if (!p_is_first) {
1639 // Use the previous value as target, since we only need one temporary variable.
1640 codegen.generator->write_or_right_operand(result_addr);
1641 codegen.generator->write_end_or(p_previous_test);
1642 } else {
1643 // Just assign this value to the accumulator temporary.
1644 codegen.generator->write_assign(p_previous_test, result_addr);
1645 }
1646 codegen.generator->pop_temporary(); // Remove temp result addr.
1647
1648 return p_previous_test;
1649 } break;
1650 case GDScriptParser::PatternNode::PT_DICTIONARY: {
1651 if (p_is_nested) {
1652 codegen.generator->write_and_left_operand(p_previous_test);
1653 } else if (!p_is_first) {
1654 codegen.generator->write_or_left_operand(p_previous_test);
1655 }
1656 // Get dictionary type into constant map.
1657 GDScriptCodeGenerator::Address dict_type_addr = codegen.add_constant((int)Variant::DICTIONARY);
1658
1659 // Equality is always a boolean.
1660 GDScriptDataType temp_type;
1661 temp_type.has_type = true;
1662 temp_type.kind = GDScriptDataType::BUILTIN;
1663 temp_type.builtin_type = Variant::BOOL;
1664
1665 // Check type equality.
1666 GDScriptCodeGenerator::Address result_addr = codegen.add_temporary(temp_type);
1667 codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_type_addr, dict_type_addr);
1668 codegen.generator->write_and_left_operand(result_addr);
1669
1670 // Store pattern length in constant map.
1671 GDScriptCodeGenerator::Address dict_length_addr = codegen.add_constant(p_pattern->rest_used ? p_pattern->dictionary.size() - 1 : p_pattern->dictionary.size());
1672
1673 // Get user's dictionary length.
1674 temp_type.builtin_type = Variant::INT;
1675 GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type);
1676 Vector<GDScriptCodeGenerator::Address> func_args;
1677 func_args.push_back(p_value_addr);
1678 codegen.generator->write_call_gdscript_utility(value_length_addr, "len", func_args);
1679
1680 // Test length compatibility.
1681 temp_type.builtin_type = Variant::BOOL;
1682 GDScriptCodeGenerator::Address length_compat_addr = codegen.add_temporary(temp_type);
1683 codegen.generator->write_binary_operator(length_compat_addr, p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL, value_length_addr, dict_length_addr);
1684 codegen.generator->write_and_right_operand(length_compat_addr);
1685
1686 // AND type and length check.
1687 codegen.generator->write_end_and(result_addr);
1688
1689 // Remove length temporaries.
1690 codegen.generator->pop_temporary();
1691 codegen.generator->pop_temporary();
1692
1693 // Create temporaries outside the loop so they can be reused.
1694 GDScriptCodeGenerator::Address element_addr = codegen.add_temporary();
1695 GDScriptCodeGenerator::Address element_type_addr = codegen.add_temporary();
1696
1697 // Evaluate element by element.
1698 for (int i = 0; i < p_pattern->dictionary.size(); i++) {
1699 const GDScriptParser::PatternNode::Pair &element = p_pattern->dictionary[i];
1700 if (element.value_pattern && element.value_pattern->pattern_type == GDScriptParser::PatternNode::PT_REST) {
1701 // Ignore rest pattern.
1702 break;
1703 }
1704
1705 // Use AND here too, as we don't want to be checking elements if previous test failed (which means this might be an invalid get).
1706 codegen.generator->write_and_left_operand(result_addr);
1707
1708 // Get the pattern key.
1709 GDScriptCodeGenerator::Address pattern_key_addr = _parse_expression(codegen, r_error, element.key);
1710 if (r_error) {
1711 return GDScriptCodeGenerator::Address();
1712 }
1713
1714 // Check if pattern key exists in user's dictionary. This will be AND-ed with next result.
1715 func_args.clear();
1716 func_args.push_back(pattern_key_addr);
1717 codegen.generator->write_call(result_addr, p_value_addr, "has", func_args);
1718
1719 if (element.value_pattern != nullptr) {
1720 // Use AND here too, as we don't want to be checking elements if previous test failed (which means this might be an invalid get).
1721 codegen.generator->write_and_left_operand(result_addr);
1722
1723 // Get actual value from user dictionary.
1724 codegen.generator->write_get(element_addr, pattern_key_addr, p_value_addr);
1725
1726 // Also get type of value.
1727 func_args.clear();
1728 func_args.push_back(element_addr);
1729 codegen.generator->write_call_utility(element_type_addr, "typeof", func_args);
1730
1731 // Try the pattern inside the value.
1732 result_addr = _parse_match_pattern(codegen, r_error, element.value_pattern, element_addr, element_type_addr, result_addr, false, true);
1733 if (r_error != OK) {
1734 return GDScriptCodeGenerator::Address();
1735 }
1736 codegen.generator->write_and_right_operand(result_addr);
1737 codegen.generator->write_end_and(result_addr);
1738 }
1739
1740 codegen.generator->write_and_right_operand(result_addr);
1741 codegen.generator->write_end_and(result_addr);
1742
1743 // Remove pattern key temporary.
1744 if (pattern_key_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1745 codegen.generator->pop_temporary();
1746 }
1747 }
1748
1749 // Remove element temporaries.
1750 codegen.generator->pop_temporary();
1751 codegen.generator->pop_temporary();
1752
1753 // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
1754 if (p_is_nested) {
1755 // Use the previous value as target, since we only need one temporary variable.
1756 codegen.generator->write_and_right_operand(result_addr);
1757 codegen.generator->write_end_and(p_previous_test);
1758 } else if (!p_is_first) {
1759 // Use the previous value as target, since we only need one temporary variable.
1760 codegen.generator->write_or_right_operand(result_addr);
1761 codegen.generator->write_end_or(p_previous_test);
1762 } else {
1763 // Just assign this value to the accumulator temporary.
1764 codegen.generator->write_assign(p_previous_test, result_addr);
1765 }
1766 codegen.generator->pop_temporary(); // Remove temp result addr.
1767
1768 return p_previous_test;
1769 } break;
1770 case GDScriptParser::PatternNode::PT_REST:
1771 // Do nothing.
1772 return p_previous_test;
1773 break;
1774 case GDScriptParser::PatternNode::PT_BIND: {
1775 if (p_is_nested) {
1776 codegen.generator->write_and_left_operand(p_previous_test);
1777 } else if (!p_is_first) {
1778 codegen.generator->write_or_left_operand(p_previous_test);
1779 }
1780 // Get the bind address.
1781 GDScriptCodeGenerator::Address bind = codegen.locals[p_pattern->bind->name];
1782
1783 // Assign value to bound variable.
1784 codegen.generator->write_assign(bind, p_value_addr);
1785 }
1786 [[fallthrough]]; // Act like matching anything too.
1787 case GDScriptParser::PatternNode::PT_WILDCARD:
1788 // If this is a fall through we don't want to do this again.
1789 if (p_pattern->pattern_type != GDScriptParser::PatternNode::PT_BIND) {
1790 if (p_is_nested) {
1791 codegen.generator->write_and_left_operand(p_previous_test);
1792 } else if (!p_is_first) {
1793 codegen.generator->write_or_left_operand(p_previous_test);
1794 }
1795 }
1796 // This matches anything so just do the same as `if(true)`.
1797 // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
1798 if (p_is_nested) {
1799 // Use the operator with the `true` constant so it works as always matching.
1800 GDScriptCodeGenerator::Address constant = codegen.add_constant(true);
1801 codegen.generator->write_and_right_operand(constant);
1802 codegen.generator->write_end_and(p_previous_test);
1803 } else if (!p_is_first) {
1804 // Use the operator with the `true` constant so it works as always matching.
1805 GDScriptCodeGenerator::Address constant = codegen.add_constant(true);
1806 codegen.generator->write_or_right_operand(constant);
1807 codegen.generator->write_end_or(p_previous_test);
1808 } else {
1809 // Just assign this value to the accumulator temporary.
1810 codegen.generator->write_assign_true(p_previous_test);
1811 }
1812 return p_previous_test;
1813 }
1814 ERR_FAIL_V_MSG(p_previous_test, "Reaching the end of pattern compilation without matching a pattern.");
1815}
1816
1817List<GDScriptCodeGenerator::Address> GDScriptCompiler::_add_locals_in_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block) {
1818 List<GDScriptCodeGenerator::Address> addresses;
1819 for (int i = 0; i < p_block->locals.size(); i++) {
1820 if (p_block->locals[i].type == GDScriptParser::SuiteNode::Local::PARAMETER || p_block->locals[i].type == GDScriptParser::SuiteNode::Local::FOR_VARIABLE) {
1821 // Parameters are added directly from function and loop variables are declared explicitly.
1822 continue;
1823 }
1824 addresses.push_back(codegen.add_local(p_block->locals[i].name, _gdtype_from_datatype(p_block->locals[i].get_datatype(), codegen.script)));
1825 }
1826 return addresses;
1827}
1828
1829// Avoid keeping in the stack long-lived references to objects, which may prevent RefCounted objects from being freed.
1830void GDScriptCompiler::_clear_addresses(CodeGen &codegen, const List<GDScriptCodeGenerator::Address> &p_addresses) {
1831 for (const List<GDScriptCodeGenerator::Address>::Element *E = p_addresses.front(); E; E = E->next()) {
1832 GDScriptDataType type = E->get().type;
1833 // If not an object and cannot contain an object, no need to clear.
1834 if (type.kind != GDScriptDataType::BUILTIN || type.builtin_type == Variant::ARRAY || type.builtin_type == Variant::DICTIONARY) {
1835 codegen.generator->write_assign_false(E->get());
1836 }
1837 }
1838}
1839
1840Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block, bool p_add_locals, bool p_reset_locals) {
1841 Error err = OK;
1842 GDScriptCodeGenerator *gen = codegen.generator;
1843 List<GDScriptCodeGenerator::Address> block_locals;
1844
1845 gen->clean_temporaries();
1846 codegen.start_block();
1847
1848 if (p_add_locals) {
1849 block_locals = _add_locals_in_block(codegen, p_block);
1850 }
1851
1852 for (int i = 0; i < p_block->statements.size(); i++) {
1853 const GDScriptParser::Node *s = p_block->statements[i];
1854
1855#ifdef DEBUG_ENABLED
1856 // Add a newline before each statement, since the debugger needs those.
1857 gen->write_newline(s->start_line);
1858#endif
1859
1860 switch (s->type) {
1861 case GDScriptParser::Node::MATCH: {
1862 const GDScriptParser::MatchNode *match = static_cast<const GDScriptParser::MatchNode *>(s);
1863
1864 codegen.start_block();
1865
1866 // Evaluate the match expression.
1867 GDScriptCodeGenerator::Address value = codegen.add_local("@match_value", _gdtype_from_datatype(match->test->get_datatype(), codegen.script));
1868 GDScriptCodeGenerator::Address value_expr = _parse_expression(codegen, err, match->test);
1869 if (err) {
1870 return err;
1871 }
1872
1873 // Assign to local.
1874 // TODO: This can be improved by passing the target to parse_expression().
1875 gen->write_assign(value, value_expr);
1876
1877 if (value_expr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1878 codegen.generator->pop_temporary();
1879 }
1880
1881 // Then, let's save the type of the value in the stack too, so we can reuse for later comparisons.
1882 GDScriptDataType typeof_type;
1883 typeof_type.has_type = true;
1884 typeof_type.kind = GDScriptDataType::BUILTIN;
1885 typeof_type.builtin_type = Variant::INT;
1886 GDScriptCodeGenerator::Address type = codegen.add_local("@match_type", typeof_type);
1887
1888 Vector<GDScriptCodeGenerator::Address> typeof_args;
1889 typeof_args.push_back(value);
1890 gen->write_call_utility(type, "typeof", typeof_args);
1891
1892 // Now we can actually start testing.
1893 // For each branch.
1894 for (int j = 0; j < match->branches.size(); j++) {
1895 if (j > 0) {
1896 // Use `else` to not check the next branch after matching.
1897 gen->write_else();
1898 }
1899
1900 const GDScriptParser::MatchBranchNode *branch = match->branches[j];
1901
1902 codegen.start_block(); // Create an extra block around for binds.
1903
1904 // Add locals in block before patterns, so temporaries don't use the stack address for binds.
1905 List<GDScriptCodeGenerator::Address> branch_locals = _add_locals_in_block(codegen, branch->block);
1906
1907#ifdef DEBUG_ENABLED
1908 // Add a newline before each branch, since the debugger needs those.
1909 gen->write_newline(branch->start_line);
1910#endif
1911 // For each pattern in branch.
1912 GDScriptCodeGenerator::Address pattern_result = codegen.add_temporary();
1913 for (int k = 0; k < branch->patterns.size(); k++) {
1914 pattern_result = _parse_match_pattern(codegen, err, branch->patterns[k], value, type, pattern_result, k == 0, false);
1915 if (err != OK) {
1916 return err;
1917 }
1918 }
1919
1920 // Check if pattern did match.
1921 gen->write_if(pattern_result);
1922
1923 // Remove the result from stack.
1924 gen->pop_temporary();
1925
1926 // Parse the branch block.
1927 err = _parse_block(codegen, branch->block, false); // Don't add locals again.
1928 if (err) {
1929 return err;
1930 }
1931
1932 _clear_addresses(codegen, branch_locals);
1933
1934 codegen.end_block(); // Get out of extra block.
1935 }
1936
1937 // End all nested `if`s.
1938 for (int j = 0; j < match->branches.size(); j++) {
1939 gen->write_endif();
1940 }
1941 } break;
1942 case GDScriptParser::Node::IF: {
1943 const GDScriptParser::IfNode *if_n = static_cast<const GDScriptParser::IfNode *>(s);
1944 GDScriptCodeGenerator::Address condition = _parse_expression(codegen, err, if_n->condition);
1945 if (err) {
1946 return err;
1947 }
1948
1949 gen->write_if(condition);
1950
1951 if (condition.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1952 codegen.generator->pop_temporary();
1953 }
1954
1955 err = _parse_block(codegen, if_n->true_block);
1956 if (err) {
1957 return err;
1958 }
1959
1960 if (if_n->false_block) {
1961 gen->write_else();
1962
1963 err = _parse_block(codegen, if_n->false_block);
1964 if (err) {
1965 return err;
1966 }
1967 }
1968
1969 gen->write_endif();
1970 } break;
1971 case GDScriptParser::Node::FOR: {
1972 const GDScriptParser::ForNode *for_n = static_cast<const GDScriptParser::ForNode *>(s);
1973
1974 codegen.start_block();
1975 GDScriptCodeGenerator::Address iterator = codegen.add_local(for_n->variable->name, _gdtype_from_datatype(for_n->variable->get_datatype(), codegen.script));
1976
1977 gen->start_for(iterator.type, _gdtype_from_datatype(for_n->list->get_datatype(), codegen.script));
1978
1979 GDScriptCodeGenerator::Address list = _parse_expression(codegen, err, for_n->list);
1980 if (err) {
1981 return err;
1982 }
1983
1984 gen->write_for_assignment(list);
1985
1986 if (list.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
1987 codegen.generator->pop_temporary();
1988 }
1989
1990 gen->write_for(iterator, for_n->use_conversion_assign);
1991
1992 err = _parse_block(codegen, for_n->loop);
1993 if (err) {
1994 return err;
1995 }
1996
1997 gen->write_endfor();
1998
1999 codegen.end_block();
2000 } break;
2001 case GDScriptParser::Node::WHILE: {
2002 const GDScriptParser::WhileNode *while_n = static_cast<const GDScriptParser::WhileNode *>(s);
2003
2004 gen->start_while_condition();
2005
2006 GDScriptCodeGenerator::Address condition = _parse_expression(codegen, err, while_n->condition);
2007 if (err) {
2008 return err;
2009 }
2010
2011 gen->write_while(condition);
2012
2013 if (condition.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
2014 codegen.generator->pop_temporary();
2015 }
2016
2017 err = _parse_block(codegen, while_n->loop);
2018 if (err) {
2019 return err;
2020 }
2021
2022 gen->write_endwhile();
2023 } break;
2024 case GDScriptParser::Node::BREAK: {
2025 gen->write_break();
2026 } break;
2027 case GDScriptParser::Node::CONTINUE: {
2028 gen->write_continue();
2029 } break;
2030 case GDScriptParser::Node::RETURN: {
2031 const GDScriptParser::ReturnNode *return_n = static_cast<const GDScriptParser::ReturnNode *>(s);
2032
2033 GDScriptCodeGenerator::Address return_value;
2034
2035 if (return_n->return_value != nullptr) {
2036 return_value = _parse_expression(codegen, err, return_n->return_value);
2037 if (err) {
2038 return err;
2039 }
2040 }
2041
2042 if (return_n->void_return) {
2043 // Always return "null", even if the expression is a call to a void function.
2044 gen->write_return(codegen.add_constant(Variant()));
2045 } else {
2046 gen->write_return(return_value);
2047 }
2048 if (return_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
2049 codegen.generator->pop_temporary();
2050 }
2051 } break;
2052 case GDScriptParser::Node::ASSERT: {
2053#ifdef DEBUG_ENABLED
2054 const GDScriptParser::AssertNode *as = static_cast<const GDScriptParser::AssertNode *>(s);
2055
2056 GDScriptCodeGenerator::Address condition = _parse_expression(codegen, err, as->condition);
2057 if (err) {
2058 return err;
2059 }
2060
2061 GDScriptCodeGenerator::Address message;
2062
2063 if (as->message) {
2064 message = _parse_expression(codegen, err, as->message);
2065 if (err) {
2066 return err;
2067 }
2068 }
2069 gen->write_assert(condition, message);
2070
2071 if (condition.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
2072 codegen.generator->pop_temporary();
2073 }
2074 if (message.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
2075 codegen.generator->pop_temporary();
2076 }
2077#endif
2078 } break;
2079 case GDScriptParser::Node::BREAKPOINT: {
2080#ifdef DEBUG_ENABLED
2081 gen->write_breakpoint();
2082#endif
2083 } break;
2084 case GDScriptParser::Node::VARIABLE: {
2085 const GDScriptParser::VariableNode *lv = static_cast<const GDScriptParser::VariableNode *>(s);
2086 // Should be already in stack when the block began.
2087 GDScriptCodeGenerator::Address local = codegen.locals[lv->identifier->name];
2088 GDScriptDataType local_type = _gdtype_from_datatype(lv->get_datatype(), codegen.script);
2089
2090 bool initialized = false;
2091 if (lv->initializer != nullptr) {
2092 GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, err, lv->initializer);
2093 if (err) {
2094 return err;
2095 }
2096 if (lv->use_conversion_assign) {
2097 gen->write_assign_with_conversion(local, src_address);
2098 } else {
2099 gen->write_assign(local, src_address);
2100 }
2101 if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
2102 codegen.generator->pop_temporary();
2103 }
2104 initialized = true;
2105 } else if (local_type.has_type) {
2106 // Initialize with default for type.
2107 if (local_type.has_container_element_type()) {
2108 codegen.generator->write_construct_typed_array(local, local_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>());
2109 initialized = true;
2110 } else if (local_type.kind == GDScriptDataType::BUILTIN) {
2111 codegen.generator->write_construct(local, local_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
2112 initialized = true;
2113 }
2114 // The `else` branch is for objects, in such case we leave it as `null`.
2115 }
2116
2117 // Assigns a null for the unassigned variables in loops.
2118 if (!initialized && p_block->is_in_loop) {
2119 codegen.generator->write_construct(local, Variant::NIL, Vector<GDScriptCodeGenerator::Address>());
2120 }
2121 } break;
2122 case GDScriptParser::Node::CONSTANT: {
2123 // Local constants.
2124 const GDScriptParser::ConstantNode *lc = static_cast<const GDScriptParser::ConstantNode *>(s);
2125 if (!lc->initializer->is_constant) {
2126 _set_error("Local constant must have a constant value as initializer.", lc->initializer);
2127 return ERR_PARSE_ERROR;
2128 }
2129
2130 codegen.add_local_constant(lc->identifier->name, lc->initializer->reduced_value);
2131 } break;
2132 case GDScriptParser::Node::PASS:
2133 // Nothing to do.
2134 break;
2135 default: {
2136 // Expression.
2137 if (s->is_expression()) {
2138 GDScriptCodeGenerator::Address expr = _parse_expression(codegen, err, static_cast<const GDScriptParser::ExpressionNode *>(s), true);
2139 if (err) {
2140 return err;
2141 }
2142 if (expr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
2143 codegen.generator->pop_temporary();
2144 }
2145 } else {
2146 ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Bug in bytecode compiler, unexpected node in parse tree while parsing statement."); // Unreachable code.
2147 }
2148 } break;
2149 }
2150
2151 gen->clean_temporaries();
2152 }
2153
2154 if (p_add_locals && p_reset_locals) {
2155 _clear_addresses(codegen, block_locals);
2156 }
2157
2158 codegen.end_block();
2159 return OK;
2160}
2161
2162GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready, bool p_for_lambda) {
2163 r_error = OK;
2164 CodeGen codegen;
2165 codegen.generator = memnew(GDScriptByteCodeGenerator);
2166
2167 codegen.class_node = p_class;
2168 codegen.script = p_script;
2169 codegen.function_node = p_func;
2170
2171 StringName func_name;
2172 bool is_static = false;
2173 Variant rpc_config;
2174 GDScriptDataType return_type;
2175 return_type.has_type = true;
2176 return_type.kind = GDScriptDataType::BUILTIN;
2177 return_type.builtin_type = Variant::NIL;
2178
2179 if (p_func) {
2180 if (p_func->identifier) {
2181 func_name = p_func->identifier->name;
2182 } else {
2183 func_name = "<anonymous lambda>";
2184 }
2185 is_static = p_func->is_static;
2186 rpc_config = p_func->rpc_config;
2187 return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script);
2188 } else {
2189 if (p_for_ready) {
2190 func_name = "_ready";
2191 } else {
2192 func_name = "@implicit_new";
2193 }
2194 }
2195
2196 MethodInfo method_info;
2197
2198 codegen.function_name = func_name;
2199 method_info.name = func_name;
2200 codegen.is_static = is_static;
2201 if (is_static) {
2202 method_info.flags |= METHOD_FLAG_STATIC;
2203 }
2204 codegen.generator->write_start(p_script, func_name, is_static, rpc_config, return_type);
2205
2206 int optional_parameters = 0;
2207
2208 if (p_func) {
2209 for (int i = 0; i < p_func->parameters.size(); i++) {
2210 const GDScriptParser::ParameterNode *parameter = p_func->parameters[i];
2211 GDScriptDataType par_type = _gdtype_from_datatype(parameter->get_datatype(), p_script);
2212 uint32_t par_addr = codegen.generator->add_parameter(parameter->identifier->name, parameter->initializer != nullptr, par_type);
2213 codegen.parameters[parameter->identifier->name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::FUNCTION_PARAMETER, par_addr, par_type);
2214
2215 method_info.arguments.push_back(parameter->get_datatype().to_property_info(parameter->identifier->name));
2216
2217 if (parameter->initializer != nullptr) {
2218 optional_parameters++;
2219 }
2220 }
2221
2222 method_info.default_arguments.append_array(p_func->default_arg_values);
2223 }
2224
2225 // Parse initializer if applies.
2226 bool is_implicit_initializer = !p_for_ready && !p_func && !p_for_lambda;
2227 bool is_initializer = p_func && !p_for_lambda && p_func->identifier->name == GDScriptLanguage::get_singleton()->strings._init;
2228 bool is_implicit_ready = !p_func && p_for_ready;
2229
2230 if (!p_for_lambda && is_implicit_initializer) {
2231 // Initialize the default values for typed variables before anything.
2232 // This avoids crashes if they are accessed with validated calls before being properly initialized.
2233 // It may happen with out-of-order access or with `@onready` variables.
2234 for (const GDScriptParser::ClassNode::Member &member : p_class->members) {
2235 if (member.type != GDScriptParser::ClassNode::Member::VARIABLE) {
2236 continue;
2237 }
2238
2239 const GDScriptParser::VariableNode *field = member.variable;
2240 if (field->is_static) {
2241 continue;
2242 }
2243
2244 GDScriptDataType field_type = _gdtype_from_datatype(field->get_datatype(), codegen.script);
2245 if (field_type.has_type) {
2246 codegen.generator->write_newline(field->start_line);
2247
2248 GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, field_type);
2249
2250 if (field_type.has_container_element_type()) {
2251 codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>());
2252 } else if (field_type.kind == GDScriptDataType::BUILTIN) {
2253 codegen.generator->write_construct(dst_address, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
2254 }
2255 // The `else` branch is for objects, in such case we leave it as `null`.
2256 }
2257 }
2258 }
2259
2260 if (!p_for_lambda && (is_implicit_initializer || is_implicit_ready)) {
2261 // Initialize class fields.
2262 for (int i = 0; i < p_class->members.size(); i++) {
2263 if (p_class->members[i].type != GDScriptParser::ClassNode::Member::VARIABLE) {
2264 continue;
2265 }
2266 const GDScriptParser::VariableNode *field = p_class->members[i].variable;
2267 if (field->is_static) {
2268 continue;
2269 }
2270
2271 if (field->onready != is_implicit_ready) {
2272 // Only initialize in @implicit_ready.
2273 continue;
2274 }
2275
2276 if (field->initializer) {
2277 // Emit proper line change.
2278 codegen.generator->write_newline(field->initializer->start_line);
2279
2280 GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, r_error, field->initializer, false, true);
2281 if (r_error) {
2282 memdelete(codegen.generator);
2283 return nullptr;
2284 }
2285
2286 GDScriptDataType field_type = _gdtype_from_datatype(field->get_datatype(), codegen.script);
2287 GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, field_type);
2288
2289 if (field->use_conversion_assign) {
2290 codegen.generator->write_assign_with_conversion(dst_address, src_address);
2291 } else {
2292 codegen.generator->write_assign(dst_address, src_address);
2293 }
2294 if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
2295 codegen.generator->pop_temporary();
2296 }
2297 }
2298 }
2299 }
2300
2301 // Parse default argument code if applies.
2302 if (p_func) {
2303 if (optional_parameters > 0) {
2304 codegen.generator->start_parameters();
2305 for (int i = p_func->parameters.size() - optional_parameters; i < p_func->parameters.size(); i++) {
2306 const GDScriptParser::ParameterNode *parameter = p_func->parameters[i];
2307 GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->initializer);
2308 if (r_error) {
2309 memdelete(codegen.generator);
2310 return nullptr;
2311 }
2312 GDScriptCodeGenerator::Address dst_addr = codegen.parameters[parameter->identifier->name];
2313 codegen.generator->write_assign_default_parameter(dst_addr, src_addr, parameter->use_conversion_assign);
2314 if (src_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
2315 codegen.generator->pop_temporary();
2316 }
2317 }
2318 codegen.generator->end_parameters();
2319 }
2320
2321 // No need to reset locals at the end of the function, the stack will be cleared anyway.
2322 r_error = _parse_block(codegen, p_func->body, true, false);
2323 if (r_error) {
2324 memdelete(codegen.generator);
2325 return nullptr;
2326 }
2327 }
2328
2329#ifdef DEBUG_ENABLED
2330 if (EngineDebugger::is_active()) {
2331 String signature;
2332 // Path.
2333 if (!p_script->get_script_path().is_empty()) {
2334 signature += p_script->get_script_path();
2335 }
2336 // Location.
2337 if (p_func) {
2338 signature += "::" + itos(p_func->body->start_line);
2339 } else {
2340 signature += "::0";
2341 }
2342
2343 // Function and class.
2344
2345 if (p_class->identifier) {
2346 signature += "::" + String(p_class->identifier->name) + "." + String(func_name);
2347 } else {
2348 signature += "::" + String(func_name);
2349 }
2350
2351 if (p_for_lambda) {
2352 signature += "(lambda)";
2353 }
2354
2355 codegen.generator->set_signature(signature);
2356 }
2357#endif
2358
2359 if (p_func) {
2360 codegen.generator->set_initial_line(p_func->start_line);
2361 } else {
2362 codegen.generator->set_initial_line(0);
2363 }
2364
2365 GDScriptFunction *gd_function = codegen.generator->write_end();
2366
2367 if (is_initializer) {
2368 p_script->initializer = gd_function;
2369 } else if (is_implicit_initializer) {
2370 p_script->implicit_initializer = gd_function;
2371 } else if (is_implicit_ready) {
2372 p_script->implicit_ready = gd_function;
2373 }
2374
2375 if (p_func) {
2376 // If no `return` statement, then return type is `void`, not `Variant`.
2377 if (p_func->body->has_return) {
2378 gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script);
2379 method_info.return_val = p_func->get_datatype().to_property_info(String());
2380 } else {
2381 gd_function->return_type = GDScriptDataType();
2382 gd_function->return_type.has_type = true;
2383 gd_function->return_type.kind = GDScriptDataType::BUILTIN;
2384 gd_function->return_type.builtin_type = Variant::NIL;
2385 }
2386 }
2387
2388 gd_function->method_info = method_info;
2389
2390 if (!is_implicit_initializer && !is_implicit_ready && !p_for_lambda) {
2391 p_script->member_functions[func_name] = gd_function;
2392 }
2393
2394 memdelete(codegen.generator);
2395
2396 return gd_function;
2397}
2398
2399GDScriptFunction *GDScriptCompiler::_make_static_initializer(Error &r_error, GDScript *p_script, const GDScriptParser::ClassNode *p_class) {
2400 r_error = OK;
2401 CodeGen codegen;
2402 codegen.generator = memnew(GDScriptByteCodeGenerator);
2403
2404 codegen.class_node = p_class;
2405 codegen.script = p_script;
2406
2407 StringName func_name = SNAME("@static_initializer");
2408 bool is_static = true;
2409 Variant rpc_config;
2410 GDScriptDataType return_type;
2411 return_type.has_type = true;
2412 return_type.kind = GDScriptDataType::BUILTIN;
2413 return_type.builtin_type = Variant::NIL;
2414
2415 codegen.function_name = func_name;
2416 codegen.is_static = is_static;
2417 codegen.generator->write_start(p_script, func_name, is_static, rpc_config, return_type);
2418
2419 // The static initializer is always called on the same class where the static variables are defined,
2420 // so the CLASS address (current class) can be used instead of `codegen.add_constant(p_script)`.
2421 GDScriptCodeGenerator::Address class_addr(GDScriptCodeGenerator::Address::CLASS);
2422
2423 // Initialize the default values for typed variables before anything.
2424 // This avoids crashes if they are accessed with validated calls before being properly initialized.
2425 // It may happen with out-of-order access or with `@onready` variables.
2426 for (const GDScriptParser::ClassNode::Member &member : p_class->members) {
2427 if (member.type != GDScriptParser::ClassNode::Member::VARIABLE) {
2428 continue;
2429 }
2430
2431 const GDScriptParser::VariableNode *field = member.variable;
2432 if (!field->is_static) {
2433 continue;
2434 }
2435
2436 GDScriptDataType field_type = _gdtype_from_datatype(field->get_datatype(), codegen.script);
2437 if (field_type.has_type) {
2438 codegen.generator->write_newline(field->start_line);
2439
2440 if (field_type.has_container_element_type()) {
2441 GDScriptCodeGenerator::Address temp = codegen.add_temporary(field_type);
2442 codegen.generator->write_construct_typed_array(temp, field_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>());
2443 codegen.generator->write_set_static_variable(temp, class_addr, p_script->static_variables_indices[field->identifier->name].index);
2444 codegen.generator->pop_temporary();
2445 } else if (field_type.kind == GDScriptDataType::BUILTIN) {
2446 GDScriptCodeGenerator::Address temp = codegen.add_temporary(field_type);
2447 codegen.generator->write_construct(temp, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
2448 codegen.generator->write_set_static_variable(temp, class_addr, p_script->static_variables_indices[field->identifier->name].index);
2449 codegen.generator->pop_temporary();
2450 }
2451 // The `else` branch is for objects, in such case we leave it as `null`.
2452 }
2453 }
2454
2455 for (int i = 0; i < p_class->members.size(); i++) {
2456 // Initialize static fields.
2457 if (p_class->members[i].type != GDScriptParser::ClassNode::Member::VARIABLE) {
2458 continue;
2459 }
2460 const GDScriptParser::VariableNode *field = p_class->members[i].variable;
2461 if (!field->is_static) {
2462 continue;
2463 }
2464
2465 if (field->initializer) {
2466 // Emit proper line change.
2467 codegen.generator->write_newline(field->initializer->start_line);
2468
2469 GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, r_error, field->initializer, false, true);
2470 if (r_error) {
2471 memdelete(codegen.generator);
2472 return nullptr;
2473 }
2474
2475 GDScriptDataType field_type = _gdtype_from_datatype(field->get_datatype(), codegen.script);
2476 GDScriptCodeGenerator::Address temp = codegen.add_temporary(field_type);
2477
2478 if (field->use_conversion_assign) {
2479 codegen.generator->write_assign_with_conversion(temp, src_address);
2480 } else {
2481 codegen.generator->write_assign(temp, src_address);
2482 }
2483 if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
2484 codegen.generator->pop_temporary();
2485 }
2486
2487 codegen.generator->write_set_static_variable(temp, class_addr, p_script->static_variables_indices[field->identifier->name].index);
2488 codegen.generator->pop_temporary();
2489 }
2490 }
2491
2492 if (p_script->has_method(GDScriptLanguage::get_singleton()->strings._static_init)) {
2493 codegen.generator->write_newline(p_class->start_line);
2494 codegen.generator->write_call(GDScriptCodeGenerator::Address(), class_addr, GDScriptLanguage::get_singleton()->strings._static_init, Vector<GDScriptCodeGenerator::Address>());
2495 }
2496
2497#ifdef DEBUG_ENABLED
2498 if (EngineDebugger::is_active()) {
2499 String signature;
2500 // Path.
2501 if (!p_script->get_script_path().is_empty()) {
2502 signature += p_script->get_script_path();
2503 }
2504 // Location.
2505 signature += "::0";
2506
2507 // Function and class.
2508
2509 if (p_class->identifier) {
2510 signature += "::" + String(p_class->identifier->name) + "." + String(func_name);
2511 } else {
2512 signature += "::" + String(func_name);
2513 }
2514
2515 codegen.generator->set_signature(signature);
2516 }
2517#endif
2518
2519 codegen.generator->set_initial_line(p_class->start_line);
2520
2521 GDScriptFunction *gd_function = codegen.generator->write_end();
2522
2523 memdelete(codegen.generator);
2524
2525 return gd_function;
2526}
2527
2528Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter) {
2529 Error err = OK;
2530
2531 GDScriptParser::FunctionNode *function;
2532
2533 if (p_is_setter) {
2534 function = p_variable->setter;
2535 } else {
2536 function = p_variable->getter;
2537 }
2538
2539 _parse_function(err, p_script, p_class, function);
2540
2541 return err;
2542}
2543
2544// Prepares given script, and inner class scripts, for compilation. It populates class members and initializes method
2545// RPC info for its base classes first, then for itself, then for inner classes.
2546// Warning: this function cannot initiate compilation of other classes, or it will result in cyclic dependency issues.
2547Error GDScriptCompiler::_prepare_compilation(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
2548 if (parsed_classes.has(p_script)) {
2549 return OK;
2550 }
2551
2552 if (parsing_classes.has(p_script)) {
2553 String class_name = p_class->identifier ? String(p_class->identifier->name) : p_class->fqcn;
2554 _set_error(vformat(R"(Cyclic class reference for "%s".)", class_name), p_class);
2555 return ERR_PARSE_ERROR;
2556 }
2557
2558 parsing_classes.insert(p_script);
2559
2560 p_script->clearing = true;
2561
2562 p_script->native = Ref<GDScriptNativeClass>();
2563 p_script->base = Ref<GDScript>();
2564 p_script->_base = nullptr;
2565 p_script->members.clear();
2566
2567 // This makes possible to clear script constants and member_functions without heap-use-after-free errors.
2568 HashMap<StringName, Variant> constants;
2569 for (const KeyValue<StringName, Variant> &E : p_script->constants) {
2570 constants.insert(E.key, E.value);
2571 }
2572 p_script->constants.clear();
2573 constants.clear();
2574 HashMap<StringName, GDScriptFunction *> member_functions;
2575 for (const KeyValue<StringName, GDScriptFunction *> &E : p_script->member_functions) {
2576 member_functions.insert(E.key, E.value);
2577 }
2578 p_script->member_functions.clear();
2579 for (const KeyValue<StringName, GDScriptFunction *> &E : member_functions) {
2580 memdelete(E.value);
2581 }
2582 member_functions.clear();
2583
2584 p_script->static_variables.clear();
2585
2586 if (p_script->implicit_initializer) {
2587 memdelete(p_script->implicit_initializer);
2588 }
2589 if (p_script->implicit_ready) {
2590 memdelete(p_script->implicit_ready);
2591 }
2592 if (p_script->static_initializer) {
2593 memdelete(p_script->static_initializer);
2594 }
2595
2596 p_script->member_functions.clear();
2597 p_script->member_indices.clear();
2598 p_script->static_variables_indices.clear();
2599 p_script->static_variables.clear();
2600 p_script->_signals.clear();
2601 p_script->initializer = nullptr;
2602 p_script->implicit_initializer = nullptr;
2603 p_script->implicit_ready = nullptr;
2604 p_script->static_initializer = nullptr;
2605 p_script->rpc_config.clear();
2606
2607 p_script->clearing = false;
2608
2609 p_script->tool = parser->is_tool();
2610
2611 if (p_script->local_name != StringName()) {
2612 if (ClassDB::class_exists(p_script->local_name) && ClassDB::is_class_exposed(p_script->local_name)) {
2613 _set_error(vformat(R"(The class "%s" shadows a native class)", p_script->local_name), p_class);
2614 return ERR_ALREADY_EXISTS;
2615 }
2616 }
2617
2618 GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type, p_script, false);
2619
2620 int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[base_type.native_type];
2621 p_script->native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx];
2622 ERR_FAIL_COND_V(p_script->native.is_null(), ERR_BUG);
2623
2624 // Inheritance
2625 switch (base_type.kind) {
2626 case GDScriptDataType::NATIVE:
2627 // Nothing more to do.
2628 break;
2629 case GDScriptDataType::GDSCRIPT: {
2630 Ref<GDScript> base = Ref<GDScript>(base_type.script_type);
2631 if (base.is_null()) {
2632 return ERR_COMPILATION_FAILED;
2633 }
2634
2635 if (main_script->has_class(base.ptr())) {
2636 Error err = _prepare_compilation(base.ptr(), p_class->base_type.class_type, p_keep_state);
2637 if (err) {
2638 return err;
2639 }
2640 } else if (!base->is_valid()) {
2641 Error err = OK;
2642 Ref<GDScript> base_root = GDScriptCache::get_shallow_script(base->path, err, p_script->path);
2643 if (err) {
2644 _set_error(vformat(R"(Could not parse base class "%s" from "%s": %s)", base->fully_qualified_name, base->path, error_names[err]), nullptr);
2645 return err;
2646 }
2647 if (base_root.is_valid()) {
2648 base = Ref<GDScript>(base_root->find_class(base->fully_qualified_name));
2649 }
2650 if (base.is_null()) {
2651 _set_error(vformat(R"(Could not find class "%s" in "%s".)", base->fully_qualified_name, base->path), nullptr);
2652 return ERR_COMPILATION_FAILED;
2653 }
2654
2655 err = _prepare_compilation(base.ptr(), p_class->base_type.class_type, p_keep_state);
2656 if (err) {
2657 _set_error(vformat(R"(Could not populate class members of base class "%s" in "%s".)", base->fully_qualified_name, base->path), nullptr);
2658 return err;
2659 }
2660 }
2661
2662 p_script->base = base;
2663 p_script->_base = base.ptr();
2664 p_script->member_indices = base->member_indices;
2665 } break;
2666 default: {
2667 _set_error("Parser bug: invalid inheritance.", nullptr);
2668 return ERR_BUG;
2669 } break;
2670 }
2671
2672 // Duplicate RPC information from base GDScript
2673 // Base script isn't valid because it should not have been compiled yet, but the reference contains relevant info.
2674 if (base_type.kind == GDScriptDataType::GDSCRIPT && p_script->base.is_valid()) {
2675 p_script->rpc_config = p_script->base->rpc_config.duplicate();
2676 }
2677
2678 for (int i = 0; i < p_class->members.size(); i++) {
2679 const GDScriptParser::ClassNode::Member &member = p_class->members[i];
2680 switch (member.type) {
2681 case GDScriptParser::ClassNode::Member::VARIABLE: {
2682 const GDScriptParser::VariableNode *variable = member.variable;
2683 StringName name = variable->identifier->name;
2684
2685 GDScript::MemberInfo minfo;
2686 switch (variable->property) {
2687 case GDScriptParser::VariableNode::PROP_NONE:
2688 break; // Nothing to do.
2689 case GDScriptParser::VariableNode::PROP_SETGET:
2690 if (variable->setter_pointer != nullptr) {
2691 minfo.setter = variable->setter_pointer->name;
2692 }
2693 if (variable->getter_pointer != nullptr) {
2694 minfo.getter = variable->getter_pointer->name;
2695 }
2696 break;
2697 case GDScriptParser::VariableNode::PROP_INLINE:
2698 if (variable->setter != nullptr) {
2699 minfo.setter = "@" + variable->identifier->name + "_setter";
2700 }
2701 if (variable->getter != nullptr) {
2702 minfo.getter = "@" + variable->identifier->name + "_getter";
2703 }
2704 break;
2705 }
2706 minfo.data_type = _gdtype_from_datatype(variable->get_datatype(), p_script);
2707
2708 PropertyInfo prop_info = variable->get_datatype().to_property_info(name);
2709 PropertyInfo export_info = variable->export_info;
2710
2711 if (variable->exported) {
2712 if (!minfo.data_type.has_type) {
2713 prop_info.type = export_info.type;
2714 prop_info.class_name = export_info.class_name;
2715 }
2716 prop_info.hint = export_info.hint;
2717 prop_info.hint_string = export_info.hint_string;
2718 prop_info.usage = export_info.usage;
2719 }
2720 prop_info.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
2721 minfo.property_info = prop_info;
2722
2723 if (variable->is_static) {
2724 minfo.index = p_script->static_variables_indices.size();
2725 p_script->static_variables_indices[name] = minfo;
2726 } else {
2727 minfo.index = p_script->member_indices.size();
2728 p_script->member_indices[name] = minfo;
2729 p_script->members.insert(name);
2730 }
2731
2732#ifdef TOOLS_ENABLED
2733 if (variable->initializer != nullptr && variable->initializer->is_constant) {
2734 p_script->member_default_values[name] = variable->initializer->reduced_value;
2735 GDScriptCompiler::convert_to_initializer_type(p_script->member_default_values[name], variable);
2736 } else {
2737 p_script->member_default_values.erase(name);
2738 }
2739#endif
2740 } break;
2741
2742 case GDScriptParser::ClassNode::Member::CONSTANT: {
2743 const GDScriptParser::ConstantNode *constant = member.constant;
2744 StringName name = constant->identifier->name;
2745
2746 p_script->constants.insert(name, constant->initializer->reduced_value);
2747 } break;
2748
2749 case GDScriptParser::ClassNode::Member::ENUM_VALUE: {
2750 const GDScriptParser::EnumNode::Value &enum_value = member.enum_value;
2751 StringName name = enum_value.identifier->name;
2752
2753 p_script->constants.insert(name, enum_value.value);
2754 } break;
2755
2756 case GDScriptParser::ClassNode::Member::SIGNAL: {
2757 const GDScriptParser::SignalNode *signal = member.signal;
2758 StringName name = signal->identifier->name;
2759
2760 p_script->_signals[name] = signal->method_info;
2761 } break;
2762
2763 case GDScriptParser::ClassNode::Member::ENUM: {
2764 const GDScriptParser::EnumNode *enum_n = member.m_enum;
2765 StringName name = enum_n->identifier->name;
2766
2767 p_script->constants.insert(name, enum_n->dictionary);
2768 } break;
2769
2770 case GDScriptParser::ClassNode::Member::GROUP: {
2771 const GDScriptParser::AnnotationNode *annotation = member.annotation;
2772 // Avoid name conflict. See GH-78252.
2773 StringName name = vformat("@group_%d_%s", p_script->members.size(), annotation->export_info.name);
2774
2775 // This is not a normal member, but we need this to keep indices in order.
2776 GDScript::MemberInfo minfo;
2777 minfo.index = p_script->member_indices.size();
2778
2779 PropertyInfo prop_info;
2780 prop_info.name = annotation->export_info.name;
2781 prop_info.usage = annotation->export_info.usage;
2782 prop_info.hint_string = annotation->export_info.hint_string;
2783 minfo.property_info = prop_info;
2784
2785 p_script->member_indices[name] = minfo;
2786 p_script->members.insert(Variant());
2787 } break;
2788
2789 case GDScriptParser::ClassNode::Member::FUNCTION: {
2790 const GDScriptParser::FunctionNode *function_n = member.function;
2791
2792 Variant config = function_n->rpc_config;
2793 if (config.get_type() != Variant::NIL) {
2794 p_script->rpc_config[function_n->identifier->name] = config;
2795 }
2796 } break;
2797 default:
2798 break; // Nothing to do here.
2799 }
2800 }
2801
2802 p_script->static_variables.resize(p_script->static_variables_indices.size());
2803
2804 parsed_classes.insert(p_script);
2805 parsing_classes.erase(p_script);
2806
2807 // Populate inner classes.
2808 for (int i = 0; i < p_class->members.size(); i++) {
2809 const GDScriptParser::ClassNode::Member &member = p_class->members[i];
2810 if (member.type != member.CLASS) {
2811 continue;
2812 }
2813 const GDScriptParser::ClassNode *inner_class = member.m_class;
2814 StringName name = inner_class->identifier->name;
2815 Ref<GDScript> &subclass = p_script->subclasses[name];
2816 GDScript *subclass_ptr = subclass.ptr();
2817
2818 // Subclass might still be parsing, just skip it
2819 if (!parsing_classes.has(subclass_ptr)) {
2820 Error err = _prepare_compilation(subclass_ptr, inner_class, p_keep_state);
2821 if (err) {
2822 return err;
2823 }
2824 }
2825
2826 p_script->constants.insert(name, subclass); //once parsed, goes to the list of constants
2827 }
2828
2829 return OK;
2830}
2831
2832Error GDScriptCompiler::_compile_class(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
2833 // Compile member functions, getters, and setters.
2834 for (int i = 0; i < p_class->members.size(); i++) {
2835 const GDScriptParser::ClassNode::Member &member = p_class->members[i];
2836 if (member.type == member.FUNCTION) {
2837 const GDScriptParser::FunctionNode *function = member.function;
2838 Error err = OK;
2839 _parse_function(err, p_script, p_class, function);
2840 if (err) {
2841 return err;
2842 }
2843 } else if (member.type == member.VARIABLE) {
2844 const GDScriptParser::VariableNode *variable = member.variable;
2845 if (variable->property == GDScriptParser::VariableNode::PROP_INLINE) {
2846 if (variable->setter != nullptr) {
2847 Error err = _parse_setter_getter(p_script, p_class, variable, true);
2848 if (err) {
2849 return err;
2850 }
2851 }
2852 if (variable->getter != nullptr) {
2853 Error err = _parse_setter_getter(p_script, p_class, variable, false);
2854 if (err) {
2855 return err;
2856 }
2857 }
2858 }
2859 }
2860 }
2861
2862 {
2863 // Create an implicit constructor in any case.
2864 Error err = OK;
2865 _parse_function(err, p_script, p_class, nullptr);
2866 if (err) {
2867 return err;
2868 }
2869 }
2870
2871 if (p_class->onready_used) {
2872 // Create an implicit_ready constructor.
2873 Error err = OK;
2874 _parse_function(err, p_script, p_class, nullptr, true);
2875 if (err) {
2876 return err;
2877 }
2878 }
2879
2880 if (p_class->has_static_data) {
2881 Error err = OK;
2882 GDScriptFunction *func = _make_static_initializer(err, p_script, p_class);
2883 p_script->static_initializer = func;
2884 if (err) {
2885 return err;
2886 }
2887 }
2888
2889#ifdef DEBUG_ENABLED
2890
2891 //validate instances if keeping state
2892
2893 if (p_keep_state) {
2894 for (RBSet<Object *>::Element *E = p_script->instances.front(); E;) {
2895 RBSet<Object *>::Element *N = E->next();
2896
2897 ScriptInstance *si = E->get()->get_script_instance();
2898 if (si->is_placeholder()) {
2899#ifdef TOOLS_ENABLED
2900 PlaceHolderScriptInstance *psi = static_cast<PlaceHolderScriptInstance *>(si);
2901
2902 if (p_script->is_tool()) {
2903 //re-create as an instance
2904 p_script->placeholders.erase(psi); //remove placeholder
2905
2906 GDScriptInstance *instance = memnew(GDScriptInstance);
2907 instance->base_ref_counted = Object::cast_to<RefCounted>(E->get());
2908 instance->members.resize(p_script->member_indices.size());
2909 instance->script = Ref<GDScript>(p_script);
2910 instance->owner = E->get();
2911
2912 //needed for hot reloading
2913 for (const KeyValue<StringName, GDScript::MemberInfo> &F : p_script->member_indices) {
2914 instance->member_indices_cache[F.key] = F.value.index;
2915 }
2916 instance->owner->set_script_instance(instance);
2917
2918 /* STEP 2, INITIALIZE AND CONSTRUCT */
2919
2920 Callable::CallError ce;
2921 p_script->initializer->call(instance, nullptr, 0, ce);
2922
2923 if (ce.error != Callable::CallError::CALL_OK) {
2924 //well, tough luck, not gonna do anything here
2925 }
2926 }
2927#endif // TOOLS_ENABLED
2928 } else {
2929 GDScriptInstance *gi = static_cast<GDScriptInstance *>(si);
2930 gi->reload_members();
2931 }
2932
2933 E = N;
2934 }
2935 }
2936#endif //DEBUG_ENABLED
2937
2938 has_static_data = p_class->has_static_data;
2939
2940 for (int i = 0; i < p_class->members.size(); i++) {
2941 if (p_class->members[i].type != GDScriptParser::ClassNode::Member::CLASS) {
2942 continue;
2943 }
2944 const GDScriptParser::ClassNode *inner_class = p_class->members[i].m_class;
2945 StringName name = inner_class->identifier->name;
2946 GDScript *subclass = p_script->subclasses[name].ptr();
2947
2948 Error err = _compile_class(subclass, inner_class, p_keep_state);
2949 if (err) {
2950 return err;
2951 }
2952
2953 has_static_data = has_static_data || inner_class->has_static_data;
2954 }
2955
2956 p_script->valid = true;
2957 return OK;
2958}
2959
2960void GDScriptCompiler::convert_to_initializer_type(Variant &p_variant, const GDScriptParser::VariableNode *p_node) {
2961 // Set p_variant to the value of p_node's initializer, with the type of p_node's variable.
2962 GDScriptParser::DataType member_t = p_node->datatype;
2963 GDScriptParser::DataType init_t = p_node->initializer->datatype;
2964 if (member_t.is_hard_type() && init_t.is_hard_type() &&
2965 member_t.kind == GDScriptParser::DataType::BUILTIN && init_t.kind == GDScriptParser::DataType::BUILTIN) {
2966 if (Variant::can_convert_strict(init_t.builtin_type, member_t.builtin_type)) {
2967 Variant *v = &p_node->initializer->reduced_value;
2968 Callable::CallError ce;
2969 Variant::construct(member_t.builtin_type, p_variant, const_cast<const Variant **>(&v), 1, ce);
2970 }
2971 }
2972}
2973
2974void GDScriptCompiler::make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
2975 p_script->fully_qualified_name = p_class->fqcn;
2976 p_script->local_name = p_class->identifier ? p_class->identifier->name : StringName();
2977 p_script->global_name = p_class->get_global_name();
2978 p_script->simplified_icon_path = p_class->simplified_icon_path;
2979
2980 HashMap<StringName, Ref<GDScript>> old_subclasses;
2981
2982 if (p_keep_state) {
2983 old_subclasses = p_script->subclasses;
2984 }
2985
2986 p_script->subclasses.clear();
2987
2988 for (int i = 0; i < p_class->members.size(); i++) {
2989 if (p_class->members[i].type != GDScriptParser::ClassNode::Member::CLASS) {
2990 continue;
2991 }
2992 const GDScriptParser::ClassNode *inner_class = p_class->members[i].m_class;
2993 StringName name = inner_class->identifier->name;
2994
2995 Ref<GDScript> subclass;
2996
2997 if (old_subclasses.has(name)) {
2998 subclass = old_subclasses[name];
2999 } else {
3000 subclass = GDScriptLanguage::get_singleton()->get_orphan_subclass(inner_class->fqcn);
3001 }
3002
3003 if (subclass.is_null()) {
3004 subclass.instantiate();
3005 }
3006
3007 subclass->_owner = p_script;
3008 subclass->path = p_script->path;
3009 p_script->subclasses.insert(name, subclass);
3010
3011 make_scripts(subclass.ptr(), inner_class, p_keep_state);
3012 }
3013}
3014
3015Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_script, bool p_keep_state) {
3016 err_line = -1;
3017 err_column = -1;
3018 error = "";
3019 parser = p_parser;
3020 main_script = p_script;
3021 const GDScriptParser::ClassNode *root = parser->get_tree();
3022
3023 source = p_script->get_path();
3024
3025 // Create scripts for subclasses beforehand so they can be referenced
3026 make_scripts(p_script, root, p_keep_state);
3027
3028 main_script->_owner = nullptr;
3029 Error err = _prepare_compilation(main_script, parser->get_tree(), p_keep_state);
3030
3031 if (err) {
3032 return err;
3033 }
3034
3035 err = _compile_class(main_script, root, p_keep_state);
3036 if (err) {
3037 return err;
3038 }
3039
3040 if (has_static_data && !root->annotated_static_unload) {
3041 GDScriptCache::add_static_script(p_script);
3042 }
3043
3044 return GDScriptCache::finish_compiling(main_script->path);
3045}
3046
3047String GDScriptCompiler::get_error() const {
3048 return error;
3049}
3050
3051int GDScriptCompiler::get_error_line() const {
3052 return err_line;
3053}
3054
3055int GDScriptCompiler::get_error_column() const {
3056 return err_column;
3057}
3058
3059GDScriptCompiler::GDScriptCompiler() {
3060}
3061