1 /*************************************************************************/
2 /*  script_language.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 "script_language.h"
32 
33 #include "core/core_string_names.h"
34 #include "core/project_settings.h"
35 
36 ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
37 int ScriptServer::_language_count = 0;
38 
39 bool ScriptServer::scripting_enabled = true;
40 bool ScriptServer::reload_scripts_on_save = false;
41 bool ScriptServer::languages_finished = false;
42 ScriptEditRequestFunction ScriptServer::edit_request_func = NULL;
43 
_notification(int p_what)44 void Script::_notification(int p_what) {
45 
46 	if (p_what == NOTIFICATION_POSTINITIALIZE) {
47 
48 		if (ScriptDebugger::get_singleton())
49 			ScriptDebugger::get_singleton()->set_break_language(get_language());
50 	}
51 }
52 
_get_property_default_value(const StringName & p_property)53 Variant Script::_get_property_default_value(const StringName &p_property) {
54 	Variant ret;
55 	get_property_default_value(p_property, ret);
56 	return ret;
57 }
58 
_get_script_property_list()59 Array Script::_get_script_property_list() {
60 	Array ret;
61 	List<PropertyInfo> list;
62 	get_script_property_list(&list);
63 	for (List<PropertyInfo>::Element *E = list.front(); E; E = E->next()) {
64 		ret.append(E->get().operator Dictionary());
65 	}
66 	return ret;
67 }
68 
_get_script_method_list()69 Array Script::_get_script_method_list() {
70 	Array ret;
71 	List<MethodInfo> list;
72 	get_script_method_list(&list);
73 	for (List<MethodInfo>::Element *E = list.front(); E; E = E->next()) {
74 		ret.append(E->get().operator Dictionary());
75 	}
76 	return ret;
77 }
78 
_get_script_signal_list()79 Array Script::_get_script_signal_list() {
80 	Array ret;
81 	List<MethodInfo> list;
82 	get_script_signal_list(&list);
83 	for (List<MethodInfo>::Element *E = list.front(); E; E = E->next()) {
84 		ret.append(E->get().operator Dictionary());
85 	}
86 	return ret;
87 }
88 
_get_script_constant_map()89 Dictionary Script::_get_script_constant_map() {
90 	Dictionary ret;
91 	Map<StringName, Variant> map;
92 	get_constants(&map);
93 	for (Map<StringName, Variant>::Element *E = map.front(); E; E = E->next()) {
94 		ret[E->key()] = E->value();
95 	}
96 	return ret;
97 }
98 
_bind_methods()99 void Script::_bind_methods() {
100 
101 	ClassDB::bind_method(D_METHOD("can_instance"), &Script::can_instance);
102 	//ClassDB::bind_method(D_METHOD("instance_create","base_object"),&Script::instance_create);
103 	ClassDB::bind_method(D_METHOD("instance_has", "base_object"), &Script::instance_has);
104 	ClassDB::bind_method(D_METHOD("has_source_code"), &Script::has_source_code);
105 	ClassDB::bind_method(D_METHOD("get_source_code"), &Script::get_source_code);
106 	ClassDB::bind_method(D_METHOD("set_source_code", "source"), &Script::set_source_code);
107 	ClassDB::bind_method(D_METHOD("reload", "keep_state"), &Script::reload, DEFVAL(false));
108 	ClassDB::bind_method(D_METHOD("get_base_script"), &Script::get_base_script);
109 	ClassDB::bind_method(D_METHOD("get_instance_base_type"), &Script::get_instance_base_type);
110 
111 	ClassDB::bind_method(D_METHOD("has_script_signal", "signal_name"), &Script::has_script_signal);
112 
113 	ClassDB::bind_method(D_METHOD("get_script_property_list"), &Script::_get_script_property_list);
114 	ClassDB::bind_method(D_METHOD("get_script_method_list"), &Script::_get_script_method_list);
115 	ClassDB::bind_method(D_METHOD("get_script_signal_list"), &Script::_get_script_signal_list);
116 	ClassDB::bind_method(D_METHOD("get_script_constant_map"), &Script::_get_script_constant_map);
117 	ClassDB::bind_method(D_METHOD("get_property_default_value", "property"), &Script::_get_property_default_value);
118 
119 	ClassDB::bind_method(D_METHOD("is_tool"), &Script::is_tool);
120 
121 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", 0), "set_source_code", "get_source_code");
122 }
123 
set_scripting_enabled(bool p_enabled)124 void ScriptServer::set_scripting_enabled(bool p_enabled) {
125 
126 	scripting_enabled = p_enabled;
127 }
128 
is_scripting_enabled()129 bool ScriptServer::is_scripting_enabled() {
130 
131 	return scripting_enabled;
132 }
133 
get_language(int p_idx)134 ScriptLanguage *ScriptServer::get_language(int p_idx) {
135 
136 	ERR_FAIL_INDEX_V(p_idx, _language_count, NULL);
137 
138 	return _languages[p_idx];
139 }
140 
register_language(ScriptLanguage * p_language)141 void ScriptServer::register_language(ScriptLanguage *p_language) {
142 
143 	ERR_FAIL_COND(_language_count >= MAX_LANGUAGES);
144 	_languages[_language_count++] = p_language;
145 }
146 
unregister_language(ScriptLanguage * p_language)147 void ScriptServer::unregister_language(ScriptLanguage *p_language) {
148 
149 	for (int i = 0; i < _language_count; i++) {
150 		if (_languages[i] == p_language) {
151 			_language_count--;
152 			if (i < _language_count) {
153 				SWAP(_languages[i], _languages[_language_count]);
154 			}
155 			return;
156 		}
157 	}
158 }
159 
init_languages()160 void ScriptServer::init_languages() {
161 
162 	{ //load global classes
163 		global_classes_clear();
164 		if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
165 			Array script_classes = ProjectSettings::get_singleton()->get("_global_script_classes");
166 
167 			for (int i = 0; i < script_classes.size(); i++) {
168 				Dictionary c = script_classes[i];
169 				if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base"))
170 					continue;
171 				add_global_class(c["class"], c["base"], c["language"], c["path"]);
172 			}
173 		}
174 	}
175 
176 	for (int i = 0; i < _language_count; i++) {
177 		_languages[i]->init();
178 	}
179 }
180 
finish_languages()181 void ScriptServer::finish_languages() {
182 
183 	for (int i = 0; i < _language_count; i++) {
184 		_languages[i]->finish();
185 	}
186 	global_classes_clear();
187 	languages_finished = true;
188 }
189 
set_reload_scripts_on_save(bool p_enable)190 void ScriptServer::set_reload_scripts_on_save(bool p_enable) {
191 
192 	reload_scripts_on_save = p_enable;
193 }
194 
is_reload_scripts_on_save_enabled()195 bool ScriptServer::is_reload_scripts_on_save_enabled() {
196 
197 	return reload_scripts_on_save;
198 }
199 
thread_enter()200 void ScriptServer::thread_enter() {
201 
202 	for (int i = 0; i < _language_count; i++) {
203 		_languages[i]->thread_enter();
204 	}
205 }
206 
thread_exit()207 void ScriptServer::thread_exit() {
208 
209 	for (int i = 0; i < _language_count; i++) {
210 		_languages[i]->thread_exit();
211 	}
212 }
213 
214 HashMap<StringName, ScriptServer::GlobalScriptClass> ScriptServer::global_classes;
215 
global_classes_clear()216 void ScriptServer::global_classes_clear() {
217 	global_classes.clear();
218 }
219 
add_global_class(const StringName & p_class,const StringName & p_base,const StringName & p_language,const String & p_path)220 void ScriptServer::add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path) {
221 	ERR_FAIL_COND_MSG(p_class == p_base || (global_classes.has(p_base) && get_global_class_native_base(p_base) == p_class), "Cyclic inheritance in script class.");
222 	GlobalScriptClass g;
223 	g.language = p_language;
224 	g.path = p_path;
225 	g.base = p_base;
226 	global_classes[p_class] = g;
227 }
remove_global_class(const StringName & p_class)228 void ScriptServer::remove_global_class(const StringName &p_class) {
229 	global_classes.erase(p_class);
230 }
is_global_class(const StringName & p_class)231 bool ScriptServer::is_global_class(const StringName &p_class) {
232 	return global_classes.has(p_class);
233 }
get_global_class_language(const StringName & p_class)234 StringName ScriptServer::get_global_class_language(const StringName &p_class) {
235 	ERR_FAIL_COND_V(!global_classes.has(p_class), StringName());
236 	return global_classes[p_class].language;
237 }
get_global_class_path(const String & p_class)238 String ScriptServer::get_global_class_path(const String &p_class) {
239 	ERR_FAIL_COND_V(!global_classes.has(p_class), String());
240 	return global_classes[p_class].path;
241 }
242 
get_global_class_base(const String & p_class)243 StringName ScriptServer::get_global_class_base(const String &p_class) {
244 	ERR_FAIL_COND_V(!global_classes.has(p_class), String());
245 	return global_classes[p_class].base;
246 }
get_global_class_native_base(const String & p_class)247 StringName ScriptServer::get_global_class_native_base(const String &p_class) {
248 	ERR_FAIL_COND_V(!global_classes.has(p_class), String());
249 	String base = global_classes[p_class].base;
250 	while (global_classes.has(base)) {
251 		base = global_classes[base].base;
252 	}
253 	return base;
254 }
get_global_class_list(List<StringName> * r_global_classes)255 void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) {
256 	const StringName *K = NULL;
257 	List<StringName> classes;
258 	while ((K = global_classes.next(K))) {
259 		classes.push_back(*K);
260 	}
261 	classes.sort_custom<StringName::AlphCompare>();
262 	for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {
263 		r_global_classes->push_back(E->get());
264 	}
265 }
save_global_classes()266 void ScriptServer::save_global_classes() {
267 	List<StringName> gc;
268 	get_global_class_list(&gc);
269 	Array gcarr;
270 	for (List<StringName>::Element *E = gc.front(); E; E = E->next()) {
271 		Dictionary d;
272 		d["class"] = E->get();
273 		d["language"] = global_classes[E->get()].language;
274 		d["path"] = global_classes[E->get()].path;
275 		d["base"] = global_classes[E->get()].base;
276 		gcarr.push_back(d);
277 	}
278 
279 	ProjectSettings::get_singleton()->set("_global_script_classes", gcarr);
280 	ProjectSettings::get_singleton()->save();
281 }
282 
283 ////////////////////
get_property_state(List<Pair<StringName,Variant>> & state)284 void ScriptInstance::get_property_state(List<Pair<StringName, Variant> > &state) {
285 
286 	List<PropertyInfo> pinfo;
287 	get_property_list(&pinfo);
288 	for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
289 
290 		if (E->get().usage & PROPERTY_USAGE_STORAGE) {
291 			Pair<StringName, Variant> p;
292 			p.first = E->get().name;
293 			if (get(p.first, p.second))
294 				state.push_back(p);
295 		}
296 	}
297 }
298 
call(const StringName & p_method,VARIANT_ARG_DECLARE)299 Variant ScriptInstance::call(const StringName &p_method, VARIANT_ARG_DECLARE) {
300 
301 	VARIANT_ARGPTRS;
302 	int argc = 0;
303 	for (int i = 0; i < VARIANT_ARG_MAX; i++) {
304 		if (argptr[i]->get_type() == Variant::NIL)
305 			break;
306 		argc++;
307 	}
308 
309 	Variant::CallError error;
310 	return call(p_method, argptr, argc, error);
311 }
312 
call_multilevel(const StringName & p_method,const Variant ** p_args,int p_argcount)313 void ScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
314 	Variant::CallError ce;
315 	call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls
316 }
317 
call_multilevel_reversed(const StringName & p_method,const Variant ** p_args,int p_argcount)318 void ScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
319 	Variant::CallError ce;
320 	call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls
321 }
322 
property_set_fallback(const StringName &,const Variant &,bool * r_valid)323 void ScriptInstance::property_set_fallback(const StringName &, const Variant &, bool *r_valid) {
324 	if (r_valid)
325 		*r_valid = false;
326 }
327 
property_get_fallback(const StringName &,bool * r_valid)328 Variant ScriptInstance::property_get_fallback(const StringName &, bool *r_valid) {
329 	if (r_valid)
330 		*r_valid = false;
331 	return Variant();
332 }
333 
call_multilevel(const StringName & p_method,VARIANT_ARG_DECLARE)334 void ScriptInstance::call_multilevel(const StringName &p_method, VARIANT_ARG_DECLARE) {
335 
336 	VARIANT_ARGPTRS;
337 	int argc = 0;
338 	for (int i = 0; i < VARIANT_ARG_MAX; i++) {
339 		if (argptr[i]->get_type() == Variant::NIL)
340 			break;
341 		argc++;
342 	}
343 
344 	call_multilevel(p_method, argptr, argc);
345 }
346 
~ScriptInstance()347 ScriptInstance::~ScriptInstance() {
348 }
349 
350 ScriptCodeCompletionCache *ScriptCodeCompletionCache::singleton = NULL;
ScriptCodeCompletionCache()351 ScriptCodeCompletionCache::ScriptCodeCompletionCache() {
352 	singleton = this;
353 }
354 
frame()355 void ScriptLanguage::frame() {
356 }
357 
358 ScriptDebugger *ScriptDebugger::singleton = NULL;
359 
set_lines_left(int p_left)360 void ScriptDebugger::set_lines_left(int p_left) {
361 
362 	lines_left = p_left;
363 }
364 
get_lines_left() const365 int ScriptDebugger::get_lines_left() const {
366 
367 	return lines_left;
368 }
369 
set_depth(int p_depth)370 void ScriptDebugger::set_depth(int p_depth) {
371 
372 	depth = p_depth;
373 }
374 
get_depth() const375 int ScriptDebugger::get_depth() const {
376 
377 	return depth;
378 }
379 
insert_breakpoint(int p_line,const StringName & p_source)380 void ScriptDebugger::insert_breakpoint(int p_line, const StringName &p_source) {
381 
382 	if (!breakpoints.has(p_line))
383 		breakpoints[p_line] = Set<StringName>();
384 	breakpoints[p_line].insert(p_source);
385 }
386 
remove_breakpoint(int p_line,const StringName & p_source)387 void ScriptDebugger::remove_breakpoint(int p_line, const StringName &p_source) {
388 
389 	if (!breakpoints.has(p_line))
390 		return;
391 
392 	breakpoints[p_line].erase(p_source);
393 	if (breakpoints[p_line].size() == 0)
394 		breakpoints.erase(p_line);
395 }
is_breakpoint(int p_line,const StringName & p_source) const396 bool ScriptDebugger::is_breakpoint(int p_line, const StringName &p_source) const {
397 
398 	if (!breakpoints.has(p_line))
399 		return false;
400 	return breakpoints[p_line].has(p_source);
401 }
is_breakpoint_line(int p_line) const402 bool ScriptDebugger::is_breakpoint_line(int p_line) const {
403 
404 	return breakpoints.has(p_line);
405 }
406 
breakpoint_find_source(const String & p_source) const407 String ScriptDebugger::breakpoint_find_source(const String &p_source) const {
408 
409 	return p_source;
410 }
411 
clear_breakpoints()412 void ScriptDebugger::clear_breakpoints() {
413 
414 	breakpoints.clear();
415 }
416 
idle_poll()417 void ScriptDebugger::idle_poll() {
418 }
419 
line_poll()420 void ScriptDebugger::line_poll() {
421 }
422 
set_break_language(ScriptLanguage * p_lang)423 void ScriptDebugger::set_break_language(ScriptLanguage *p_lang) {
424 
425 	break_lang = p_lang;
426 }
427 
get_break_language() const428 ScriptLanguage *ScriptDebugger::get_break_language() const {
429 
430 	return break_lang;
431 }
432 
ScriptDebugger()433 ScriptDebugger::ScriptDebugger() {
434 
435 	singleton = this;
436 	lines_left = -1;
437 	depth = -1;
438 	break_lang = NULL;
439 }
440 
set(const StringName & p_name,const Variant & p_value)441 bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_value) {
442 
443 	if (script->is_placeholder_fallback_enabled())
444 		return false;
445 
446 	if (values.has(p_name)) {
447 		Variant defval;
448 		if (script->get_property_default_value(p_name, defval)) {
449 			if (defval == p_value) {
450 				values.erase(p_name);
451 				return true;
452 			}
453 		}
454 		values[p_name] = p_value;
455 		return true;
456 	} else {
457 		Variant defval;
458 		if (script->get_property_default_value(p_name, defval)) {
459 			if (defval != p_value) {
460 				values[p_name] = p_value;
461 			}
462 			return true;
463 		}
464 	}
465 	return false;
466 }
get(const StringName & p_name,Variant & r_ret) const467 bool PlaceHolderScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
468 
469 	if (values.has(p_name)) {
470 		r_ret = values[p_name];
471 		return true;
472 	}
473 
474 	if (constants.has(p_name)) {
475 		r_ret = constants[p_name];
476 		return true;
477 	}
478 
479 	if (!script->is_placeholder_fallback_enabled()) {
480 		Variant defval;
481 		if (script->get_property_default_value(p_name, defval)) {
482 			r_ret = defval;
483 			return true;
484 		}
485 	}
486 
487 	return false;
488 }
489 
get_property_list(List<PropertyInfo> * p_properties) const490 void PlaceHolderScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
491 
492 	if (script->is_placeholder_fallback_enabled()) {
493 		for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
494 			p_properties->push_back(E->get());
495 		}
496 	} else {
497 		for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
498 			PropertyInfo pinfo = E->get();
499 			if (!values.has(pinfo.name)) {
500 				pinfo.usage |= PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE;
501 			}
502 			p_properties->push_back(E->get());
503 		}
504 	}
505 }
506 
get_property_type(const StringName & p_name,bool * r_is_valid) const507 Variant::Type PlaceHolderScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
508 
509 	if (values.has(p_name)) {
510 		if (r_is_valid)
511 			*r_is_valid = true;
512 		return values[p_name].get_type();
513 	}
514 
515 	if (constants.has(p_name)) {
516 		if (r_is_valid)
517 			*r_is_valid = true;
518 		return constants[p_name].get_type();
519 	}
520 
521 	if (r_is_valid)
522 		*r_is_valid = false;
523 
524 	return Variant::NIL;
525 }
526 
get_method_list(List<MethodInfo> * p_list) const527 void PlaceHolderScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
528 
529 	if (script->is_placeholder_fallback_enabled())
530 		return;
531 
532 	if (script.is_valid()) {
533 		script->get_script_method_list(p_list);
534 	}
535 }
has_method(const StringName & p_method) const536 bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const {
537 
538 	if (script->is_placeholder_fallback_enabled())
539 		return false;
540 
541 	if (script.is_valid()) {
542 		return script->has_method(p_method);
543 	}
544 	return false;
545 }
546 
update(const List<PropertyInfo> & p_properties,const Map<StringName,Variant> & p_values)547 void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, const Map<StringName, Variant> &p_values) {
548 
549 	Set<StringName> new_values;
550 	for (const List<PropertyInfo>::Element *E = p_properties.front(); E; E = E->next()) {
551 
552 		StringName n = E->get().name;
553 		new_values.insert(n);
554 
555 		if (!values.has(n) || values[n].get_type() != E->get().type) {
556 
557 			if (p_values.has(n))
558 				values[n] = p_values[n];
559 		}
560 	}
561 
562 	properties = p_properties;
563 	List<StringName> to_remove;
564 
565 	for (Map<StringName, Variant>::Element *E = values.front(); E; E = E->next()) {
566 
567 		if (!new_values.has(E->key()))
568 			to_remove.push_back(E->key());
569 
570 		Variant defval;
571 		if (script->get_property_default_value(E->key(), defval)) {
572 			//remove because it's the same as the default value
573 			if (defval == E->get()) {
574 				to_remove.push_back(E->key());
575 			}
576 		}
577 	}
578 
579 	while (to_remove.size()) {
580 
581 		values.erase(to_remove.front()->get());
582 		to_remove.pop_front();
583 	}
584 
585 	if (owner && owner->get_script_instance() == this) {
586 
587 		owner->_change_notify();
588 	}
589 	//change notify
590 
591 	constants.clear();
592 	script->get_constants(&constants);
593 }
594 
property_set_fallback(const StringName & p_name,const Variant & p_value,bool * r_valid)595 void PlaceHolderScriptInstance::property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid) {
596 
597 	if (script->is_placeholder_fallback_enabled()) {
598 		Map<StringName, Variant>::Element *E = values.find(p_name);
599 
600 		if (E) {
601 			E->value() = p_value;
602 		} else {
603 			values.insert(p_name, p_value);
604 		}
605 
606 		bool found = false;
607 		for (const List<PropertyInfo>::Element *F = properties.front(); F; F = F->next()) {
608 			if (F->get().name == p_name) {
609 				found = true;
610 				break;
611 			}
612 		}
613 		if (!found) {
614 			properties.push_back(PropertyInfo(p_value.get_type(), p_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_SCRIPT_VARIABLE));
615 		}
616 	}
617 
618 	if (r_valid)
619 		*r_valid = false; // Cannot change the value in either case
620 }
621 
property_get_fallback(const StringName & p_name,bool * r_valid)622 Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_name, bool *r_valid) {
623 
624 	if (script->is_placeholder_fallback_enabled()) {
625 		const Map<StringName, Variant>::Element *E = values.find(p_name);
626 
627 		if (E) {
628 			if (r_valid)
629 				*r_valid = true;
630 			return E->value();
631 		}
632 
633 		E = constants.find(p_name);
634 		if (E) {
635 			if (r_valid)
636 				*r_valid = true;
637 			return E->value();
638 		}
639 	}
640 
641 	if (r_valid)
642 		*r_valid = false;
643 
644 	return Variant();
645 }
646 
PlaceHolderScriptInstance(ScriptLanguage * p_language,Ref<Script> p_script,Object * p_owner)647 PlaceHolderScriptInstance::PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner) :
648 		owner(p_owner),
649 		language(p_language),
650 		script(p_script) {
651 }
652 
~PlaceHolderScriptInstance()653 PlaceHolderScriptInstance::~PlaceHolderScriptInstance() {
654 
655 	if (script.is_valid()) {
656 		script->_placeholder_erased(this);
657 	}
658 }
659