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