summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/gdscript_compiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gdscript_compiler.cpp')
-rw-r--r--modules/gdscript/gdscript_compiler.cpp65
1 files changed, 53 insertions, 12 deletions
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index e62972b949..eebf282633 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -532,10 +532,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
Vector<GDScriptCodeGenerator::Address> elements;
// Create the result temporary first since it's the last to be killed.
- GDScriptDataType dict_type;
- dict_type.has_type = true;
- dict_type.kind = GDScriptDataType::BUILTIN;
- dict_type.builtin_type = Variant::DICTIONARY;
+ GDScriptDataType dict_type = _gdtype_from_datatype(dn->get_datatype(), codegen.script);
GDScriptCodeGenerator::Address result = codegen.add_temporary(dict_type);
for (int i = 0; i < dn->elements.size(); i++) {
@@ -566,7 +563,11 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
elements.push_back(element);
}
- gen->write_construct_dictionary(result, elements);
+ if (dict_type.has_container_element_types()) {
+ gen->write_construct_typed_dictionary(result, dict_type.get_container_element_type_or_variant(0), dict_type.get_container_element_type_or_variant(1), elements);
+ } else {
+ gen->write_construct_dictionary(result, elements);
+ }
for (int i = 0; i < elements.size(); i++) {
if (elements[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
@@ -1064,12 +1065,24 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// Get at (potential) root stack pos, so it can be returned.
GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, chain.back()->get()->base);
+ const bool base_known_type = base.type.has_type;
+ const bool base_is_shared = Variant::is_type_shared(base.type.builtin_type);
+
if (r_error) {
return GDScriptCodeGenerator::Address();
}
GDScriptCodeGenerator::Address prev_base = base;
+ // In case the base has a setter, don't use the address directly, as we want to call that setter.
+ // So use a temp value instead and call the setter at the end.
+ GDScriptCodeGenerator::Address base_temp;
+ if ((!base_known_type || !base_is_shared) && base.mode == GDScriptCodeGenerator::Address::MEMBER && member_property_has_setter && !member_property_is_in_setter) {
+ base_temp = codegen.add_temporary(base.type);
+ gen->write_assign(base_temp, base);
+ prev_base = base_temp;
+ }
+
struct ChainInfo {
bool is_named = false;
GDScriptCodeGenerator::Address base;
@@ -1218,6 +1231,15 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
gen->write_end_jump_if_shared();
}
}
+ } else if (base_temp.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ if (!base_known_type) {
+ gen->write_jump_if_shared(base);
+ }
+ // Save the temp value back to the base by calling its setter.
+ gen->write_call(GDScriptCodeGenerator::Address(), base, member_property_setter_function, { assigned });
+ if (!base_known_type) {
+ gen->write_end_jump_if_shared();
+ }
}
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
@@ -1880,7 +1902,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
case GDScriptParser::Node::MATCH: {
const GDScriptParser::MatchNode *match = static_cast<const GDScriptParser::MatchNode *>(s);
- codegen.start_block(); // Add an extra block, since the binding pattern and @special variables belong to the branch scope.
+ codegen.start_block(); // Add an extra block, since @special locals belong to the match scope.
// Evaluate the match expression.
GDScriptCodeGenerator::Address value = codegen.add_local("@match_value", _gdtype_from_datatype(match->test->get_datatype(), codegen.script));
@@ -1918,7 +1940,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
const GDScriptParser::MatchBranchNode *branch = match->branches[j];
- codegen.start_block(); // Create an extra block around for binds.
+ codegen.start_block(); // Add an extra block, since binds belong to the match branch scope.
// Add locals in block before patterns, so temporaries don't use the stack address for binds.
List<GDScriptCodeGenerator::Address> branch_locals = _add_block_locals(codegen, branch->block);
@@ -1970,13 +1992,15 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
_clear_block_locals(codegen, branch_locals);
- codegen.end_block(); // Get out of extra block.
+ codegen.end_block(); // Get out of extra block for binds.
}
// End all nested `if`s.
for (int j = 0; j < match->branches.size(); j++) {
gen->write_endif();
}
+
+ codegen.end_block(); // Get out of extra block for match's @special locals.
} break;
case GDScriptParser::Node::IF: {
const GDScriptParser::IfNode *if_n = static_cast<const GDScriptParser::IfNode *>(s);
@@ -2010,7 +2034,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
case GDScriptParser::Node::FOR: {
const GDScriptParser::ForNode *for_n = static_cast<const GDScriptParser::ForNode *>(s);
- codegen.start_block(); // Add an extra block, since the iterator and @special variables belong to the loop scope.
+ // Add an extra block, since the iterator and @special locals belong to the loop scope.
+ // Also we use custom logic to clear block locals.
+ codegen.start_block();
GDScriptCodeGenerator::Address iterator = codegen.add_local(for_n->variable->name, _gdtype_from_datatype(for_n->variable->get_datatype(), codegen.script));
@@ -2043,11 +2069,13 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
_clear_block_locals(codegen, loop_locals); // Outside loop, after block - for `break` and normal exit.
- codegen.end_block(); // Get out of extra block.
+ codegen.end_block(); // Get out of extra block for loop iterator, @special locals, and custom locals clearing.
} break;
case GDScriptParser::Node::WHILE: {
const GDScriptParser::WhileNode *while_n = static_cast<const GDScriptParser::WhileNode *>(s);
+ codegen.start_block(); // Add an extra block, since we use custom logic to clear block locals.
+
gen->start_while_condition();
GDScriptCodeGenerator::Address condition = _parse_expression(codegen, err, while_n->condition);
@@ -2074,6 +2102,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
gen->write_endwhile();
_clear_block_locals(codegen, loop_locals); // Outside loop, after block - for `break` and normal exit.
+
+ codegen.end_block(); // Get out of extra block for custom locals clearing.
} break;
case GDScriptParser::Node::BREAK: {
gen->write_break();
@@ -2296,8 +2326,11 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, field_type);
- if (field_type.has_container_element_type(0)) {
+ if (field_type.builtin_type == Variant::ARRAY && field_type.has_container_element_type(0)) {
codegen.generator->write_construct_typed_array(dst_address, field_type.get_container_element_type(0), Vector<GDScriptCodeGenerator::Address>());
+ } else if (field_type.builtin_type == Variant::DICTIONARY && field_type.has_container_element_types()) {
+ codegen.generator->write_construct_typed_dictionary(dst_address, field_type.get_container_element_type_or_variant(0),
+ field_type.get_container_element_type_or_variant(1), Vector<GDScriptCodeGenerator::Address>());
} else if (field_type.kind == GDScriptDataType::BUILTIN) {
codegen.generator->write_construct(dst_address, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
}
@@ -2486,11 +2519,17 @@ GDScriptFunction *GDScriptCompiler::_make_static_initializer(Error &r_error, GDS
if (field_type.has_type) {
codegen.generator->write_newline(field->start_line);
- if (field_type.has_container_element_type(0)) {
+ if (field_type.builtin_type == Variant::ARRAY && field_type.has_container_element_type(0)) {
GDScriptCodeGenerator::Address temp = codegen.add_temporary(field_type);
codegen.generator->write_construct_typed_array(temp, field_type.get_container_element_type(0), Vector<GDScriptCodeGenerator::Address>());
codegen.generator->write_set_static_variable(temp, class_addr, p_script->static_variables_indices[field->identifier->name].index);
codegen.generator->pop_temporary();
+ } else if (field_type.builtin_type == Variant::DICTIONARY && field_type.has_container_element_types()) {
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(field_type);
+ codegen.generator->write_construct_typed_dictionary(temp, field_type.get_container_element_type_or_variant(0),
+ field_type.get_container_element_type_or_variant(1), Vector<GDScriptCodeGenerator::Address>());
+ codegen.generator->write_set_static_variable(temp, class_addr, p_script->static_variables_indices[field->identifier->name].index);
+ codegen.generator->pop_temporary();
} else if (field_type.kind == GDScriptDataType::BUILTIN) {
GDScriptCodeGenerator::Address temp = codegen.add_temporary(field_type);
codegen.generator->write_construct(temp, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
@@ -3006,6 +3045,8 @@ Error GDScriptCompiler::_compile_class(GDScript *p_script, const GDScriptParser:
has_static_data = has_static_data || inner_class->has_static_data;
}
+ p_script->_static_default_init();
+
p_script->valid = true;
return OK;
}