1 /*************************************************************************/
2 /* gdscript.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
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.h"
32
33 #include "core/core_string_names.h"
34 #include "core/engine.h"
35 #include "core/global_constants.h"
36 #include "core/io/file_access_encrypted.h"
37 #include "core/os/file_access.h"
38 #include "core/os/os.h"
39 #include "core/project_settings.h"
40 #include "gdscript_compiler.h"
41
42 ///////////////////////////
43
GDScriptNativeClass(const StringName & p_name)44 GDScriptNativeClass::GDScriptNativeClass(const StringName &p_name) {
45
46 name = p_name;
47 }
48
_get(const StringName & p_name,Variant & r_ret) const49 bool GDScriptNativeClass::_get(const StringName &p_name, Variant &r_ret) const {
50
51 bool ok;
52 int v = ClassDB::get_integer_constant(name, p_name, &ok);
53
54 if (ok) {
55 r_ret = v;
56 return true;
57 } else {
58 return false;
59 }
60 }
61
_bind_methods()62 void GDScriptNativeClass::_bind_methods() {
63
64 ClassDB::bind_method(D_METHOD("new"), &GDScriptNativeClass::_new);
65 }
66
_new()67 Variant GDScriptNativeClass::_new() {
68
69 Object *o = instance();
70 ERR_FAIL_COND_V_MSG(!o, Variant(), "Class type: '" + String(name) + "' is not instantiable.");
71
72 Reference *ref = Object::cast_to<Reference>(o);
73 if (ref) {
74 return REF(ref);
75 } else {
76 return o;
77 }
78 }
79
instance()80 Object *GDScriptNativeClass::instance() {
81
82 return ClassDB::instance(name);
83 }
84
_create_instance(const Variant ** p_args,int p_argcount,Object * p_owner,bool p_isref,Variant::CallError & r_error)85 GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error) {
86
87 /* STEP 1, CREATE */
88
89 GDScriptInstance *instance = memnew(GDScriptInstance);
90 instance->base_ref = p_isref;
91 instance->members.resize(member_indices.size());
92 instance->script = Ref<GDScript>(this);
93 instance->owner = p_owner;
94 #ifdef DEBUG_ENABLED
95 //needed for hot reloading
96 for (Map<StringName, MemberInfo>::Element *E = member_indices.front(); E; E = E->next()) {
97 instance->member_indices_cache[E->key()] = E->get().index;
98 }
99 #endif
100 instance->owner->set_script_instance(instance);
101
102 /* STEP 2, INITIALIZE AND CONSTRUCT */
103
104 #ifndef NO_THREADS
105 GDScriptLanguage::singleton->lock->lock();
106 #endif
107
108 instances.insert(instance->owner);
109
110 #ifndef NO_THREADS
111 GDScriptLanguage::singleton->lock->unlock();
112 #endif
113
114 initializer->call(instance, p_args, p_argcount, r_error);
115
116 if (r_error.error != Variant::CallError::CALL_OK) {
117 instance->script = Ref<GDScript>();
118 instance->owner->set_script_instance(NULL);
119 #ifndef NO_THREADS
120 GDScriptLanguage::singleton->lock->lock();
121 #endif
122 instances.erase(p_owner);
123 #ifndef NO_THREADS
124 GDScriptLanguage::singleton->lock->unlock();
125 #endif
126
127 ERR_FAIL_COND_V(r_error.error != Variant::CallError::CALL_OK, NULL); //error constructing
128 }
129
130 //@TODO make thread safe
131 return instance;
132 }
133
_new(const Variant ** p_args,int p_argcount,Variant::CallError & r_error)134 Variant GDScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
135
136 /* STEP 1, CREATE */
137
138 if (!valid) {
139 r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
140 return Variant();
141 }
142
143 r_error.error = Variant::CallError::CALL_OK;
144 REF ref;
145 Object *owner = NULL;
146
147 GDScript *_baseptr = this;
148 while (_baseptr->_base) {
149 _baseptr = _baseptr->_base;
150 }
151
152 ERR_FAIL_COND_V(_baseptr->native.is_null(), Variant());
153 if (_baseptr->native.ptr()) {
154 owner = _baseptr->native->instance();
155 } else {
156 owner = memnew(Reference); //by default, no base means use reference
157 }
158 ERR_FAIL_COND_V_MSG(!owner, Variant(), "Can't inherit from a virtual class.");
159
160 Reference *r = Object::cast_to<Reference>(owner);
161 if (r) {
162 ref = REF(r);
163 }
164
165 GDScriptInstance *instance = _create_instance(p_args, p_argcount, owner, r != NULL, r_error);
166 if (!instance) {
167 if (ref.is_null()) {
168 memdelete(owner); //no owner, sorry
169 }
170 return Variant();
171 }
172
173 if (ref.is_valid()) {
174 return ref;
175 } else {
176 return owner;
177 }
178 }
179
can_instance() const180 bool GDScript::can_instance() const {
181
182 #ifdef TOOLS_ENABLED
183 return valid && (tool || ScriptServer::is_scripting_enabled());
184 #else
185 return valid;
186 #endif
187 }
188
get_base_script() const189 Ref<Script> GDScript::get_base_script() const {
190
191 if (_base) {
192 return Ref<GDScript>(_base);
193 } else {
194 return Ref<Script>();
195 }
196 }
197
get_instance_base_type() const198 StringName GDScript::get_instance_base_type() const {
199
200 if (native.is_valid())
201 return native->get_name();
202 if (base.is_valid() && base->is_valid())
203 return base->get_instance_base_type();
204 return StringName();
205 }
206
207 struct _GDScriptMemberSort {
208
209 int index;
210 StringName name;
operator <_GDScriptMemberSort211 _FORCE_INLINE_ bool operator<(const _GDScriptMemberSort &p_member) const { return index < p_member.index; }
212 };
213
214 #ifdef TOOLS_ENABLED
215
_placeholder_erased(PlaceHolderScriptInstance * p_placeholder)216 void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
217
218 placeholders.erase(p_placeholder);
219 }
220 #endif
221
get_script_method_list(List<MethodInfo> * p_list) const222 void GDScript::get_script_method_list(List<MethodInfo> *p_list) const {
223
224 const GDScript *current = this;
225 while (current) {
226 for (const Map<StringName, GDScriptFunction *>::Element *E = current->member_functions.front(); E; E = E->next()) {
227 GDScriptFunction *func = E->get();
228 MethodInfo mi;
229 mi.name = E->key();
230 for (int i = 0; i < func->get_argument_count(); i++) {
231 mi.arguments.push_back(func->get_argument_type(i));
232 }
233
234 mi.return_val = func->get_return_type();
235 p_list->push_back(mi);
236 }
237
238 current = current->_base;
239 }
240 }
241
get_script_property_list(List<PropertyInfo> * p_list) const242 void GDScript::get_script_property_list(List<PropertyInfo> *p_list) const {
243
244 const GDScript *sptr = this;
245 List<PropertyInfo> props;
246
247 while (sptr) {
248
249 Vector<_GDScriptMemberSort> msort;
250 for (Map<StringName, PropertyInfo>::Element *E = sptr->member_info.front(); E; E = E->next()) {
251
252 _GDScriptMemberSort ms;
253 ERR_CONTINUE(!sptr->member_indices.has(E->key()));
254 ms.index = sptr->member_indices[E->key()].index;
255 ms.name = E->key();
256 msort.push_back(ms);
257 }
258
259 msort.sort();
260 msort.invert();
261 for (int i = 0; i < msort.size(); i++) {
262
263 props.push_front(sptr->member_info[msort[i].name]);
264 }
265
266 sptr = sptr->_base;
267 }
268
269 for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
270 p_list->push_back(E->get());
271 }
272 }
273
has_method(const StringName & p_method) const274 bool GDScript::has_method(const StringName &p_method) const {
275
276 return member_functions.has(p_method);
277 }
278
get_method_info(const StringName & p_method) const279 MethodInfo GDScript::get_method_info(const StringName &p_method) const {
280
281 const Map<StringName, GDScriptFunction *>::Element *E = member_functions.find(p_method);
282 if (!E)
283 return MethodInfo();
284
285 GDScriptFunction *func = E->get();
286 MethodInfo mi;
287 mi.name = E->key();
288 for (int i = 0; i < func->get_argument_count(); i++) {
289 mi.arguments.push_back(func->get_argument_type(i));
290 }
291
292 mi.return_val = func->get_return_type();
293 return mi;
294 }
295
get_property_default_value(const StringName & p_property,Variant & r_value) const296 bool GDScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
297
298 #ifdef TOOLS_ENABLED
299
300 const Map<StringName, Variant>::Element *E = member_default_values_cache.find(p_property);
301 if (E) {
302 r_value = E->get();
303 return true;
304 }
305
306 if (base_cache.is_valid()) {
307 return base_cache->get_property_default_value(p_property, r_value);
308 }
309 #endif
310 return false;
311 }
312
instance_create(Object * p_this)313 ScriptInstance *GDScript::instance_create(Object *p_this) {
314
315 GDScript *top = this;
316 while (top->_base)
317 top = top->_base;
318
319 if (top->native.is_valid()) {
320 if (!ClassDB::is_parent_class(p_this->get_class_name(), top->native->get_name())) {
321
322 if (ScriptDebugger::get_singleton()) {
323 GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'");
324 }
325 ERR_FAIL_V_MSG(NULL, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type '" + p_this->get_class() + "'" + ".");
326 }
327 }
328
329 Variant::CallError unchecked_error;
330 return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error);
331 }
332
placeholder_instance_create(Object * p_this)333 PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) {
334 #ifdef TOOLS_ENABLED
335 PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(), Ref<Script>(this), p_this));
336 placeholders.insert(si);
337 _update_exports();
338 return si;
339 #else
340 return NULL;
341 #endif
342 }
343
instance_has(const Object * p_this) const344 bool GDScript::instance_has(const Object *p_this) const {
345
346 #ifndef NO_THREADS
347 GDScriptLanguage::singleton->lock->lock();
348 #endif
349 bool hasit = instances.has((Object *)p_this);
350
351 #ifndef NO_THREADS
352 GDScriptLanguage::singleton->lock->unlock();
353 #endif
354
355 return hasit;
356 }
357
has_source_code() const358 bool GDScript::has_source_code() const {
359
360 return source != "";
361 }
get_source_code() const362 String GDScript::get_source_code() const {
363
364 return source;
365 }
set_source_code(const String & p_code)366 void GDScript::set_source_code(const String &p_code) {
367
368 if (source == p_code)
369 return;
370 source = p_code;
371 #ifdef TOOLS_ENABLED
372 source_changed_cache = true;
373 #endif
374 }
375
376 #ifdef TOOLS_ENABLED
_update_exports_values(Map<StringName,Variant> & values,List<PropertyInfo> & propnames)377 void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames) {
378
379 if (base_cache.is_valid()) {
380 base_cache->_update_exports_values(values, propnames);
381 }
382
383 for (Map<StringName, Variant>::Element *E = member_default_values_cache.front(); E; E = E->next()) {
384 values[E->key()] = E->get();
385 }
386
387 for (List<PropertyInfo>::Element *E = members_cache.front(); E; E = E->next()) {
388 propnames.push_back(E->get());
389 }
390 }
391 #endif
392
_update_exports(bool * r_err,bool p_recursive_call)393 bool GDScript::_update_exports(bool *r_err, bool p_recursive_call) {
394
395 #ifdef TOOLS_ENABLED
396
397 static Vector<GDScript *> base_caches;
398 if (!p_recursive_call)
399 base_caches.clear();
400 base_caches.push_back(this);
401
402 bool changed = false;
403
404 if (source_changed_cache) {
405 source_changed_cache = false;
406 changed = true;
407
408 String basedir = path;
409
410 if (basedir == "")
411 basedir = get_path();
412
413 if (basedir != "")
414 basedir = basedir.get_base_dir();
415
416 GDScriptParser parser;
417 Error err = parser.parse(source, basedir, true, path);
418
419 if (err == OK) {
420
421 const GDScriptParser::Node *root = parser.get_parse_tree();
422 ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, false);
423
424 const GDScriptParser::ClassNode *c = static_cast<const GDScriptParser::ClassNode *>(root);
425
426 if (base_cache.is_valid()) {
427 base_cache->inheriters_cache.erase(get_instance_id());
428 base_cache = Ref<GDScript>();
429 }
430
431 if (c->extends_used) {
432 String path = "";
433 if (String(c->extends_file) != "" && String(c->extends_file) != get_path()) {
434 path = c->extends_file;
435 if (path.is_rel_path()) {
436
437 String base = get_path();
438 if (base == "" || base.is_rel_path()) {
439
440 ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data());
441 } else {
442 path = base.get_base_dir().plus_file(path);
443 }
444 }
445 } else if (c->extends_class.size() != 0) {
446 String base = c->extends_class[0];
447
448 if (ScriptServer::is_global_class(base))
449 path = ScriptServer::get_global_class_path(base);
450 }
451
452 if (path != "") {
453 if (path != get_path()) {
454
455 Ref<GDScript> bf = ResourceLoader::load(path);
456
457 if (bf.is_valid()) {
458
459 base_cache = bf;
460 bf->inheriters_cache.insert(get_instance_id());
461 }
462 } else {
463 ERR_PRINT(("Path extending itself in " + path).utf8().get_data());
464 }
465 }
466 }
467
468 members_cache.clear();
469 member_default_values_cache.clear();
470
471 for (int i = 0; i < c->variables.size(); i++) {
472 if (c->variables[i]._export.type == Variant::NIL)
473 continue;
474
475 members_cache.push_back(c->variables[i]._export);
476 member_default_values_cache[c->variables[i].identifier] = c->variables[i].default_value;
477 }
478
479 _signals.clear();
480
481 for (int i = 0; i < c->_signals.size(); i++) {
482 _signals[c->_signals[i].name] = c->_signals[i].arguments;
483 }
484 } else {
485 placeholder_fallback_enabled = true;
486 return false;
487 }
488 } else if (placeholder_fallback_enabled) {
489 return false;
490 }
491
492 placeholder_fallback_enabled = false;
493
494 if (base_cache.is_valid() && base_cache->is_valid()) {
495 for (int i = 0; i < base_caches.size(); i++) {
496 if (base_caches[i] == base_cache.ptr()) {
497 if (r_err)
498 *r_err = true;
499 valid = false; // to show error in the editor
500 base_cache->valid = false;
501 base_cache->inheriters_cache.clear(); // to prevent future stackoverflows
502 base_cache.unref();
503 base.unref();
504 _base = nullptr;
505 ERR_FAIL_V_MSG(false, "Cyclic inheritance in script class.");
506 }
507 }
508 if (base_cache->_update_exports(r_err, true)) {
509 if (r_err && *r_err)
510 return false;
511 changed = true;
512 }
513 }
514
515 if (placeholders.size()) { //hm :(
516
517 // update placeholders if any
518 Map<StringName, Variant> values;
519 List<PropertyInfo> propnames;
520 _update_exports_values(values, propnames);
521
522 for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
523 E->get()->update(propnames, values);
524 }
525 }
526
527 return changed;
528
529 #else
530 return false;
531 #endif
532 }
533
update_exports()534 void GDScript::update_exports() {
535
536 #ifdef TOOLS_ENABLED
537
538 bool cyclic_error = false;
539 _update_exports(&cyclic_error);
540 if (cyclic_error)
541 return;
542
543 Set<ObjectID> copy = inheriters_cache; //might get modified
544
545 for (Set<ObjectID>::Element *E = copy.front(); E; E = E->next()) {
546 Object *id = ObjectDB::get_instance(E->get());
547 GDScript *s = Object::cast_to<GDScript>(id);
548 if (!s)
549 continue;
550 s->update_exports();
551 }
552
553 #endif
554 }
555
_set_subclass_path(Ref<GDScript> & p_sc,const String & p_path)556 void GDScript::_set_subclass_path(Ref<GDScript> &p_sc, const String &p_path) {
557
558 p_sc->path = p_path;
559 for (Map<StringName, Ref<GDScript> >::Element *E = p_sc->subclasses.front(); E; E = E->next()) {
560
561 _set_subclass_path(E->get(), p_path);
562 }
563 }
564
reload(bool p_keep_state)565 Error GDScript::reload(bool p_keep_state) {
566
567 #ifndef NO_THREADS
568 GDScriptLanguage::singleton->lock->lock();
569 #endif
570 bool has_instances = instances.size();
571
572 #ifndef NO_THREADS
573 GDScriptLanguage::singleton->lock->unlock();
574 #endif
575
576 ERR_FAIL_COND_V(!p_keep_state && has_instances, ERR_ALREADY_IN_USE);
577
578 String basedir = path;
579
580 if (basedir == "")
581 basedir = get_path();
582
583 if (basedir != "")
584 basedir = basedir.get_base_dir();
585
586 if (source.find("%BASE%") != -1) {
587 //loading a template, don't parse
588 return OK;
589 }
590
591 valid = false;
592 GDScriptParser parser;
593 Error err = parser.parse(source, basedir, false, path);
594 if (err) {
595 if (ScriptDebugger::get_singleton()) {
596 GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), parser.get_error_line(), "Parser Error: " + parser.get_error());
597 }
598 _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_error_line(), ("Parse Error: " + parser.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
599 ERR_FAIL_V(ERR_PARSE_ERROR);
600 }
601
602 bool can_run = ScriptServer::is_scripting_enabled() || parser.is_tool_script();
603
604 GDScriptCompiler compiler;
605 err = compiler.compile(&parser, this, p_keep_state);
606
607 if (err) {
608
609 if (can_run) {
610 if (ScriptDebugger::get_singleton()) {
611 GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error());
612 }
613 _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
614 ERR_FAIL_V(ERR_COMPILATION_FAILED);
615 } else {
616 return err;
617 }
618 }
619 #ifdef DEBUG_ENABLED
620 for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) {
621 const GDScriptWarning &warning = E->get();
622 if (ScriptDebugger::get_singleton()) {
623 Vector<ScriptLanguage::StackInfo> si;
624 ScriptDebugger::get_singleton()->send_error("", get_path(), warning.line, warning.get_name(), warning.get_message(), ERR_HANDLER_WARNING, si);
625 }
626 }
627 #endif
628
629 valid = true;
630
631 for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
632
633 _set_subclass_path(E->get(), path);
634 }
635
636 return OK;
637 }
638
get_language() const639 ScriptLanguage *GDScript::get_language() const {
640
641 return GDScriptLanguage::get_singleton();
642 }
643
get_constants(Map<StringName,Variant> * p_constants)644 void GDScript::get_constants(Map<StringName, Variant> *p_constants) {
645
646 if (p_constants) {
647 for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
648 (*p_constants)[E->key()] = E->value();
649 }
650 }
651 }
652
get_members(Set<StringName> * p_members)653 void GDScript::get_members(Set<StringName> *p_members) {
654 if (p_members) {
655 for (Set<StringName>::Element *E = members.front(); E; E = E->next()) {
656 p_members->insert(E->get());
657 }
658 }
659 }
660
call(const StringName & p_method,const Variant ** p_args,int p_argcount,Variant::CallError & r_error)661 Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
662
663 GDScript *top = this;
664 while (top) {
665
666 Map<StringName, GDScriptFunction *>::Element *E = top->member_functions.find(p_method);
667 if (E) {
668
669 ERR_FAIL_COND_V_MSG(!E->get()->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script.");
670
671 return E->get()->call(NULL, p_args, p_argcount, r_error);
672 }
673 top = top->_base;
674 }
675
676 //none found, regular
677
678 return Script::call(p_method, p_args, p_argcount, r_error);
679 }
680
_get(const StringName & p_name,Variant & r_ret) const681 bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
682
683 {
684
685 const GDScript *top = this;
686 while (top) {
687
688 {
689 const Map<StringName, Variant>::Element *E = top->constants.find(p_name);
690 if (E) {
691
692 r_ret = E->get();
693 return true;
694 }
695 }
696
697 {
698 const Map<StringName, Ref<GDScript> >::Element *E = subclasses.find(p_name);
699 if (E) {
700
701 r_ret = E->get();
702 return true;
703 }
704 }
705 top = top->_base;
706 }
707
708 if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
709
710 r_ret = get_source_code();
711 return true;
712 }
713 }
714
715 return false;
716 }
_set(const StringName & p_name,const Variant & p_value)717 bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
718
719 if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
720
721 set_source_code(p_value);
722 reload();
723 } else
724 return false;
725
726 return true;
727 }
728
_get_property_list(List<PropertyInfo> * p_properties) const729 void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const {
730
731 p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
732 }
733
_bind_methods()734 void GDScript::_bind_methods() {
735
736 ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &GDScript::_new, MethodInfo("new"));
737
738 ClassDB::bind_method(D_METHOD("get_as_byte_code"), &GDScript::get_as_byte_code);
739 }
740
get_as_byte_code() const741 Vector<uint8_t> GDScript::get_as_byte_code() const {
742
743 GDScriptTokenizerBuffer tokenizer;
744 return tokenizer.parse_code_string(source);
745 };
746
load_byte_code(const String & p_path)747 Error GDScript::load_byte_code(const String &p_path) {
748
749 Vector<uint8_t> bytecode;
750
751 if (p_path.ends_with("gde")) {
752
753 FileAccess *fa = FileAccess::open(p_path, FileAccess::READ);
754 ERR_FAIL_COND_V(!fa, ERR_CANT_OPEN);
755
756 FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
757 ERR_FAIL_COND_V(!fae, ERR_CANT_OPEN);
758
759 Vector<uint8_t> key;
760 key.resize(32);
761 for (int i = 0; i < key.size(); i++) {
762 key.write[i] = script_encryption_key[i];
763 }
764
765 Error err = fae->open_and_parse(fa, key, FileAccessEncrypted::MODE_READ);
766
767 if (err) {
768 fa->close();
769 memdelete(fa);
770 memdelete(fae);
771
772 ERR_FAIL_COND_V(err, err);
773 }
774
775 bytecode.resize(fae->get_len());
776 fae->get_buffer(bytecode.ptrw(), bytecode.size());
777 fae->close();
778 memdelete(fae);
779
780 } else {
781
782 bytecode = FileAccess::get_file_as_array(p_path);
783 }
784
785 ERR_FAIL_COND_V(bytecode.size() == 0, ERR_PARSE_ERROR);
786 path = p_path;
787
788 String basedir = path;
789
790 if (basedir == "")
791 basedir = get_path();
792
793 if (basedir != "")
794 basedir = basedir.get_base_dir();
795
796 valid = false;
797 GDScriptParser parser;
798 Error err = parser.parse_bytecode(bytecode, basedir, get_path());
799 if (err) {
800 _err_print_error("GDScript::load_byte_code", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_error_line(), ("Parse Error: " + parser.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
801 ERR_FAIL_V(ERR_PARSE_ERROR);
802 }
803
804 GDScriptCompiler compiler;
805 err = compiler.compile(&parser, this);
806
807 if (err) {
808 _err_print_error("GDScript::load_byte_code", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
809 ERR_FAIL_V(ERR_COMPILATION_FAILED);
810 }
811
812 valid = true;
813
814 for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
815
816 _set_subclass_path(E->get(), path);
817 }
818
819 return OK;
820 }
821
load_source_code(const String & p_path)822 Error GDScript::load_source_code(const String &p_path) {
823
824 PoolVector<uint8_t> sourcef;
825 Error err;
826 FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
827 if (err) {
828
829 ERR_FAIL_COND_V(err, err);
830 }
831
832 int len = f->get_len();
833 sourcef.resize(len + 1);
834 PoolVector<uint8_t>::Write w = sourcef.write();
835 int r = f->get_buffer(w.ptr(), len);
836 f->close();
837 memdelete(f);
838 ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
839 w[len] = 0;
840
841 String s;
842 if (s.parse_utf8((const char *)w.ptr())) {
843
844 ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded. Please ensure that scripts are saved in valid UTF-8 unicode.");
845 }
846
847 source = s;
848 #ifdef TOOLS_ENABLED
849 source_changed_cache = true;
850 #endif
851 path = p_path;
852 return OK;
853 }
854
debug_get_member_functions() const855 const Map<StringName, GDScriptFunction *> &GDScript::debug_get_member_functions() const {
856
857 return member_functions;
858 }
859
debug_get_member_by_index(int p_idx) const860 StringName GDScript::debug_get_member_by_index(int p_idx) const {
861
862 for (const Map<StringName, MemberInfo>::Element *E = member_indices.front(); E; E = E->next()) {
863
864 if (E->get().index == p_idx)
865 return E->key();
866 }
867
868 return "<error>";
869 }
870
get_base() const871 Ref<GDScript> GDScript::get_base() const {
872
873 return base;
874 }
875
has_script_signal(const StringName & p_signal) const876 bool GDScript::has_script_signal(const StringName &p_signal) const {
877 if (_signals.has(p_signal))
878 return true;
879 if (base.is_valid()) {
880 return base->has_script_signal(p_signal);
881 }
882 #ifdef TOOLS_ENABLED
883 else if (base_cache.is_valid()) {
884 return base_cache->has_script_signal(p_signal);
885 }
886 #endif
887 return false;
888 }
get_script_signal_list(List<MethodInfo> * r_signals) const889 void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
890
891 for (const Map<StringName, Vector<StringName> >::Element *E = _signals.front(); E; E = E->next()) {
892
893 MethodInfo mi;
894 mi.name = E->key();
895 for (int i = 0; i < E->get().size(); i++) {
896 PropertyInfo arg;
897 arg.name = E->get()[i];
898 mi.arguments.push_back(arg);
899 }
900 r_signals->push_back(mi);
901 }
902
903 if (base.is_valid()) {
904 base->get_script_signal_list(r_signals);
905 }
906 #ifdef TOOLS_ENABLED
907 else if (base_cache.is_valid()) {
908 base_cache->get_script_signal_list(r_signals);
909 }
910
911 #endif
912 }
913
GDScript()914 GDScript::GDScript() :
915 script_list(this) {
916
917 _static_ref = this;
918 valid = false;
919 subclass_count = 0;
920 initializer = NULL;
921 _base = NULL;
922 _owner = NULL;
923 tool = false;
924 #ifdef TOOLS_ENABLED
925 source_changed_cache = false;
926 placeholder_fallback_enabled = false;
927 #endif
928
929 #ifdef DEBUG_ENABLED
930 if (GDScriptLanguage::get_singleton()->lock) {
931 GDScriptLanguage::get_singleton()->lock->lock();
932 }
933 GDScriptLanguage::get_singleton()->script_list.add(&script_list);
934
935 if (GDScriptLanguage::get_singleton()->lock) {
936 GDScriptLanguage::get_singleton()->lock->unlock();
937 }
938 #endif
939 }
940
_save_orphaned_subclasses()941 void GDScript::_save_orphaned_subclasses() {
942 struct ClassRefWithName {
943 ObjectID id;
944 String fully_qualified_name;
945 };
946 Vector<ClassRefWithName> weak_subclasses;
947 // collect subclasses ObjectID and name
948 for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
949 E->get()->_owner = NULL; //bye, you are no longer owned cause I died
950 ClassRefWithName subclass;
951 subclass.id = E->get()->get_instance_id();
952 subclass.fully_qualified_name = E->get()->fully_qualified_name;
953 weak_subclasses.push_back(subclass);
954 }
955
956 // clear subclasses to allow unused subclasses to be deleted
957 subclasses.clear();
958 // subclasses are also held by constants, clear those as well
959 constants.clear();
960
961 // keep orphan subclass only for subclasses that are still in use
962 for (int i = 0; i < weak_subclasses.size(); i++) {
963 ClassRefWithName subclass = weak_subclasses[i];
964 Object *obj = ObjectDB::get_instance(subclass.id);
965 if (!obj)
966 continue;
967 // subclass is not released
968 GDScriptLanguage::get_singleton()->add_orphan_subclass(subclass.fully_qualified_name, subclass.id);
969 }
970 }
971
~GDScript()972 GDScript::~GDScript() {
973
974 if (GDScriptLanguage::get_singleton()->lock) {
975 GDScriptLanguage::get_singleton()->lock->lock();
976 }
977 while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
978 E->self()->_clear_stack();
979 pending_func_states.remove(E);
980 }
981 if (GDScriptLanguage::get_singleton()->lock) {
982 GDScriptLanguage::get_singleton()->lock->unlock();
983 }
984
985 for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
986 memdelete(E->get());
987 }
988
989 _save_orphaned_subclasses();
990
991 #ifdef DEBUG_ENABLED
992 if (GDScriptLanguage::get_singleton()->lock) {
993 GDScriptLanguage::get_singleton()->lock->lock();
994 }
995 GDScriptLanguage::get_singleton()->script_list.remove(&script_list);
996
997 if (GDScriptLanguage::get_singleton()->lock) {
998 GDScriptLanguage::get_singleton()->lock->unlock();
999 }
1000 #endif
1001 }
1002
1003 //////////////////////////////
1004 // INSTANCE //
1005 //////////////////////////////
1006
set(const StringName & p_name,const Variant & p_value)1007 bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
1008
1009 //member
1010 {
1011 const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
1012 if (E) {
1013 const GDScript::MemberInfo *member = &E->get();
1014 if (member->setter) {
1015 const Variant *val = &p_value;
1016 Variant::CallError err;
1017 call(member->setter, &val, 1, err);
1018 if (err.error == Variant::CallError::CALL_OK) {
1019 return true; //function exists, call was successful
1020 }
1021 } else {
1022 if (!member->data_type.is_type(p_value)) {
1023 // Try conversion
1024 Variant::CallError ce;
1025 const Variant *value = &p_value;
1026 Variant converted = Variant::construct(member->data_type.builtin_type, &value, 1, ce);
1027 if (ce.error == Variant::CallError::CALL_OK) {
1028 members.write[member->index] = converted;
1029 return true;
1030 } else {
1031 return false;
1032 }
1033 } else {
1034 members.write[member->index] = p_value;
1035 }
1036 }
1037 return true;
1038 }
1039 }
1040
1041 GDScript *sptr = script.ptr();
1042 while (sptr) {
1043
1044 Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
1045 if (E) {
1046
1047 Variant name = p_name;
1048 const Variant *args[2] = { &name, &p_value };
1049
1050 Variant::CallError err;
1051 Variant ret = E->get()->call(this, (const Variant **)args, 2, err);
1052 if (err.error == Variant::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool())
1053 return true;
1054 }
1055 sptr = sptr->_base;
1056 }
1057
1058 return false;
1059 }
1060
get(const StringName & p_name,Variant & r_ret) const1061 bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
1062
1063 const GDScript *sptr = script.ptr();
1064 while (sptr) {
1065
1066 {
1067 const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
1068 if (E) {
1069 if (E->get().getter) {
1070 Variant::CallError err;
1071 r_ret = const_cast<GDScriptInstance *>(this)->call(E->get().getter, NULL, 0, err);
1072 if (err.error == Variant::CallError::CALL_OK) {
1073 return true;
1074 }
1075 }
1076 r_ret = members[E->get().index];
1077 return true; //index found
1078 }
1079 }
1080
1081 {
1082
1083 const GDScript *sl = sptr;
1084 while (sl) {
1085 const Map<StringName, Variant>::Element *E = sl->constants.find(p_name);
1086 if (E) {
1087 r_ret = E->get();
1088 return true; //index found
1089 }
1090 sl = sl->_base;
1091 }
1092 }
1093
1094 {
1095 const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get);
1096 if (E) {
1097
1098 Variant name = p_name;
1099 const Variant *args[1] = { &name };
1100
1101 Variant::CallError err;
1102 Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), (const Variant **)args, 1, err);
1103 if (err.error == Variant::CallError::CALL_OK && ret.get_type() != Variant::NIL) {
1104 r_ret = ret;
1105 return true;
1106 }
1107 }
1108 }
1109 sptr = sptr->_base;
1110 }
1111
1112 return false;
1113 }
1114
get_property_type(const StringName & p_name,bool * r_is_valid) const1115 Variant::Type GDScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
1116
1117 const GDScript *sptr = script.ptr();
1118 while (sptr) {
1119
1120 if (sptr->member_info.has(p_name)) {
1121 if (r_is_valid)
1122 *r_is_valid = true;
1123 return sptr->member_info[p_name].type;
1124 }
1125 sptr = sptr->_base;
1126 }
1127
1128 if (r_is_valid)
1129 *r_is_valid = false;
1130 return Variant::NIL;
1131 }
1132
get_property_list(List<PropertyInfo> * p_properties) const1133 void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
1134 // exported members, not done yet!
1135
1136 const GDScript *sptr = script.ptr();
1137 List<PropertyInfo> props;
1138
1139 while (sptr) {
1140
1141 const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list);
1142 if (E) {
1143
1144 Variant::CallError err;
1145 Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), NULL, 0, err);
1146 if (err.error == Variant::CallError::CALL_OK) {
1147
1148 ERR_FAIL_COND_MSG(ret.get_type() != Variant::ARRAY, "Wrong type for _get_property_list, must be an array of dictionaries.");
1149
1150 Array arr = ret;
1151 for (int i = 0; i < arr.size(); i++) {
1152
1153 Dictionary d = arr[i];
1154 ERR_CONTINUE(!d.has("name"));
1155 ERR_CONTINUE(!d.has("type"));
1156 PropertyInfo pinfo;
1157 pinfo.type = Variant::Type(d["type"].operator int());
1158 ERR_CONTINUE(pinfo.type < 0 || pinfo.type >= Variant::VARIANT_MAX);
1159 pinfo.name = d["name"];
1160 ERR_CONTINUE(pinfo.name == "");
1161 if (d.has("hint"))
1162 pinfo.hint = PropertyHint(d["hint"].operator int());
1163 if (d.has("hint_string"))
1164 pinfo.hint_string = d["hint_string"];
1165 if (d.has("usage"))
1166 pinfo.usage = d["usage"];
1167
1168 props.push_back(pinfo);
1169 }
1170 }
1171 }
1172
1173 //instance a fake script for editing the values
1174
1175 Vector<_GDScriptMemberSort> msort;
1176 for (Map<StringName, PropertyInfo>::Element *F = sptr->member_info.front(); F; F = F->next()) {
1177
1178 _GDScriptMemberSort ms;
1179 ERR_CONTINUE(!sptr->member_indices.has(F->key()));
1180 ms.index = sptr->member_indices[F->key()].index;
1181 ms.name = F->key();
1182 msort.push_back(ms);
1183 }
1184
1185 msort.sort();
1186 msort.invert();
1187 for (int i = 0; i < msort.size(); i++) {
1188
1189 props.push_front(sptr->member_info[msort[i].name]);
1190 }
1191
1192 sptr = sptr->_base;
1193 }
1194
1195 for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
1196
1197 p_properties->push_back(E->get());
1198 }
1199 }
1200
get_method_list(List<MethodInfo> * p_list) const1201 void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
1202
1203 const GDScript *sptr = script.ptr();
1204 while (sptr) {
1205
1206 for (Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.front(); E; E = E->next()) {
1207
1208 MethodInfo mi;
1209 mi.name = E->key();
1210 mi.flags |= METHOD_FLAG_FROM_SCRIPT;
1211 for (int i = 0; i < E->get()->get_argument_count(); i++)
1212 mi.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i)));
1213 p_list->push_back(mi);
1214 }
1215 sptr = sptr->_base;
1216 }
1217 }
1218
has_method(const StringName & p_method) const1219 bool GDScriptInstance::has_method(const StringName &p_method) const {
1220
1221 const GDScript *sptr = script.ptr();
1222 while (sptr) {
1223 const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
1224 if (E)
1225 return true;
1226 sptr = sptr->_base;
1227 }
1228
1229 return false;
1230 }
call(const StringName & p_method,const Variant ** p_args,int p_argcount,Variant::CallError & r_error)1231 Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
1232
1233 GDScript *sptr = script.ptr();
1234 while (sptr) {
1235 Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
1236 if (E) {
1237 return E->get()->call(this, p_args, p_argcount, r_error);
1238 }
1239 sptr = sptr->_base;
1240 }
1241 r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
1242 return Variant();
1243 }
1244
call_multilevel(const StringName & p_method,const Variant ** p_args,int p_argcount)1245 void GDScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
1246
1247 GDScript *sptr = script.ptr();
1248 Variant::CallError ce;
1249
1250 while (sptr) {
1251 Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
1252 if (E) {
1253 E->get()->call(this, p_args, p_argcount, ce);
1254 }
1255 sptr = sptr->_base;
1256 }
1257 }
1258
_ml_call_reversed(GDScript * sptr,const StringName & p_method,const Variant ** p_args,int p_argcount)1259 void GDScriptInstance::_ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount) {
1260
1261 if (sptr->_base)
1262 _ml_call_reversed(sptr->_base, p_method, p_args, p_argcount);
1263
1264 Variant::CallError ce;
1265
1266 Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
1267 if (E) {
1268 E->get()->call(this, p_args, p_argcount, ce);
1269 }
1270 }
1271
call_multilevel_reversed(const StringName & p_method,const Variant ** p_args,int p_argcount)1272 void GDScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
1273
1274 if (script.ptr()) {
1275 _ml_call_reversed(script.ptr(), p_method, p_args, p_argcount);
1276 }
1277 }
1278
notification(int p_notification)1279 void GDScriptInstance::notification(int p_notification) {
1280
1281 //notification is not virtual, it gets called at ALL levels just like in C.
1282 Variant value = p_notification;
1283 const Variant *args[1] = { &value };
1284
1285 GDScript *sptr = script.ptr();
1286 while (sptr) {
1287 Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification);
1288 if (E) {
1289 Variant::CallError err;
1290 E->get()->call(this, args, 1, err);
1291 if (err.error != Variant::CallError::CALL_OK) {
1292 //print error about notification call
1293 }
1294 }
1295 sptr = sptr->_base;
1296 }
1297 }
1298
to_string(bool * r_valid)1299 String GDScriptInstance::to_string(bool *r_valid) {
1300 if (has_method(CoreStringNames::get_singleton()->_to_string)) {
1301 Variant::CallError ce;
1302 Variant ret = call(CoreStringNames::get_singleton()->_to_string, NULL, 0, ce);
1303 if (ce.error == Variant::CallError::CALL_OK) {
1304 if (ret.get_type() != Variant::STRING) {
1305 if (r_valid)
1306 *r_valid = false;
1307 ERR_FAIL_V_MSG(String(), "Wrong type for " + CoreStringNames::get_singleton()->_to_string + ", must be a String.");
1308 }
1309 if (r_valid)
1310 *r_valid = true;
1311 return ret.operator String();
1312 }
1313 }
1314 if (r_valid)
1315 *r_valid = false;
1316 return String();
1317 }
1318
get_script() const1319 Ref<Script> GDScriptInstance::get_script() const {
1320
1321 return script;
1322 }
1323
get_language()1324 ScriptLanguage *GDScriptInstance::get_language() {
1325
1326 return GDScriptLanguage::get_singleton();
1327 }
1328
get_rpc_mode(const StringName & p_method) const1329 MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode(const StringName &p_method) const {
1330
1331 const GDScript *cscript = script.ptr();
1332
1333 while (cscript) {
1334 const Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.find(p_method);
1335 if (E) {
1336
1337 if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) {
1338 return E->get()->get_rpc_mode();
1339 }
1340 }
1341 cscript = cscript->_base;
1342 }
1343
1344 return MultiplayerAPI::RPC_MODE_DISABLED;
1345 }
1346
get_rset_mode(const StringName & p_variable) const1347 MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_variable) const {
1348
1349 const GDScript *cscript = script.ptr();
1350
1351 while (cscript) {
1352 const Map<StringName, GDScript::MemberInfo>::Element *E = cscript->member_indices.find(p_variable);
1353 if (E) {
1354
1355 if (E->get().rpc_mode) {
1356 return E->get().rpc_mode;
1357 }
1358 }
1359 cscript = cscript->_base;
1360 }
1361
1362 return MultiplayerAPI::RPC_MODE_DISABLED;
1363 }
1364
reload_members()1365 void GDScriptInstance::reload_members() {
1366
1367 #ifdef DEBUG_ENABLED
1368
1369 members.resize(script->member_indices.size()); //resize
1370
1371 Vector<Variant> new_members;
1372 new_members.resize(script->member_indices.size());
1373
1374 //pass the values to the new indices
1375 for (Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.front(); E; E = E->next()) {
1376
1377 if (member_indices_cache.has(E->key())) {
1378 Variant value = members[member_indices_cache[E->key()]];
1379 new_members.write[E->get().index] = value;
1380 }
1381 }
1382
1383 //apply
1384 members = new_members;
1385
1386 //pass the values to the new indices
1387 member_indices_cache.clear();
1388 for (Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.front(); E; E = E->next()) {
1389
1390 member_indices_cache[E->key()] = E->get().index;
1391 }
1392
1393 #endif
1394 }
1395
GDScriptInstance()1396 GDScriptInstance::GDScriptInstance() {
1397 owner = NULL;
1398 base_ref = false;
1399 }
1400
~GDScriptInstance()1401 GDScriptInstance::~GDScriptInstance() {
1402 #ifndef NO_THREADS
1403 GDScriptLanguage::singleton->lock->lock();
1404 #endif
1405
1406 while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
1407 E->self()->_clear_stack();
1408 pending_func_states.remove(E);
1409 }
1410
1411 if (script.is_valid() && owner) {
1412 script->instances.erase(owner);
1413 }
1414
1415 #ifndef NO_THREADS
1416 GDScriptLanguage::singleton->lock->unlock();
1417 #endif
1418 }
1419
1420 /************* SCRIPT LANGUAGE **************/
1421
1422 GDScriptLanguage *GDScriptLanguage::singleton = NULL;
1423
get_name() const1424 String GDScriptLanguage::get_name() const {
1425
1426 return "GDScript";
1427 }
1428
1429 /* LANGUAGE FUNCTIONS */
1430
_add_global(const StringName & p_name,const Variant & p_value)1431 void GDScriptLanguage::_add_global(const StringName &p_name, const Variant &p_value) {
1432
1433 if (globals.has(p_name)) {
1434 //overwrite existing
1435 global_array.write[globals[p_name]] = p_value;
1436 return;
1437 }
1438 globals[p_name] = global_array.size();
1439 global_array.push_back(p_value);
1440 _global_array = global_array.ptrw();
1441 }
1442
add_global_constant(const StringName & p_variable,const Variant & p_value)1443 void GDScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) {
1444
1445 _add_global(p_variable, p_value);
1446 }
1447
add_named_global_constant(const StringName & p_name,const Variant & p_value)1448 void GDScriptLanguage::add_named_global_constant(const StringName &p_name, const Variant &p_value) {
1449 named_globals[p_name] = p_value;
1450 }
1451
remove_named_global_constant(const StringName & p_name)1452 void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) {
1453 ERR_FAIL_COND(!named_globals.has(p_name));
1454 named_globals.erase(p_name);
1455 }
1456
init()1457 void GDScriptLanguage::init() {
1458
1459 //populate global constants
1460 int gcc = GlobalConstants::get_global_constant_count();
1461 for (int i = 0; i < gcc; i++) {
1462
1463 _add_global(StaticCString::create(GlobalConstants::get_global_constant_name(i)), GlobalConstants::get_global_constant_value(i));
1464 }
1465
1466 _add_global(StaticCString::create("PI"), Math_PI);
1467 _add_global(StaticCString::create("TAU"), Math_TAU);
1468 _add_global(StaticCString::create("INF"), Math_INF);
1469 _add_global(StaticCString::create("NAN"), Math_NAN);
1470
1471 //populate native classes
1472
1473 List<StringName> class_list;
1474 ClassDB::get_class_list(&class_list);
1475 for (List<StringName>::Element *E = class_list.front(); E; E = E->next()) {
1476
1477 StringName n = E->get();
1478 String s = String(n);
1479 if (s.begins_with("_"))
1480 n = s.substr(1, s.length());
1481
1482 if (globals.has(n))
1483 continue;
1484 Ref<GDScriptNativeClass> nc = memnew(GDScriptNativeClass(E->get()));
1485 _add_global(n, nc);
1486 }
1487
1488 //populate singletons
1489
1490 List<Engine::Singleton> singletons;
1491 Engine::get_singleton()->get_singletons(&singletons);
1492 for (List<Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) {
1493
1494 _add_global(E->get().name, E->get().ptr);
1495 }
1496 }
1497
get_type() const1498 String GDScriptLanguage::get_type() const {
1499
1500 return "GDScript";
1501 }
get_extension() const1502 String GDScriptLanguage::get_extension() const {
1503
1504 return "gd";
1505 }
execute_file(const String & p_path)1506 Error GDScriptLanguage::execute_file(const String &p_path) {
1507
1508 // ??
1509 return OK;
1510 }
finish()1511 void GDScriptLanguage::finish() {
1512 }
1513
profiling_start()1514 void GDScriptLanguage::profiling_start() {
1515
1516 #ifdef DEBUG_ENABLED
1517 if (lock) {
1518 lock->lock();
1519 }
1520
1521 SelfList<GDScriptFunction> *elem = function_list.first();
1522 while (elem) {
1523 elem->self()->profile.call_count = 0;
1524 elem->self()->profile.self_time = 0;
1525 elem->self()->profile.total_time = 0;
1526 elem->self()->profile.frame_call_count = 0;
1527 elem->self()->profile.frame_self_time = 0;
1528 elem->self()->profile.frame_total_time = 0;
1529 elem->self()->profile.last_frame_call_count = 0;
1530 elem->self()->profile.last_frame_self_time = 0;
1531 elem->self()->profile.last_frame_total_time = 0;
1532 elem = elem->next();
1533 }
1534
1535 profiling = true;
1536 if (lock) {
1537 lock->unlock();
1538 }
1539
1540 #endif
1541 }
1542
profiling_stop()1543 void GDScriptLanguage::profiling_stop() {
1544
1545 #ifdef DEBUG_ENABLED
1546 if (lock) {
1547 lock->lock();
1548 }
1549
1550 profiling = false;
1551 if (lock) {
1552 lock->unlock();
1553 }
1554
1555 #endif
1556 }
1557
profiling_get_accumulated_data(ProfilingInfo * p_info_arr,int p_info_max)1558 int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) {
1559
1560 int current = 0;
1561 #ifdef DEBUG_ENABLED
1562 if (lock) {
1563 lock->lock();
1564 }
1565
1566 SelfList<GDScriptFunction> *elem = function_list.first();
1567 while (elem) {
1568 if (current >= p_info_max)
1569 break;
1570 p_info_arr[current].call_count = elem->self()->profile.call_count;
1571 p_info_arr[current].self_time = elem->self()->profile.self_time;
1572 p_info_arr[current].total_time = elem->self()->profile.total_time;
1573 p_info_arr[current].signature = elem->self()->profile.signature;
1574 elem = elem->next();
1575 current++;
1576 }
1577
1578 if (lock) {
1579 lock->unlock();
1580 }
1581
1582 #endif
1583
1584 return current;
1585 }
1586
profiling_get_frame_data(ProfilingInfo * p_info_arr,int p_info_max)1587 int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) {
1588
1589 int current = 0;
1590
1591 #ifdef DEBUG_ENABLED
1592 if (lock) {
1593 lock->lock();
1594 }
1595
1596 SelfList<GDScriptFunction> *elem = function_list.first();
1597 while (elem) {
1598 if (current >= p_info_max)
1599 break;
1600 if (elem->self()->profile.last_frame_call_count > 0) {
1601 p_info_arr[current].call_count = elem->self()->profile.last_frame_call_count;
1602 p_info_arr[current].self_time = elem->self()->profile.last_frame_self_time;
1603 p_info_arr[current].total_time = elem->self()->profile.last_frame_total_time;
1604 p_info_arr[current].signature = elem->self()->profile.signature;
1605 current++;
1606 }
1607 elem = elem->next();
1608 }
1609
1610 if (lock) {
1611 lock->unlock();
1612 }
1613
1614 #endif
1615
1616 return current;
1617 }
1618
1619 struct GDScriptDepSort {
1620
1621 //must support sorting so inheritance works properly (parent must be reloaded first)
operator ()GDScriptDepSort1622 bool operator()(const Ref<GDScript> &A, const Ref<GDScript> &B) const {
1623
1624 if (A == B)
1625 return false; //shouldn't happen but..
1626 const GDScript *I = B->get_base().ptr();
1627 while (I) {
1628 if (I == A.ptr()) {
1629 // A is a base of B
1630 return true;
1631 }
1632
1633 I = I->get_base().ptr();
1634 }
1635
1636 return false; //not a base
1637 }
1638 };
1639
reload_all_scripts()1640 void GDScriptLanguage::reload_all_scripts() {
1641
1642 #ifdef DEBUG_ENABLED
1643 print_verbose("GDScript: Reloading all scripts");
1644 if (lock) {
1645 lock->lock();
1646 }
1647
1648 List<Ref<GDScript> > scripts;
1649
1650 SelfList<GDScript> *elem = script_list.first();
1651 while (elem) {
1652 if (elem->self()->get_path().is_resource_file()) {
1653 print_verbose("GDScript: Found: " + elem->self()->get_path());
1654 scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident
1655 }
1656 elem = elem->next();
1657 }
1658
1659 if (lock) {
1660 lock->unlock();
1661 }
1662
1663 //as scripts are going to be reloaded, must proceed without locking here
1664
1665 scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order
1666
1667 for (List<Ref<GDScript> >::Element *E = scripts.front(); E; E = E->next()) {
1668
1669 print_verbose("GDScript: Reloading: " + E->get()->get_path());
1670 E->get()->load_source_code(E->get()->get_path());
1671 E->get()->reload(true);
1672 }
1673 #endif
1674 }
1675
reload_tool_script(const Ref<Script> & p_script,bool p_soft_reload)1676 void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) {
1677
1678 #ifdef DEBUG_ENABLED
1679
1680 if (lock) {
1681 lock->lock();
1682 }
1683
1684 List<Ref<GDScript> > scripts;
1685
1686 SelfList<GDScript> *elem = script_list.first();
1687 while (elem) {
1688 if (elem->self()->get_path().is_resource_file()) {
1689
1690 scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident
1691 }
1692 elem = elem->next();
1693 }
1694
1695 if (lock) {
1696 lock->unlock();
1697 }
1698
1699 //when someone asks you why dynamically typed languages are easier to write....
1700
1701 Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant> > > > to_reload;
1702
1703 //as scripts are going to be reloaded, must proceed without locking here
1704
1705 scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order
1706
1707 for (List<Ref<GDScript> >::Element *E = scripts.front(); E; E = E->next()) {
1708
1709 bool reload = E->get() == p_script || to_reload.has(E->get()->get_base());
1710
1711 if (!reload)
1712 continue;
1713
1714 to_reload.insert(E->get(), Map<ObjectID, List<Pair<StringName, Variant> > >());
1715
1716 if (!p_soft_reload) {
1717
1718 //save state and remove script from instances
1719 Map<ObjectID, List<Pair<StringName, Variant> > > &map = to_reload[E->get()];
1720
1721 while (E->get()->instances.front()) {
1722 Object *obj = E->get()->instances.front()->get();
1723 //save instance info
1724 List<Pair<StringName, Variant> > state;
1725 if (obj->get_script_instance()) {
1726
1727 obj->get_script_instance()->get_property_state(state);
1728 map[obj->get_instance_id()] = state;
1729 obj->set_script(RefPtr());
1730 }
1731 }
1732
1733 //same thing for placeholders
1734 #ifdef TOOLS_ENABLED
1735
1736 while (E->get()->placeholders.size()) {
1737 Object *obj = E->get()->placeholders.front()->get()->get_owner();
1738
1739 //save instance info
1740 if (obj->get_script_instance()) {
1741
1742 map.insert(obj->get_instance_id(), List<Pair<StringName, Variant> >());
1743 List<Pair<StringName, Variant> > &state = map[obj->get_instance_id()];
1744 obj->get_script_instance()->get_property_state(state);
1745 obj->set_script(RefPtr());
1746 } else {
1747 // no instance found. Let's remove it so we don't loop forever
1748 E->get()->placeholders.erase(E->get()->placeholders.front()->get());
1749 }
1750 }
1751
1752 #endif
1753
1754 for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get()->pending_reload_state.front(); F; F = F->next()) {
1755 map[F->key()] = F->get(); //pending to reload, use this one instead
1756 }
1757 }
1758 }
1759
1760 for (Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) {
1761
1762 Ref<GDScript> scr = E->key();
1763 scr->reload(p_soft_reload);
1764
1765 //restore state if saved
1766 for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get().front(); F; F = F->next()) {
1767
1768 List<Pair<StringName, Variant> > &saved_state = F->get();
1769
1770 Object *obj = ObjectDB::get_instance(F->key());
1771 if (!obj)
1772 continue;
1773
1774 if (!p_soft_reload) {
1775 //clear it just in case (may be a pending reload state)
1776 obj->set_script(RefPtr());
1777 }
1778 obj->set_script(scr.get_ref_ptr());
1779
1780 ScriptInstance *script_instance = obj->get_script_instance();
1781
1782 if (!script_instance) {
1783 //failed, save reload state for next time if not saved
1784 if (!scr->pending_reload_state.has(obj->get_instance_id())) {
1785 scr->pending_reload_state[obj->get_instance_id()] = saved_state;
1786 }
1787 continue;
1788 }
1789
1790 if (script_instance->is_placeholder() && scr->is_placeholder_fallback_enabled()) {
1791 PlaceHolderScriptInstance *placeholder = static_cast<PlaceHolderScriptInstance *>(script_instance);
1792 for (List<Pair<StringName, Variant> >::Element *G = saved_state.front(); G; G = G->next()) {
1793 placeholder->property_set_fallback(G->get().first, G->get().second);
1794 }
1795 } else {
1796 for (List<Pair<StringName, Variant> >::Element *G = saved_state.front(); G; G = G->next()) {
1797 script_instance->set(G->get().first, G->get().second);
1798 }
1799 }
1800
1801 scr->pending_reload_state.erase(obj->get_instance_id()); //as it reloaded, remove pending state
1802 }
1803
1804 //if instance states were saved, set them!
1805 }
1806
1807 #endif
1808 }
1809
frame()1810 void GDScriptLanguage::frame() {
1811
1812 calls = 0;
1813
1814 #ifdef DEBUG_ENABLED
1815 if (profiling) {
1816 if (lock) {
1817 lock->lock();
1818 }
1819
1820 SelfList<GDScriptFunction> *elem = function_list.first();
1821 while (elem) {
1822 elem->self()->profile.last_frame_call_count = elem->self()->profile.frame_call_count;
1823 elem->self()->profile.last_frame_self_time = elem->self()->profile.frame_self_time;
1824 elem->self()->profile.last_frame_total_time = elem->self()->profile.frame_total_time;
1825 elem->self()->profile.frame_call_count = 0;
1826 elem->self()->profile.frame_self_time = 0;
1827 elem->self()->profile.frame_total_time = 0;
1828 elem = elem->next();
1829 }
1830
1831 if (lock) {
1832 lock->unlock();
1833 }
1834 }
1835
1836 #endif
1837 }
1838
1839 /* EDITOR FUNCTIONS */
get_reserved_words(List<String> * p_words) const1840 void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
1841
1842 static const char *_reserved_words[] = {
1843 // operators
1844 "and",
1845 "in",
1846 "not",
1847 "or",
1848 // types and values
1849 "false",
1850 "float",
1851 "int",
1852 "bool",
1853 "null",
1854 "PI",
1855 "TAU",
1856 "INF",
1857 "NAN",
1858 "self",
1859 "true",
1860 "void",
1861 // functions
1862 "as",
1863 "assert",
1864 "breakpoint",
1865 "class",
1866 "class_name",
1867 "extends",
1868 "is",
1869 "func",
1870 "preload",
1871 "setget",
1872 "signal",
1873 "tool",
1874 "yield",
1875 // var
1876 "const",
1877 "enum",
1878 "export",
1879 "onready",
1880 "static",
1881 "var",
1882 // control flow
1883 "break",
1884 "continue",
1885 "if",
1886 "elif",
1887 "else",
1888 "for",
1889 "pass",
1890 "return",
1891 "match",
1892 "while",
1893 "remote",
1894 "sync",
1895 "master",
1896 "puppet",
1897 "slave",
1898 "remotesync",
1899 "mastersync",
1900 "puppetsync",
1901 0
1902 };
1903
1904 const char **w = _reserved_words;
1905
1906 while (*w) {
1907
1908 p_words->push_back(*w);
1909 w++;
1910 }
1911
1912 for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
1913 p_words->push_back(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i)));
1914 }
1915 }
1916
handles_global_class_type(const String & p_type) const1917 bool GDScriptLanguage::handles_global_class_type(const String &p_type) const {
1918
1919 return p_type == "GDScript";
1920 }
1921
get_global_class_name(const String & p_path,String * r_base_type,String * r_icon_path) const1922 String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const {
1923
1924 PoolVector<uint8_t> sourcef;
1925 Error err;
1926 FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
1927 if (err) {
1928 return String();
1929 }
1930
1931 String source = f->get_as_utf8_string();
1932
1933 GDScriptParser parser;
1934 parser.parse(source, p_path.get_base_dir(), true, p_path, false, NULL, true);
1935
1936 if (parser.get_parse_tree() && parser.get_parse_tree()->type == GDScriptParser::Node::TYPE_CLASS) {
1937
1938 const GDScriptParser::ClassNode *c = static_cast<const GDScriptParser::ClassNode *>(parser.get_parse_tree());
1939 if (r_icon_path) {
1940 if (c->icon_path.empty() || c->icon_path.is_abs_path())
1941 *r_icon_path = c->icon_path;
1942 else if (c->icon_path.is_rel_path())
1943 *r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path();
1944 }
1945 if (r_base_type) {
1946
1947 const GDScriptParser::ClassNode *subclass = c;
1948 String path = p_path;
1949 GDScriptParser subparser;
1950 while (subclass) {
1951 if (subclass->extends_used) {
1952 if (subclass->extends_file) {
1953 if (subclass->extends_class.size() == 0) {
1954 get_global_class_name(subclass->extends_file, r_base_type);
1955 subclass = NULL;
1956 break;
1957 } else {
1958 Vector<StringName> extend_classes = subclass->extends_class;
1959
1960 FileAccessRef subfile = FileAccess::open(subclass->extends_file, FileAccess::READ);
1961 if (!subfile) {
1962 break;
1963 }
1964 String subsource = subfile->get_as_utf8_string();
1965
1966 if (subsource.empty()) {
1967 break;
1968 }
1969 String subpath = subclass->extends_file;
1970 if (subpath.is_rel_path()) {
1971 subpath = path.get_base_dir().plus_file(subpath).simplify_path();
1972 }
1973
1974 if (OK != subparser.parse(subsource, subpath.get_base_dir(), true, subpath, false, NULL, true)) {
1975 break;
1976 }
1977 path = subpath;
1978 if (!subparser.get_parse_tree() || subparser.get_parse_tree()->type != GDScriptParser::Node::TYPE_CLASS) {
1979 break;
1980 }
1981 subclass = static_cast<const GDScriptParser::ClassNode *>(subparser.get_parse_tree());
1982
1983 while (extend_classes.size() > 0) {
1984 bool found = false;
1985 for (int i = 0; i < subclass->subclasses.size(); i++) {
1986 const GDScriptParser::ClassNode *inner_class = subclass->subclasses[i];
1987 if (inner_class->name == extend_classes[0]) {
1988 extend_classes.remove(0);
1989 found = true;
1990 subclass = inner_class;
1991 break;
1992 }
1993 }
1994 if (!found) {
1995 subclass = NULL;
1996 break;
1997 }
1998 }
1999 }
2000 } else if (subclass->extends_class.size() == 1) {
2001 *r_base_type = subclass->extends_class[0];
2002 subclass = NULL;
2003 } else {
2004 break;
2005 }
2006 } else {
2007 *r_base_type = "Reference";
2008 subclass = NULL;
2009 }
2010 }
2011 }
2012 return c->name;
2013 }
2014
2015 return String();
2016 }
2017
2018 #ifdef DEBUG_ENABLED
get_message() const2019 String GDScriptWarning::get_message() const {
2020
2021 #define CHECK_SYMBOLS(m_amount) ERR_FAIL_COND_V(symbols.size() < m_amount, String());
2022
2023 switch (code) {
2024 case UNASSIGNED_VARIABLE_OP_ASSIGN: {
2025 CHECK_SYMBOLS(1);
2026 return "Using assignment with operation but the variable '" + symbols[0] + "' was not previously assigned a value.";
2027 } break;
2028 case UNASSIGNED_VARIABLE: {
2029 CHECK_SYMBOLS(1);
2030 return "The variable '" + symbols[0] + "' was used but never assigned a value.";
2031 } break;
2032 case UNUSED_VARIABLE: {
2033 CHECK_SYMBOLS(1);
2034 return "The local variable '" + symbols[0] + "' is declared but never used in the block. If this is intended, prefix it with an underscore: '_" + symbols[0] + "'";
2035 } break;
2036 case SHADOWED_VARIABLE: {
2037 CHECK_SYMBOLS(2);
2038 return "The local variable '" + symbols[0] + "' is shadowing an already-defined variable at line " + symbols[1] + ".";
2039 } break;
2040 case UNUSED_CLASS_VARIABLE: {
2041 CHECK_SYMBOLS(1);
2042 return "The class variable '" + symbols[0] + "' is declared but never used in the script.";
2043 } break;
2044 case UNUSED_ARGUMENT: {
2045 CHECK_SYMBOLS(2);
2046 return "The argument '" + symbols[1] + "' is never used in the function '" + symbols[0] + "'. If this is intended, prefix it with an underscore: '_" + symbols[1] + "'";
2047 } break;
2048 case UNREACHABLE_CODE: {
2049 CHECK_SYMBOLS(1);
2050 return "Unreachable code (statement after return) in function '" + symbols[0] + "()'.";
2051 } break;
2052 case STANDALONE_EXPRESSION: {
2053 return "Standalone expression (the line has no effect).";
2054 } break;
2055 case VOID_ASSIGNMENT: {
2056 CHECK_SYMBOLS(1);
2057 return "Assignment operation, but the function '" + symbols[0] + "()' returns void.";
2058 } break;
2059 case NARROWING_CONVERSION: {
2060 return "Narrowing conversion (float is converted to int and loses precision).";
2061 } break;
2062 case FUNCTION_MAY_YIELD: {
2063 CHECK_SYMBOLS(1);
2064 return "Assigned variable is typed but the function '" + symbols[0] + "()' may yield and return a GDScriptFunctionState instead.";
2065 } break;
2066 case VARIABLE_CONFLICTS_FUNCTION: {
2067 CHECK_SYMBOLS(1);
2068 return "Variable declaration of '" + symbols[0] + "' conflicts with a function of the same name.";
2069 } break;
2070 case FUNCTION_CONFLICTS_VARIABLE: {
2071 CHECK_SYMBOLS(1);
2072 return "Function declaration of '" + symbols[0] + "()' conflicts with a variable of the same name.";
2073 } break;
2074 case FUNCTION_CONFLICTS_CONSTANT: {
2075 CHECK_SYMBOLS(1);
2076 return "Function declaration of '" + symbols[0] + "()' conflicts with a constant of the same name.";
2077 } break;
2078 case INCOMPATIBLE_TERNARY: {
2079 return "Values of the ternary conditional are not mutually compatible.";
2080 } break;
2081 case UNUSED_SIGNAL: {
2082 CHECK_SYMBOLS(1);
2083 return "The signal '" + symbols[0] + "' is declared but never emitted.";
2084 } break;
2085 case RETURN_VALUE_DISCARDED: {
2086 CHECK_SYMBOLS(1);
2087 return "The function '" + symbols[0] + "()' returns a value, but this value is never used.";
2088 } break;
2089 case PROPERTY_USED_AS_FUNCTION: {
2090 CHECK_SYMBOLS(2);
2091 return "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a property with the same name. Did you mean to access it?";
2092 } break;
2093 case CONSTANT_USED_AS_FUNCTION: {
2094 CHECK_SYMBOLS(2);
2095 return "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a constant with the same name. Did you mean to access it?";
2096 } break;
2097 case FUNCTION_USED_AS_PROPERTY: {
2098 CHECK_SYMBOLS(2);
2099 return "The property '" + symbols[0] + "' was not found in base '" + symbols[1] + "' but there's a method with the same name. Did you mean to call it?";
2100 } break;
2101 case INTEGER_DIVISION: {
2102 return "Integer division, decimal part will be discarded.";
2103 } break;
2104 case UNSAFE_PROPERTY_ACCESS: {
2105 CHECK_SYMBOLS(2);
2106 return "The property '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype).";
2107 } break;
2108 case UNSAFE_METHOD_ACCESS: {
2109 CHECK_SYMBOLS(2);
2110 return "The method '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype).";
2111 } break;
2112 case UNSAFE_CAST: {
2113 CHECK_SYMBOLS(1);
2114 return "The value is cast to '" + symbols[0] + "' but has an unknown type.";
2115 } break;
2116 case UNSAFE_CALL_ARGUMENT: {
2117 CHECK_SYMBOLS(4);
2118 return "The argument '" + symbols[0] + "' of the function '" + symbols[1] + "' requires a the subtype '" + symbols[2] + "' but the supertype '" + symbols[3] + "' was provided";
2119 } break;
2120 case DEPRECATED_KEYWORD: {
2121 CHECK_SYMBOLS(2);
2122 return "The '" + symbols[0] + "' keyword is deprecated and will be removed in a future release, please replace its uses by '" + symbols[1] + "'.";
2123 } break;
2124 case STANDALONE_TERNARY: {
2125 return "Standalone ternary conditional operator: the return value is being discarded.";
2126 }
2127 case WARNING_MAX:
2128 break; // Can't happen, but silences warning
2129 }
2130 ERR_FAIL_V_MSG(String(), "Invalid GDScript warning code: " + get_name_from_code(code) + ".");
2131
2132 #undef CHECK_SYMBOLS
2133 }
2134
get_name() const2135 String GDScriptWarning::get_name() const {
2136 return get_name_from_code(code);
2137 }
2138
get_name_from_code(Code p_code)2139 String GDScriptWarning::get_name_from_code(Code p_code) {
2140 ERR_FAIL_COND_V(p_code < 0 || p_code >= WARNING_MAX, String());
2141
2142 static const char *names[] = {
2143 "UNASSIGNED_VARIABLE",
2144 "UNASSIGNED_VARIABLE_OP_ASSIGN",
2145 "UNUSED_VARIABLE",
2146 "SHADOWED_VARIABLE",
2147 "UNUSED_CLASS_VARIABLE",
2148 "UNUSED_ARGUMENT",
2149 "UNREACHABLE_CODE",
2150 "STANDALONE_EXPRESSION",
2151 "VOID_ASSIGNMENT",
2152 "NARROWING_CONVERSION",
2153 "FUNCTION_MAY_YIELD",
2154 "VARIABLE_CONFLICTS_FUNCTION",
2155 "FUNCTION_CONFLICTS_VARIABLE",
2156 "FUNCTION_CONFLICTS_CONSTANT",
2157 "INCOMPATIBLE_TERNARY",
2158 "UNUSED_SIGNAL",
2159 "RETURN_VALUE_DISCARDED",
2160 "PROPERTY_USED_AS_FUNCTION",
2161 "CONSTANT_USED_AS_FUNCTION",
2162 "FUNCTION_USED_AS_PROPERTY",
2163 "INTEGER_DIVISION",
2164 "UNSAFE_PROPERTY_ACCESS",
2165 "UNSAFE_METHOD_ACCESS",
2166 "UNSAFE_CAST",
2167 "UNSAFE_CALL_ARGUMENT",
2168 "DEPRECATED_KEYWORD",
2169 "STANDALONE_TERNARY",
2170 NULL
2171 };
2172
2173 return names[(int)p_code];
2174 }
2175
get_code_from_name(const String & p_name)2176 GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name) {
2177 for (int i = 0; i < WARNING_MAX; i++) {
2178 if (get_name_from_code((Code)i) == p_name) {
2179 return (Code)i;
2180 }
2181 }
2182
2183 ERR_FAIL_V_MSG(WARNING_MAX, "Invalid GDScript warning name: " + p_name);
2184 }
2185
2186 #endif // DEBUG_ENABLED
2187
GDScriptLanguage()2188 GDScriptLanguage::GDScriptLanguage() {
2189
2190 calls = 0;
2191 ERR_FAIL_COND(singleton);
2192 singleton = this;
2193 strings._init = StaticCString::create("_init");
2194 strings._notification = StaticCString::create("_notification");
2195 strings._set = StaticCString::create("_set");
2196 strings._get = StaticCString::create("_get");
2197 strings._get_property_list = StaticCString::create("_get_property_list");
2198 strings._script_source = StaticCString::create("script/source");
2199 _debug_parse_err_line = -1;
2200 _debug_parse_err_file = "";
2201
2202 #ifdef NO_THREADS
2203 lock = NULL;
2204 #else
2205 lock = Mutex::create();
2206 #endif
2207 profiling = false;
2208 script_frame_time = 0;
2209
2210 _debug_call_stack_pos = 0;
2211 int dmcs = GLOBAL_DEF("debug/settings/gdscript/max_call_stack", 1024);
2212 ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/gdscript/max_call_stack", PropertyInfo(Variant::INT, "debug/settings/gdscript/max_call_stack", PROPERTY_HINT_RANGE, "1024,4096,1,or_greater")); //minimum is 1024
2213
2214 if (ScriptDebugger::get_singleton()) {
2215 //debugging enabled!
2216
2217 _debug_max_call_stack = dmcs;
2218 _call_stack = memnew_arr(CallLevel, _debug_max_call_stack + 1);
2219
2220 } else {
2221 _debug_max_call_stack = 0;
2222 _call_stack = NULL;
2223 }
2224
2225 #ifdef DEBUG_ENABLED
2226 GLOBAL_DEF("debug/gdscript/warnings/enable", true);
2227 GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false);
2228 GLOBAL_DEF("debug/gdscript/warnings/exclude_addons", true);
2229 GLOBAL_DEF("debug/gdscript/completion/autocomplete_setters_and_getters", false);
2230 for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
2231 String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
2232 bool default_enabled = !warning.begins_with("unsafe_") && i != GDScriptWarning::UNUSED_CLASS_VARIABLE;
2233 GLOBAL_DEF("debug/gdscript/warnings/" + warning, default_enabled);
2234 }
2235 #endif // DEBUG_ENABLED
2236 }
2237
~GDScriptLanguage()2238 GDScriptLanguage::~GDScriptLanguage() {
2239
2240 if (lock) {
2241 memdelete(lock);
2242 lock = NULL;
2243 }
2244 if (_call_stack) {
2245 memdelete_arr(_call_stack);
2246 }
2247 singleton = NULL;
2248 }
2249
add_orphan_subclass(const String & p_qualified_name,const ObjectID & p_subclass)2250 void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass) {
2251 orphan_subclasses[p_qualified_name] = p_subclass;
2252 }
2253
get_orphan_subclass(const String & p_qualified_name)2254 Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_name) {
2255 Map<String, ObjectID>::Element *orphan_subclass_element = orphan_subclasses.find(p_qualified_name);
2256 if (!orphan_subclass_element)
2257 return Ref<GDScript>();
2258 ObjectID orphan_subclass = orphan_subclass_element->get();
2259 Object *obj = ObjectDB::get_instance(orphan_subclass);
2260 orphan_subclasses.erase(orphan_subclass_element);
2261 if (!obj)
2262 return Ref<GDScript>();
2263 return Ref<GDScript>(Object::cast_to<GDScript>(obj));
2264 }
2265
2266 /*************** RESOURCE ***************/
2267
load(const String & p_path,const String & p_original_path,Error * r_error)2268 RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error) {
2269
2270 if (r_error)
2271 *r_error = ERR_FILE_CANT_OPEN;
2272
2273 GDScript *script = memnew(GDScript);
2274
2275 Ref<GDScript> scriptres(script);
2276
2277 if (p_path.ends_with(".gde") || p_path.ends_with(".gdc")) {
2278
2279 script->set_script_path(p_original_path); // script needs this.
2280 script->set_path(p_original_path);
2281 Error err = script->load_byte_code(p_path);
2282 ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load byte code from file '" + p_path + "'.");
2283
2284 } else {
2285 Error err = script->load_source_code(p_path);
2286 ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load source code from file '" + p_path + "'.");
2287
2288 script->set_script_path(p_original_path); // script needs this.
2289 script->set_path(p_original_path);
2290
2291 script->reload();
2292 }
2293 if (r_error)
2294 *r_error = OK;
2295
2296 return scriptres;
2297 }
2298
get_recognized_extensions(List<String> * p_extensions) const2299 void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const {
2300
2301 p_extensions->push_back("gd");
2302 p_extensions->push_back("gdc");
2303 p_extensions->push_back("gde");
2304 }
2305
handles_type(const String & p_type) const2306 bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const {
2307
2308 return (p_type == "Script" || p_type == "GDScript");
2309 }
2310
get_resource_type(const String & p_path) const2311 String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {
2312
2313 String el = p_path.get_extension().to_lower();
2314 if (el == "gd" || el == "gdc" || el == "gde")
2315 return "GDScript";
2316 return "";
2317 }
2318
get_dependencies(const String & p_path,List<String> * p_dependencies,bool p_add_types)2319 void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
2320
2321 FileAccessRef file = FileAccess::open(p_path, FileAccess::READ);
2322 ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_path + "'.");
2323
2324 String source = file->get_as_utf8_string();
2325 if (source.empty()) {
2326 return;
2327 }
2328
2329 GDScriptParser parser;
2330 if (OK != parser.parse(source, p_path.get_base_dir(), true, p_path, false, NULL, true)) {
2331 return;
2332 }
2333
2334 for (const List<String>::Element *E = parser.get_dependencies().front(); E; E = E->next()) {
2335 p_dependencies->push_back(E->get());
2336 }
2337 }
2338
save(const String & p_path,const RES & p_resource,uint32_t p_flags)2339 Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
2340
2341 Ref<GDScript> sqscr = p_resource;
2342 ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
2343
2344 String source = sqscr->get_source_code();
2345
2346 Error err;
2347 FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
2348
2349 ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'.");
2350
2351 file->store_string(source);
2352 if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
2353 memdelete(file);
2354 return ERR_CANT_CREATE;
2355 }
2356 file->close();
2357 memdelete(file);
2358
2359 if (ScriptServer::is_reload_scripts_on_save_enabled()) {
2360 GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, false);
2361 }
2362
2363 return OK;
2364 }
2365
get_recognized_extensions(const RES & p_resource,List<String> * p_extensions) const2366 void ResourceFormatSaverGDScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
2367
2368 if (Object::cast_to<GDScript>(*p_resource)) {
2369 p_extensions->push_back("gd");
2370 }
2371 }
recognize(const RES & p_resource) const2372 bool ResourceFormatSaverGDScript::recognize(const RES &p_resource) const {
2373
2374 return Object::cast_to<GDScript>(*p_resource) != NULL;
2375 }
2376