diff options
Diffstat (limited to 'modules/gdscript/gdscript_compiler.cpp')
-rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 166 |
1 files changed, 73 insertions, 93 deletions
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index cf9e734b05..b34be11169 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -1,32 +1,32 @@ -/*************************************************************************/ -/* gdscript_compiler.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ +/**************************************************************************/ +/* gdscript_compiler.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ #include "gdscript_compiler.h" @@ -196,7 +196,11 @@ static bool _is_exact_type(const PropertyInfo &p_par_type, const GDScriptDataTyp } } -static bool _have_exact_arguments(const MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) { +static bool _can_use_ptrcall(const MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) { + if (p_method->is_vararg()) { + // ptrcall won't work with vararg methods. + return false; + } if (p_method->get_argument_count() != p_arguments.size()) { // ptrcall won't work with default arguments. return false; @@ -213,7 +217,7 @@ static bool _have_exact_arguments(const MethodBind *p_method, const Vector<GDScr } GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root, bool p_initializer, const GDScriptCodeGenerator::Address &p_index_addr) { - if (p_expression->is_constant) { + if (p_expression->is_constant && !(p_expression->get_datatype().is_meta_type && p_expression->get_datatype().kind == GDScriptParser::DataType::CLASS)) { return codegen.add_constant(p_expression->reduced_value); } @@ -250,7 +254,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (codegen.script->member_indices.has(identifier)) { if (codegen.script->member_indices[identifier].getter != StringName() && codegen.script->member_indices[identifier].getter != codegen.function_name) { // Perform getter. - GDScriptCodeGenerator::Address temp = codegen.add_temporary(); + GDScriptCodeGenerator::Address temp = codegen.add_temporary(codegen.script->member_indices[identifier].data_type); Vector<GDScriptCodeGenerator::Address> args; // No argument needed. gen->write_call_self(temp, codegen.script->member_indices[identifier].getter, args); return temp; @@ -520,10 +524,12 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code case GDScriptParser::Node::CALL: { const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_expression); GDScriptDataType type = _gdtype_from_datatype(call->get_datatype(), codegen.script); - GDScriptCodeGenerator::Address result = codegen.add_temporary(type); - GDScriptCodeGenerator::Address nil = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NIL); - - GDScriptCodeGenerator::Address return_addr = p_root ? nil : result; + GDScriptCodeGenerator::Address result; + if (p_root) { + result = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NIL); + } else { + result = codegen.add_temporary(type); + } Vector<GDScriptCodeGenerator::Address> arguments; for (int i = 0; i < call->arguments.size(); i++) { @@ -544,7 +550,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code gen->write_call_utility(result, call->function_name, arguments); } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptUtilityFunctions::function_exists(call->function_name)) { // GDScript utility function. - gen->write_call_gdscript_utility(result, GDScriptUtilityFunctions::get_function(call->function_name), arguments); + gen->write_call_gdscript_utility(result, call->function_name, arguments); } else { // Regular function. const GDScriptParser::ExpressionNode *callee = call->callee; @@ -561,7 +567,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code self.mode = GDScriptCodeGenerator::Address::SELF; MethodBind *method = ClassDB::get_method(codegen.script->native->get_name(), call->function_name); - if (_have_exact_arguments(method, arguments)) { + if (_can_use_ptrcall(method, arguments)) { // Exact arguments, use ptrcall. gen->write_call_ptrcall(result, self, method, arguments); } else { @@ -574,13 +580,13 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (within_await) { gen->write_call_async(result, self, call->function_name, arguments); } else { - gen->write_call(return_addr, self, call->function_name, arguments); + gen->write_call(result, self, call->function_name, arguments); } } else { if (within_await) { gen->write_call_self_async(result, call->function_name, arguments); } else { - gen->write_call_self(return_addr, call->function_name, arguments); + gen->write_call_self(result, call->function_name, arguments); } } } else if (callee->type == GDScriptParser::Node::SUBSCRIPT) { @@ -611,7 +617,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } if (ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) { MethodBind *method = ClassDB::get_method(class_name, call->function_name); - if (_have_exact_arguments(method, arguments)) { + if (_can_use_ptrcall(method, arguments)) { // Exact arguments, use ptrcall. gen->write_call_ptrcall(result, base, method, arguments); } else { @@ -619,12 +625,12 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code gen->write_call_method_bind(result, base, method, arguments); } } else { - gen->write_call(return_addr, base, call->function_name, arguments); + gen->write_call(result, base, call->function_name, arguments); } } else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) { gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments); } else { - gen->write_call(return_addr, base, call->function_name, arguments); + gen->write_call(result, base, call->function_name, arguments); } if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) { gen->pop_temporary(); @@ -1408,7 +1414,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type); Vector<GDScriptCodeGenerator::Address> len_args; len_args.push_back(p_value_addr); - codegen.generator->write_call_gdscript_utility(value_length_addr, GDScriptUtilityFunctions::get_function("len"), len_args); + codegen.generator->write_call_gdscript_utility(value_length_addr, "len", len_args); // Test length compatibility. temp_type.builtin_type = Variant::BOOL; @@ -1506,7 +1512,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type); Vector<GDScriptCodeGenerator::Address> func_args; func_args.push_back(p_value_addr); - codegen.generator->write_call_gdscript_utility(value_length_addr, GDScriptUtilityFunctions::get_function("len"), func_args); + codegen.generator->write_call_gdscript_utility(value_length_addr, "len", func_args); // Test length compatibility. temp_type.builtin_type = Variant::BOOL; @@ -1677,7 +1683,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui case GDScriptParser::Node::MATCH: { const GDScriptParser::MatchNode *match = static_cast<const GDScriptParser::MatchNode *>(s); - gen->start_match(); codegen.start_block(); // Evaluate the match expression. @@ -1716,7 +1721,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui const GDScriptParser::MatchBranchNode *branch = match->branches[j]; - gen->start_match_branch(); // Need so lower level code can patch 'continue' jumps. codegen.start_block(); // Create an extra block around for binds. // Add locals in block before patterns, so temporaries don't use the stack address for binds. @@ -1754,8 +1758,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui for (int j = 0; j < match->branches.size(); j++) { gen->write_endif(); } - - gen->end_match(); } break; case GDScriptParser::Node::IF: { const GDScriptParser::IfNode *if_n = static_cast<const GDScriptParser::IfNode *>(s); @@ -1843,12 +1845,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui gen->write_break(); } break; case GDScriptParser::Node::CONTINUE: { - const GDScriptParser::ContinueNode *cont = static_cast<const GDScriptParser::ContinueNode *>(s); - if (cont->is_for_match) { - gen->write_continue_match(); - } else { - gen->write_continue(); - } + gen->write_continue(); } break; case GDScriptParser::Node::RETURN: { const GDScriptParser::ReturnNode *return_n = static_cast<const GDScriptParser::ReturnNode *>(s); @@ -1862,7 +1859,12 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui } } - gen->write_return(return_value); + if (return_n->void_return) { + // Always return "null", even if the expression is a call to a void function. + gen->write_return(codegen.add_constant(Variant())); + } else { + gen->write_return(return_value); + } if (return_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) { codegen.generator->pop_temporary(); } @@ -1907,14 +1909,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui bool initialized = false; if (lv->initializer != nullptr) { - // For typed arrays we need to make sure this is already initialized correctly so typed assignment work. - if (local_type.has_type && local_type.builtin_type == Variant::ARRAY) { - if (local_type.has_container_element_type()) { - codegen.generator->write_construct_typed_array(local, local_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>()); - } else { - codegen.generator->write_construct_array(local, Vector<GDScriptCodeGenerator::Address>()); - } - } GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, err, lv->initializer); if (err) { return err; @@ -2022,10 +2016,10 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ for (int i = 0; i < p_func->parameters.size(); i++) { const GDScriptParser::ParameterNode *parameter = p_func->parameters[i]; GDScriptDataType par_type = _gdtype_from_datatype(parameter->get_datatype(), p_script); - uint32_t par_addr = codegen.generator->add_parameter(parameter->identifier->name, parameter->default_value != nullptr, par_type); + uint32_t par_addr = codegen.generator->add_parameter(parameter->identifier->name, parameter->initializer != nullptr, par_type); codegen.parameters[parameter->identifier->name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::FUNCTION_PARAMETER, par_addr, par_type); - if (p_func->parameters[i]->default_value != nullptr) { + if (parameter->initializer != nullptr) { optional_parameters++; } } @@ -2055,14 +2049,6 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ // Emit proper line change. codegen.generator->write_newline(field->initializer->start_line); - // For typed arrays we need to make sure this is already initialized correctly so typed assignment work. - if (field_type.has_type && field_type.builtin_type == Variant::ARRAY) { - if (field_type.has_container_element_type()) { - codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(), Vector<GDScriptCodeGenerator::Address>()); - } else { - codegen.generator->write_construct_array(dst_address, Vector<GDScriptCodeGenerator::Address>()); - } - } GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, r_error, field->initializer, false, true); if (r_error) { memdelete(codegen.generator); @@ -2097,13 +2083,13 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ codegen.generator->start_parameters(); for (int i = p_func->parameters.size() - optional_parameters; i < p_func->parameters.size(); i++) { const GDScriptParser::ParameterNode *parameter = p_func->parameters[i]; - GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->default_value); + GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->initializer); if (r_error) { memdelete(codegen.generator); return nullptr; } GDScriptCodeGenerator::Address dst_addr = codegen.parameters[parameter->identifier->name]; - codegen.generator->write_assign_default_parameter(dst_addr, src_addr); + codegen.generator->write_assign_default_parameter(dst_addr, src_addr, parameter->use_conversion_assign); if (src_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) { codegen.generator->pop_temporary(); } @@ -2453,26 +2439,20 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri case GDScriptParser::ClassNode::Member::ENUM: { const GDScriptParser::EnumNode *enum_n = member.m_enum; + StringName name = enum_n->identifier->name; - // TODO: Make enums not be just a dictionary? - Dictionary new_enum; - for (int j = 0; j < enum_n->values.size(); j++) { - // Needs to be string because Variant::get will convert to String. - new_enum[String(enum_n->values[j].identifier->name)] = enum_n->values[j].value; - } - - p_script->constants.insert(enum_n->identifier->name, new_enum); + p_script->constants.insert(name, enum_n->dictionary); #ifdef TOOLS_ENABLED - p_script->member_lines[enum_n->identifier->name] = enum_n->start_line; - p_script->doc_enums[enum_n->identifier->name] = DocData::EnumDoc(); - p_script->doc_enums[enum_n->identifier->name].name = enum_n->identifier->name; - p_script->doc_enums[enum_n->identifier->name].description = enum_n->doc_description; + p_script->member_lines[name] = enum_n->start_line; + p_script->doc_enums[name] = DocData::EnumDoc(); + p_script->doc_enums[name].name = name; + p_script->doc_enums[name].description = enum_n->doc_description; for (int j = 0; j < enum_n->values.size(); j++) { DocData::ConstantDoc const_doc; const_doc.name = enum_n->values[j].identifier->name; const_doc.value = Variant(enum_n->values[j].value).operator String(); const_doc.description = enum_n->values[j].doc_description; - p_script->doc_enums[enum_n->identifier->name].values.push_back(const_doc); + p_script->doc_enums[name].values.push_back(const_doc); } #endif } break; @@ -2642,10 +2622,6 @@ Error GDScriptCompiler::_compile_class(GDScript *p_script, const GDScriptParser: } } -#ifdef TOOLS_ENABLED - p_script->_update_doc(); -#endif - p_script->_init_rpc_methods_properties(); p_script->valid = true; @@ -2730,6 +2706,10 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri return err; } +#ifdef TOOLS_ENABLED + p_script->_update_doc(); +#endif + return GDScriptCache::finish_compiling(main_script->get_path()); } |