diff options
Diffstat (limited to 'modules/gdscript')
| -rw-r--r-- | modules/gdscript/doc_classes/@GDScript.xml | 1 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_analyzer.cpp | 77 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_analyzer.h | 3 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_byte_codegen.cpp | 8 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_compiler.h | 14 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_editor.cpp | 8 | ||||
| -rw-r--r-- | modules/gdscript/icons/GDScript.svg | 6 | ||||
| -rw-r--r-- | modules/gdscript/tests/test_gdscript.cpp | 76 | 
8 files changed, 150 insertions, 43 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index fc27892099..e170667a30 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -7,6 +7,7 @@  		List of core built-in GDScript functions. Math functions and other utilities. Everything else is provided by objects. (Keywords: builtin, built in, global functions.)  	</description>  	<tutorials> +		<link title="Random number generation">https://docs.godotengine.org/en/latest/tutorials/math/random_number_generation.html</link>  	</tutorials>  	<methods>  		<method name="Color8"> diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 943a49060f..5250115608 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -577,6 +577,12 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas  				GDScriptParser::DataType datatype = member.constant->get_datatype();  				if (member.constant->initializer) { +					if (member.constant->initializer->type == GDScriptParser::Node::ARRAY) { +						const_fold_array(static_cast<GDScriptParser::ArrayNode *>(member.constant->initializer)); +					} else if (member.constant->initializer->type == GDScriptParser::Node::DICTIONARY) { +						const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(member.constant->initializer)); +					} +  					if (!member.constant->initializer->is_constant) {  						push_error(R"(Initializer for a constant must be a constant expression.)", member.constant->initializer);  					} @@ -1113,6 +1119,11 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant  	GDScriptParser::DataType type;  	reduce_expression(p_constant->initializer); +	if (p_constant->initializer->type == GDScriptParser::Node::ARRAY) { +		const_fold_array(static_cast<GDScriptParser::ArrayNode *>(p_constant->initializer)); +	} else if (p_constant->initializer->type == GDScriptParser::Node::DICTIONARY) { +		const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(p_constant->initializer)); +	}  	if (!p_constant->initializer->is_constant) {  		push_error(vformat(R"(Assigned value for constant "%s" isn't a constant expression.)", p_constant->identifier->name), p_constant->initializer); @@ -1422,22 +1433,9 @@ void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expre  }  void GDScriptAnalyzer::reduce_array(GDScriptParser::ArrayNode *p_array) { -	bool all_is_constant = true; -  	for (int i = 0; i < p_array->elements.size(); i++) {  		GDScriptParser::ExpressionNode *element = p_array->elements[i];  		reduce_expression(element); -		all_is_constant = all_is_constant && element->is_constant; -	} - -	if (all_is_constant) { -		Array array; -		array.resize(p_array->elements.size()); -		for (int i = 0; i < p_array->elements.size(); i++) { -			array[i] = p_array->elements[i]->reduced_value; -		} -		p_array->is_constant = true; -		p_array->reduced_value = array;  	}  	// It's array in any case. @@ -1984,8 +1982,6 @@ void GDScriptAnalyzer::reduce_cast(GDScriptParser::CastNode *p_cast) {  }  void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dictionary) { -	bool all_is_constant = true; -  	HashMap<Variant, GDScriptParser::ExpressionNode *, VariantHasher, VariantComparator> elements;  	for (int i = 0; i < p_dictionary->elements.size(); i++) { @@ -1994,7 +1990,6 @@ void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dicti  			reduce_expression(element.key);  		}  		reduce_expression(element.value); -		all_is_constant = all_is_constant && element.key->is_constant && element.value->is_constant;  		if (element.key->is_constant) {  			if (elements.has(element.key->reduced_value)) { @@ -2005,16 +2000,6 @@ void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dicti  		}  	} -	if (all_is_constant) { -		Dictionary dict; -		for (int i = 0; i < p_dictionary->elements.size(); i++) { -			const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i]; -			dict[element.key->reduced_value] = element.value->reduced_value; -		} -		p_dictionary->is_constant = true; -		p_dictionary->reduced_value = dict; -	} -  	// It's dictionary in any case.  	GDScriptParser::DataType dict_type;  	dict_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; @@ -2737,6 +2722,46 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)  	p_unary_op->set_datatype(result);  } +void GDScriptAnalyzer::const_fold_array(GDScriptParser::ArrayNode *p_array) { +	bool all_is_constant = true; + +	for (int i = 0; i < p_array->elements.size(); i++) { +		GDScriptParser::ExpressionNode *element = p_array->elements[i]; +		all_is_constant = all_is_constant && element->is_constant; +		if (!all_is_constant) { +			return; +		} +	} + +	Array array; +	array.resize(p_array->elements.size()); +	for (int i = 0; i < p_array->elements.size(); i++) { +		array[i] = p_array->elements[i]->reduced_value; +	} +	p_array->is_constant = true; +	p_array->reduced_value = array; +} + +void GDScriptAnalyzer::const_fold_dictionary(GDScriptParser::DictionaryNode *p_dictionary) { +	bool all_is_constant = true; + +	for (int i = 0; i < p_dictionary->elements.size(); i++) { +		const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i]; +		all_is_constant = all_is_constant && element.key->is_constant && element.value->is_constant; +		if (!all_is_constant) { +			return; +		} +	} + +	Dictionary dict; +	for (int i = 0; i < p_dictionary->elements.size(); i++) { +		const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i]; +		dict[element.key->reduced_value] = element.value->reduced_value; +	} +	p_dictionary->is_constant = true; +	p_dictionary->reduced_value = dict; +} +  GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source) {  	GDScriptParser::DataType result;  	result.is_constant = true; diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index c3911cce76..f3cbb320b7 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -89,6 +89,9 @@ class GDScriptAnalyzer {  	void reduce_ternary_op(GDScriptParser::TernaryOpNode *p_ternary_op);  	void reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op); +	void const_fold_array(GDScriptParser::ArrayNode *p_array); +	void const_fold_dictionary(GDScriptParser::DictionaryNode *p_dictionary); +  	// Helpers.  	GDScriptParser::DataType type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source);  	GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type) const; diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index eabf53581d..cc9e87b882 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -580,8 +580,8 @@ void GDScriptByteCodeGenerator::write_endif() {  }  void GDScriptByteCodeGenerator::write_for(const Address &p_variable, const Address &p_list) { -	int counter_pos = increase_stack() | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); -	int container_pos = increase_stack() | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); +	int counter_pos = add_temporary() | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); +	int container_pos = add_temporary() | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);  	current_breaks_to_patch.push_back(List<int>()); @@ -629,7 +629,9 @@ void GDScriptByteCodeGenerator::write_endfor() {  	}  	current_breaks_to_patch.pop_back(); -	current_stack_size -= 2; // Remove loop temporaries. +	// Remove loop temporaries. +	pop_temporary(); +	pop_temporary();  }  void GDScriptByteCodeGenerator::start_while_condition() { diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index db02079d26..fe34d6cba3 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -51,12 +51,11 @@ class GDScriptCompiler {  		GDScriptCodeGenerator *generator = nullptr;  		Map<StringName, GDScriptCodeGenerator::Address> parameters;  		Map<StringName, GDScriptCodeGenerator::Address> locals; -		List<Set<StringName>> locals_in_scope; +		List<Map<StringName, GDScriptCodeGenerator::Address>> locals_stack;  		GDScriptCodeGenerator::Address add_local(const StringName &p_name, const GDScriptDataType &p_type) {  			uint32_t addr = generator->add_local(p_name, p_type);  			locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::LOCAL_VARIABLE, addr, p_type); -			locals_in_scope.back()->get().insert(p_name);  			return locals[p_name];  		} @@ -102,17 +101,14 @@ class GDScriptCompiler {  		}  		void start_block() { -			Set<StringName> scope; -			locals_in_scope.push_back(scope); +			Map<StringName, GDScriptCodeGenerator::Address> old_locals = locals; +			locals_stack.push_back(old_locals);  			generator->start_block();  		}  		void end_block() { -			Set<StringName> &scope = locals_in_scope.back()->get(); -			for (Set<StringName>::Element *E = scope.front(); E; E = E->next()) { -				locals.erase(E->get()); -			} -			locals_in_scope.pop_back(); +			locals = locals_stack.back()->get(); +			locals_stack.pop_back();  			generator->end_block();  		}  	}; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 2e372575da..aec05b6771 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -792,6 +792,9 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,  							continue;  						}  						option = ScriptCodeCompletionOption(member.constant->identifier->name, ScriptCodeCompletionOption::KIND_CONSTANT); +						if (member.constant->initializer) { +							option.default_value = member.constant->initializer->reduced_value; +						}  						break;  					case GDScriptParser::ClassNode::Member::CLASS:  						if (p_only_functions) { @@ -2404,6 +2407,11 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path  			Variant::get_constants_for_type(completion_context.builtin_type, &constants);  			for (const List<StringName>::Element *E = constants.front(); E != nullptr; E = E->next()) {  				ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CONSTANT); +				bool valid = false; +				Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E->get(), &valid); +				if (valid) { +					option.default_value = default_value; +				}  				options.insert(option.display, option);  			}  		} break; diff --git a/modules/gdscript/icons/GDScript.svg b/modules/gdscript/icons/GDScript.svg index 953bb9ae9e..aa59125ea9 100644 --- a/modules/gdscript/icons/GDScript.svg +++ b/modules/gdscript/icons/GDScript.svg @@ -1,5 +1 @@ -<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m7 1l-0.56445 2.2578a5 5 0 0 0 -0.68945 0.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -0.28516 0.68555l-2.2539 0.5625v2l2.2578 0.56445a5 5 0 0 0 0.2793 0.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953a5 5 0 0 0 0.68555 0.28516l0.5625 2.2539h2l0.56445-2.2578a5 5 0 0 0 0.6875 -0.2793l1.9902 1.1934 1.4141-1.4141-1.1953-1.9941a5 5 0 0 0 0.28516 -0.68555l2.2539-0.5625v-2l-2.2578-0.56445a5 5 0 0 0 -0.2793 -0.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -0.68555 -0.28516l-0.5625-2.2539h-2zm1 5a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2 -2 2 2 0 0 1 2 -2z" fill="#e0e0e0"/> -</g> -</svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625v2l2.2578.56445a5 5 0 0 0 .2793.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953a5 5 0 0 0 .68555.28516l.5625 2.2539h2l.56445-2.2578a5 5 0 0 0 .6875-.2793l1.9902 1.1934 1.4141-1.4141-1.1953-1.9941a5 5 0 0 0 .28516-.68555l2.2539-.5625v-2l-2.2578-.56445a5 5 0 0 0 -.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2zm1 5a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2-2 2 2 0 0 1 2-2z" fill="#e0e0e0"/></svg> diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp index 68d9984b43..931b683a44 100644 --- a/modules/gdscript/tests/test_gdscript.cpp +++ b/modules/gdscript/tests/test_gdscript.cpp @@ -30,10 +30,13 @@  #include "test_gdscript.h" +#include "core/io/file_access_pack.h"  #include "core/os/file_access.h"  #include "core/os/main_loop.h"  #include "core/os/os.h" +#include "core/project_settings.h"  #include "core/string_builder.h" +#include "scene/resources/packed_scene.h"  #include "modules/gdscript/gdscript_analyzer.h"  #include "modules/gdscript/gdscript_compiler.h" @@ -179,6 +182,60 @@ static void test_compiler(const String &p_code, const String &p_script_path, con  	}  } +void init_autoloads() { +	Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + +	// First pass, add the constants so they exist before any script is loaded. +	for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { +		const ProjectSettings::AutoloadInfo &info = E->get(); + +		if (info.is_singleton) { +			for (int i = 0; i < ScriptServer::get_language_count(); i++) { +				ScriptServer::get_language(i)->add_global_constant(info.name, Variant()); +			} +		} +	} + +	// Second pass, load into global constants. +	for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { +		const ProjectSettings::AutoloadInfo &info = E->get(); + +		if (!info.is_singleton) { +			// Skip non-singletons since we don't have a scene tree here anyway. +			continue; +		} + +		RES res = ResourceLoader::load(info.path); +		ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path); +		Node *n = nullptr; +		if (res->is_class("PackedScene")) { +			Ref<PackedScene> ps = res; +			n = ps->instance(); +		} else if (res->is_class("Script")) { +			Ref<Script> script_res = res; +			StringName ibt = script_res->get_instance_base_type(); +			bool valid_type = ClassDB::is_parent_class(ibt, "Node"); +			ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path); + +			Object *obj = ClassDB::instance(ibt); + +			ERR_CONTINUE_MSG(obj == nullptr, +					"Cannot instance script for autoload, expected 'Node' inheritance, got: " + +							String(ibt)); + +			n = Object::cast_to<Node>(obj); +			n->set_script(script_res); +		} + +		ERR_CONTINUE_MSG(!n, "Path in autoload not a node or script: " + info.path); +		n->set_name(info.name); + +		for (int i = 0; i < ScriptServer::get_language_count(); i++) { +			ScriptServer::get_language(i)->add_global_constant(info.name, n); +		} +	} +} +  void test(TestType p_type) {  	List<String> cmdlargs = OS::get_singleton()->get_cmdline_args(); @@ -195,6 +252,21 @@ void test(TestType p_type) {  	FileAccessRef fa = FileAccess::open(test, FileAccess::READ);  	ERR_FAIL_COND_MSG(!fa, "Could not open file: " + test); +	// Init PackedData since it's used by ProjectSettings. +	PackedData *packed_data = memnew(PackedData); + +	// Setup project settings since it's needed by the languages to get the global scripts. +	// This also sets up the base resource path. +	Error err = ProjectSettings::get_singleton()->setup(fa->get_path_absolute().get_base_dir(), String(), true); +	if (err) { +		print_line("Could not load project settings."); +		// Keep going since some scripts still work without this. +	} + +	// Initialize the language for the test routine. +	ScriptServer::init_languages(); +	init_autoloads(); +  	Vector<uint8_t> buf;  	int flen = fa->get_len();  	buf.resize(fa->get_len() + 1); @@ -226,6 +298,10 @@ void test(TestType p_type) {  		case TEST_BYTECODE:  			print_line("Not implemented.");  	} + +	// Destroy stuff we set up earlier. +	ScriptServer::finish_languages(); +	memdelete(packed_data);  }  } // namespace TestGDScript  |