summaryrefslogtreecommitdiff
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.cpp464
1 files changed, 264 insertions, 200 deletions
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 63ca34fc24..ab0fe5c37d 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -35,6 +35,8 @@
#include "gdscript_cache.h"
#include "gdscript_utility_functions.h"
+#include "core/config/project_settings.h"
+
bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) {
if (codegen.function_node && codegen.function_node->is_static) {
return false;
@@ -107,7 +109,9 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
// Locate class by constructing the path to it and following that path
GDScriptParser::ClassNode *class_type = p_datatype.class_type;
if (class_type) {
- if (class_type->fqcn.begins_with(main_script->path) || (!main_script->name.is_empty() && class_type->fqcn.begins_with(main_script->name))) {
+ const bool is_inner_by_path = (!main_script->path.is_empty()) && (class_type->fqcn.split("::")[0] == main_script->path);
+ const bool is_inner_by_name = (!main_script->name.is_empty()) && (class_type->fqcn.split("::")[0] == main_script->name);
+ if (is_inner_by_path || is_inner_by_name) {
// Local class.
List<StringName> names;
while (class_type->outer) {
@@ -126,8 +130,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
names.pop_back();
}
result.kind = GDScriptDataType::GDSCRIPT;
- result.script_type_ref = script;
- result.script_type = result.script_type_ref.ptr();
+ result.script_type = script.ptr();
result.native_type = script->get_instance_base_type();
} else {
result.kind = GDScriptDataType::GDSCRIPT;
@@ -137,22 +140,22 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
}
}
} break;
+ case GDScriptParser::DataType::ENUM:
case GDScriptParser::DataType::ENUM_VALUE:
result.has_type = true;
result.kind = GDScriptDataType::BUILTIN;
result.builtin_type = Variant::INT;
break;
- case GDScriptParser::DataType::ENUM:
- result.has_type = true;
- result.kind = GDScriptDataType::BUILTIN;
- result.builtin_type = Variant::DICTIONARY;
- break;
case GDScriptParser::DataType::UNRESOLVED: {
ERR_PRINT("Parser bug: converting unresolved type.");
return GDScriptDataType();
}
}
+ if (p_datatype.has_container_element_type()) {
+ result.set_container_element_type(_gdtype_from_datatype(p_datatype.get_container_element_type()));
+ }
+
// Only hold strong reference to the script if it's not the owner of the
// element qualified with this type, to avoid cyclic references (leaks).
if (result.script_type && result.script_type == p_owner) {
@@ -262,7 +265,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
GDScriptNativeClass *nc = nullptr;
while (scr) {
if (scr->constants.has(identifier)) {
- return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS_CONSTANT, gen->add_or_get_name(identifier)); // TODO: Get type here.
+ return codegen.add_constant(scr->constants[identifier]); // TODO: Get type here.
}
if (scr->native.is_valid()) {
nc = scr->native.ptr();
@@ -317,9 +320,21 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
}
+ // Try globals.
if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
- int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
- return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::GLOBAL, idx); // TODO: Get type.
+ // If it's an autoload singleton, we postpone to load it at runtime.
+ // This is so one autoload doesn't try to load another before it's compiled.
+ OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+ if (autoloads.has(identifier) && autoloads[identifier].is_singleton) {
+ GDScriptCodeGenerator::Address global = codegen.add_temporary(_gdtype_from_datatype(in->get_datatype()));
+ int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
+ gen->write_store_global(global, idx);
+ return global;
+ } else {
+ int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
+ Variant global = GDScriptLanguage::get_singleton()->get_global_array()[idx];
+ return codegen.add_constant(global);
+ }
}
// Try global classes.
@@ -347,7 +362,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
#ifdef TOOLS_ENABLED
if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) {
- return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NAMED_GLOBAL, gen->add_or_get_name(identifier)); // TODO: Get type.
+ GDScriptCodeGenerator::Address global = codegen.add_temporary(); // TODO: Get type.
+ gen->write_store_named_global(global, identifier);
+ return global;
}
#endif
@@ -376,10 +393,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
Vector<GDScriptCodeGenerator::Address> values;
// Create the result temporary first since it's the last to be killed.
- GDScriptDataType array_type;
- array_type.has_type = true;
- array_type.kind = GDScriptDataType::BUILTIN;
- array_type.builtin_type = Variant::ARRAY;
+ GDScriptDataType array_type = _gdtype_from_datatype(an->get_datatype());
GDScriptCodeGenerator::Address result = codegen.add_temporary(array_type);
for (int i = 0; i < an->elements.size(); i++) {
@@ -390,7 +404,11 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
values.push_back(val);
}
- gen->write_construct_array(result, values);
+ if (array_type.has_container_element_type()) {
+ gen->write_construct_typed_array(result, array_type.get_container_element_type(), values);
+ } else {
+ gen->write_construct_array(result, values);
+ }
for (int i = 0; i < values.size(); i++) {
if (values[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
@@ -423,8 +441,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
break;
case GDScriptParser::DictionaryNode::LUA_TABLE:
- // Lua-style: key is an identifier interpreted as string.
- String key = static_cast<const GDScriptParser::IdentifierNode *>(dn->elements[i].key)->name;
+ // Lua-style: key is an identifier interpreted as StringName.
+ StringName key = dn->elements[i].key->reduced_value.operator StringName();
element = codegen.add_constant(key);
break;
}
@@ -470,6 +488,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_expression);
GDScriptDataType type = _gdtype_from_datatype(call->get_datatype());
GDScriptCodeGenerator::Address result = codegen.add_temporary(type);
+ GDScriptCodeGenerator::Address nil = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NIL);
+
+ GDScriptCodeGenerator::Address return_addr = p_root ? nil : result;
Vector<GDScriptCodeGenerator::Address> arguments;
for (int i = 0; i < call->arguments.size(); i++) {
@@ -520,52 +541,57 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (within_await) {
gen->write_call_async(result, self, call->function_name, arguments);
} else {
- gen->write_call(result, self, call->function_name, arguments);
+ gen->write_call(return_addr, self, call->function_name, arguments);
}
} else {
if (within_await) {
gen->write_call_self_async(result, call->function_name, arguments);
} else {
- gen->write_call_self(result, call->function_name, arguments);
+ gen->write_call_self(return_addr, call->function_name, arguments);
}
}
} else if (callee->type == GDScriptParser::Node::SUBSCRIPT) {
const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee);
if (subscript->is_attribute) {
- GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
- if (r_error) {
- return GDScriptCodeGenerator::Address();
- }
- if (within_await) {
- gen->write_call_async(result, base, call->function_name, arguments);
- } else if (base.type.has_type && base.type.kind != GDScriptDataType::BUILTIN) {
- // Native method, use faster path.
- StringName class_name;
- if (base.type.kind == GDScriptDataType::NATIVE) {
- class_name = base.type.native_type;
- } else {
- class_name = base.type.native_type == StringName() ? base.type.script_type->get_instance_base_type() : base.type.native_type;
+ // May be static built-in method call.
+ if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) {
+ gen->write_call_builtin_type_static(result, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments);
+ } else {
+ GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
- 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)) {
- // Exact arguments, use ptrcall.
- gen->write_call_ptrcall(result, base, method, arguments);
+ if (within_await) {
+ gen->write_call_async(result, base, call->function_name, arguments);
+ } else if (base.type.has_type && base.type.kind != GDScriptDataType::BUILTIN) {
+ // Native method, use faster path.
+ StringName class_name;
+ if (base.type.kind == GDScriptDataType::NATIVE) {
+ class_name = base.type.native_type;
} else {
- // Not exact arguments, but still can use method bind call.
- gen->write_call_method_bind(result, base, method, arguments);
+ class_name = base.type.native_type == StringName() ? base.type.script_type->get_instance_base_type() : base.type.native_type;
}
+ 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)) {
+ // Exact arguments, use ptrcall.
+ gen->write_call_ptrcall(result, base, method, arguments);
+ } else {
+ // Not exact arguments, but still can use method bind call.
+ gen->write_call_method_bind(result, base, method, arguments);
+ }
+ } else {
+ gen->write_call(return_addr, 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(result, base, call->function_name, arguments);
+ gen->write_call(return_addr, base, call->function_name, arguments);
+ }
+ if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
- } 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(result, base, call->function_name, arguments);
- }
- if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- gen->pop_temporary();
}
} else {
_set_error("Cannot call something that isn't a function.", call->callee);
@@ -676,9 +702,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
name = subscript->attribute->name;
named = true;
} else {
- if (subscript->index->type == GDScriptParser::Node::LITERAL && static_cast<const GDScriptParser::LiteralNode *>(subscript->index)->value.get_type() == Variant::STRING) {
+ if (subscript->index->is_constant && subscript->index->reduced_value.get_type() == Variant::STRING_NAME) {
// Also, somehow, named (speed up anyway).
- name = static_cast<const GDScriptParser::LiteralNode *>(subscript->index)->value;
+ name = subscript->index->reduced_value;
named = true;
} else {
// Regular indexing.
@@ -707,7 +733,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
case GDScriptParser::Node::UNARY_OPERATOR: {
const GDScriptParser::UnaryOpNode *unary = static_cast<const GDScriptParser::UnaryOpNode *>(p_expression);
- GDScriptCodeGenerator::Address result = codegen.add_temporary();
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(unary->get_datatype()));
GDScriptCodeGenerator::Address operand = _parse_expression(codegen, r_error, unary->operand);
if (r_error) {
@@ -725,7 +751,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
case GDScriptParser::Node::BINARY_OPERATOR: {
const GDScriptParser::BinaryOpNode *binary = static_cast<const GDScriptParser::BinaryOpNode *>(p_expression);
- GDScriptCodeGenerator::Address result = codegen.add_temporary();
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(binary->get_datatype()));
switch (binary->operation) {
case GDScriptParser::BinaryOpNode::OP_LOGIC_AND: {
@@ -777,6 +803,10 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
gen->pop_temporary();
}
}
+
+ if (operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
} break;
default: {
GDScriptCodeGenerator::Address left_operand = _parse_expression(codegen, r_error, binary->left_operand);
@@ -939,7 +969,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// Perform operator if any.
if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
- GDScriptCodeGenerator::Address value = codegen.add_temporary();
+ GDScriptCodeGenerator::Address value = codegen.add_temporary(_gdtype_from_datatype(subscript->get_datatype()));
if (subscript->is_attribute) {
gen->write_get_named(value, name, prev_base);
} else {
@@ -958,6 +988,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
} else {
gen->write_set(prev_base, key, assigned);
}
+ if (key.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
gen->pop_temporary();
}
@@ -965,8 +998,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
assigned = prev_base;
// Set back the values into their bases.
- for (List<ChainInfo>::Element *E = set_chain.front(); E; E = E->next()) {
- const ChainInfo &info = E->get();
+ for (const ChainInfo &info : set_chain) {
if (!info.is_named) {
gen->write_set(info.base, info.key, assigned);
if (info.key.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
@@ -992,25 +1024,32 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
} else if (assignment->assignee->type == GDScriptParser::Node::IDENTIFIER && _is_class_member_property(codegen, static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name)) {
// Assignment to member property.
- GDScriptCodeGenerator::Address assigned = _parse_expression(codegen, r_error, assignment->assigned_value);
+ GDScriptCodeGenerator::Address assigned_value = _parse_expression(codegen, r_error, assignment->assigned_value);
if (r_error) {
return GDScriptCodeGenerator::Address();
}
- GDScriptCodeGenerator::Address assign_temp = assigned;
+
+ GDScriptCodeGenerator::Address to_assign = assigned_value;
+ bool has_operation = assignment->operation != GDScriptParser::AssignmentNode::OP_NONE;
StringName name = static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name;
- if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
+ if (has_operation) {
+ GDScriptCodeGenerator::Address op_result = codegen.add_temporary();
GDScriptCodeGenerator::Address member = codegen.add_temporary();
gen->write_get_member(member, name);
- gen->write_binary_operator(assigned, assignment->variant_op, member, assigned);
- gen->pop_temporary();
+ gen->write_binary_operator(op_result, assignment->variant_op, member, assigned_value);
+ gen->pop_temporary(); // Pop member temp.
+ to_assign = op_result;
}
- gen->write_set_member(assigned, name);
+ gen->write_set_member(to_assign, name);
- if (assign_temp.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- gen->pop_temporary();
+ if (to_assign.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary(); // Pop the assigned expression or the temp result if it has operation.
+ }
+ if (has_operation && assigned_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary(); // Pop the assigned expression if not done before.
}
} else {
// Regular assignment.
@@ -1044,19 +1083,25 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
}
- GDScriptCodeGenerator::Address assigned = _parse_expression(codegen, r_error, assignment->assigned_value);
- GDScriptCodeGenerator::Address op_result;
+ GDScriptCodeGenerator::Address assigned_value = _parse_expression(codegen, r_error, assignment->assigned_value);
if (r_error) {
return GDScriptCodeGenerator::Address();
}
- if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
+ GDScriptCodeGenerator::Address to_assign;
+ bool has_operation = assignment->operation != GDScriptParser::AssignmentNode::OP_NONE;
+ if (has_operation) {
// Perform operation.
- op_result = codegen.add_temporary();
- gen->write_binary_operator(op_result, assignment->variant_op, target, assigned);
+ GDScriptCodeGenerator::Address op_result = codegen.add_temporary();
+ GDScriptCodeGenerator::Address og_value = _parse_expression(codegen, r_error, assignment->assignee);
+ gen->write_binary_operator(op_result, assignment->variant_op, og_value, assigned_value);
+ to_assign = op_result;
+
+ if (og_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
} else {
- op_result = assigned;
- assigned = GDScriptCodeGenerator::Address();
+ to_assign = assigned_value;
}
GDScriptDataType assign_type = _gdtype_from_datatype(assignment->assignee->get_datatype());
@@ -1064,25 +1109,57 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (has_setter && !is_in_setter) {
// Call setter.
Vector<GDScriptCodeGenerator::Address> args;
- args.push_back(op_result);
+ args.push_back(to_assign);
gen->write_call(GDScriptCodeGenerator::Address(), GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), setter_function, args);
} else {
// Just assign.
- gen->write_assign(target, op_result);
+ if (assignment->use_conversion_assign) {
+ gen->write_assign_with_conversion(target, to_assign);
+ } else {
+ gen->write_assign(target, to_assign);
+ }
}
- if (op_result.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- gen->pop_temporary();
+ if (to_assign.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary(); // Pop assigned value or temp operation result.
}
- if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- gen->pop_temporary();
+ if (has_operation && assigned_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary(); // Pop assigned value if not done before.
}
if (target.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- gen->pop_temporary();
+ gen->pop_temporary(); // Pop the target to assignment.
}
}
return GDScriptCodeGenerator::Address(); // Assignment does not return a value.
} break;
+ case GDScriptParser::Node::LAMBDA: {
+ const GDScriptParser::LambdaNode *lambda = static_cast<const GDScriptParser::LambdaNode *>(p_expression);
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(lambda->get_datatype()));
+
+ Vector<GDScriptCodeGenerator::Address> captures;
+ captures.resize(lambda->captures.size());
+ for (int i = 0; i < lambda->captures.size(); i++) {
+ captures.write[i] = _parse_expression(codegen, r_error, lambda->captures[i]);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
+ }
+
+ GDScriptFunction *function = _parse_function(r_error, codegen.script, codegen.class_node, lambda->function, false, true);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
+
+ gen->write_lambda(result, function, captures);
+
+ for (int i = 0; i < captures.size(); i++) {
+ if (captures[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
+ }
+
+ return result;
+ } break;
default: {
ERR_FAIL_V_MSG(GDScriptCodeGenerator::Address(), "Bug in bytecode compiler, unexpected node in parse tree while parsing expression."); // Unreachable code.
} break;
@@ -1733,16 +1810,37 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
const GDScriptParser::VariableNode *lv = static_cast<const GDScriptParser::VariableNode *>(s);
// Should be already in stack when the block began.
GDScriptCodeGenerator::Address local = codegen.locals[lv->identifier->name];
+ GDScriptParser::DataType local_type = lv->get_datatype();
if (lv->initializer != nullptr) {
+ // For typed arrays we need to make sure this is already initialized correctly so typed assignment work.
+ if (local_type.is_hard_type() && local_type.builtin_type == Variant::ARRAY) {
+ if (local_type.has_container_element_type()) {
+ codegen.generator->write_construct_typed_array(local, _gdtype_from_datatype(local_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>());
+ } else {
+ codegen.generator->write_construct_array(local, Vector<GDScriptCodeGenerator::Address>());
+ }
+ }
GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, error, lv->initializer);
if (error) {
return error;
}
- gen->write_assign(local, src_address);
+ if (lv->use_conversion_assign) {
+ gen->write_assign_with_conversion(local, src_address);
+ } else {
+ gen->write_assign(local, src_address);
+ }
if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
+ } else if (lv->get_datatype().is_hard_type()) {
+ // Initialize with default for type.
+ if (local_type.has_container_element_type()) {
+ codegen.generator->write_construct_typed_array(local, _gdtype_from_datatype(local_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>());
+ } else if (local_type.kind == GDScriptParser::DataType::BUILTIN) {
+ codegen.generator->write_construct(local, local_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
+ }
+ // The `else` branch is for objects, in such case we leave it as `null`.
}
} break;
case GDScriptParser::Node::CONSTANT: {
@@ -1779,8 +1877,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
return OK;
}
-Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready) {
- Error error = OK;
+GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready, bool p_for_lambda) {
+ r_error = OK;
CodeGen codegen;
codegen.generator = memnew(GDScriptByteCodeGenerator);
@@ -1790,16 +1888,20 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
StringName func_name;
bool is_static = false;
- MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
+ Multiplayer::RPCConfig rpc_config;
GDScriptDataType return_type;
return_type.has_type = true;
return_type.kind = GDScriptDataType::BUILTIN;
return_type.builtin_type = Variant::NIL;
if (p_func) {
- func_name = p_func->identifier->name;
+ if (p_func->identifier) {
+ func_name = p_func->identifier->name;
+ } else {
+ func_name = "<anonymous lambda>";
+ }
is_static = p_func->is_static;
- rpc_mode = p_func->rpc_mode;
+ rpc_config = p_func->rpc_config;
return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script);
} else {
if (p_for_ready) {
@@ -1810,7 +1912,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
}
codegen.function_name = func_name;
- codegen.generator->write_start(p_script, func_name, is_static, rpc_mode, return_type);
+ codegen.generator->write_start(p_script, func_name, is_static, rpc_config, return_type);
int optional_parameters = 0;
@@ -1828,11 +1930,11 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
}
// Parse initializer if applies.
- bool is_implicit_initializer = !p_for_ready && !p_func;
- bool is_initializer = p_func && String(p_func->identifier->name) == GDScriptLanguage::get_singleton()->strings._init;
- bool is_for_ready = p_for_ready || (p_func && String(p_func->identifier->name) == "_ready");
+ bool is_implicit_initializer = !p_for_ready && !p_func && !p_for_lambda;
+ bool is_initializer = p_func && !p_for_lambda && String(p_func->identifier->name) == GDScriptLanguage::get_singleton()->strings._init;
+ bool is_for_ready = p_for_ready || (p_func && !p_for_lambda && String(p_func->identifier->name) == "_ready");
- if (is_implicit_initializer || is_for_ready) {
+ if (!p_for_lambda && (is_implicit_initializer || is_for_ready)) {
// Initialize class fields.
for (int i = 0; i < p_class->members.size(); i++) {
if (p_class->members[i].type != GDScriptParser::ClassNode::Member::VARIABLE) {
@@ -1844,21 +1946,45 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
continue;
}
+ GDScriptParser::DataType field_type = field->get_datatype();
+
+ GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, _gdtype_from_datatype(field->get_datatype()));
if (field->initializer) {
// Emit proper line change.
codegen.generator->write_newline(field->initializer->start_line);
- GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, error, field->initializer, false, true);
- if (error) {
+ // For typed arrays we need to make sure this is already initialized correctly so typed assignment work.
+ if (field_type.is_hard_type() && field_type.builtin_type == Variant::ARRAY && field_type.has_container_element_type()) {
+ if (field_type.has_container_element_type()) {
+ codegen.generator->write_construct_typed_array(dst_address, _gdtype_from_datatype(field_type.get_container_element_type(), codegen.script), 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);
- return error;
+ return nullptr;
}
- GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, _gdtype_from_datatype(field->get_datatype()));
- codegen.generator->write_assign(dst_address, src_address);
+ if (field->use_conversion_assign) {
+ codegen.generator->write_assign_with_conversion(dst_address, src_address);
+ } else {
+ codegen.generator->write_assign(dst_address, src_address);
+ }
if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
+ } else if (field->get_datatype().is_hard_type()) {
+ codegen.generator->write_newline(field->start_line);
+
+ // Initialize with default for type.
+ if (field_type.has_container_element_type()) {
+ codegen.generator->write_construct_typed_array(dst_address, _gdtype_from_datatype(field_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>());
+ } else if (field_type.kind == GDScriptParser::DataType::BUILTIN) {
+ codegen.generator->write_construct(dst_address, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
+ }
+ // The `else` branch is for objects, in such case we leave it as `null`.
}
}
}
@@ -1869,10 +1995,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
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, error, parameter->default_value, true);
- if (error) {
+ GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->default_value, true);
+ if (r_error) {
memdelete(codegen.generator);
- return error;
+ return nullptr;
}
GDScriptCodeGenerator::Address dst_addr = codegen.parameters[parameter->identifier->name];
codegen.generator->write_assign_default_parameter(dst_addr, src_addr);
@@ -1883,10 +2009,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
codegen.generator->end_parameters();
}
- Error err = _parse_block(codegen, p_func->body);
- if (err) {
+ r_error = _parse_block(codegen, p_func->body);
+ if (r_error) {
memdelete(codegen.generator);
- return err;
+ return nullptr;
}
}
@@ -1912,6 +2038,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
signature += "::" + String(func_name);
}
+ if (p_for_lambda) {
+ signature += "(lambda)";
+ }
+
codegen.generator->set_signature(signature);
}
#endif
@@ -1919,8 +2049,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
if (p_func) {
codegen.generator->set_initial_line(p_func->start_line);
#ifdef TOOLS_ENABLED
- p_script->member_lines[func_name] = p_func->start_line;
- p_script->doc_functions[func_name] = p_func->doc_description;
+ if (!p_for_lambda) {
+ p_script->member_lines[func_name] = p_func->start_line;
+ p_script->doc_functions[func_name] = p_func->doc_description;
+ }
#endif
} else {
codegen.generator->set_initial_line(0);
@@ -1949,84 +2081,29 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
#endif
}
- p_script->member_functions[func_name] = gd_function;
+ if (!p_for_lambda) {
+ p_script->member_functions[func_name] = gd_function;
+ }
memdelete(codegen.generator);
- return OK;
+ return gd_function;
}
Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter) {
Error error = OK;
- CodeGen codegen;
- codegen.generator = memnew(GDScriptByteCodeGenerator);
- codegen.class_node = p_class;
- codegen.script = p_script;
+ GDScriptParser::FunctionNode *function;
- StringName func_name;
-
- if (p_is_setter) {
- func_name = "@" + p_variable->identifier->name + "_setter";
- } else {
- func_name = "@" + p_variable->identifier->name + "_getter";
- }
-
- GDScriptDataType return_type;
if (p_is_setter) {
- return_type.has_type = true;
- return_type.kind = GDScriptDataType::BUILTIN;
- return_type.builtin_type = Variant::NIL;
+ function = p_variable->setter;
} else {
- return_type = _gdtype_from_datatype(p_variable->get_datatype(), p_script);
+ function = p_variable->getter;
}
- codegen.generator->write_start(p_script, func_name, false, p_variable->rpc_mode, return_type);
+ _parse_function(error, p_script, p_class, function);
- if (p_is_setter) {
- uint32_t par_addr = codegen.generator->add_parameter(p_variable->setter_parameter->name, false, _gdtype_from_datatype(p_variable->get_datatype()));
- codegen.parameters[p_variable->setter_parameter->name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::FUNCTION_PARAMETER, par_addr, _gdtype_from_datatype(p_variable->get_datatype()));
- }
-
- error = _parse_block(codegen, p_is_setter ? p_variable->setter : p_variable->getter);
- if (error) {
- memdelete(codegen.generator);
- return error;
- }
-
- GDScriptFunction *gd_function = codegen.generator->write_end();
-
- p_script->member_functions[func_name] = gd_function;
-
-#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active()) {
- String signature;
- //path
- if (p_script->get_path() != String()) {
- signature += p_script->get_path();
- }
- //loc
- signature += "::" + itos(p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line);
-
- //function and class
-
- if (p_class->identifier) {
- signature += "::" + String(p_class->identifier->name) + "." + String(func_name);
- } else {
- signature += "::" + String(func_name);
- }
-
- codegen.generator->set_signature(signature);
- }
-#endif
- codegen.generator->set_initial_line(p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line);
-
-#ifdef TOOLS_ENABLED
- p_script->member_lines[func_name] = p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line;
-#endif
- memdelete(codegen.generator);
-
- return OK;
+ return error;
}
Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
@@ -2069,8 +2146,8 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->_base = nullptr;
p_script->members.clear();
p_script->constants.clear();
- for (Map<StringName, GDScriptFunction *>::Element *E = p_script->member_functions.front(); E; E = E->next()) {
- memdelete(E->get());
+ for (const KeyValue<StringName, GDScriptFunction *> &E : p_script->member_functions) {
+ memdelete(E.value);
}
p_script->member_functions.clear();
p_script->member_indices.clear();
@@ -2081,6 +2158,13 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->tool = parser->is_tool();
p_script->name = p_class->identifier ? p_class->identifier->name : "";
+ if (p_script->name != "") {
+ if (ClassDB::class_exists(p_script->name) && ClassDB::is_class_exposed(p_script->name)) {
+ _set_error("The class '" + p_script->name + "' shadows a native class", p_class);
+ return ERR_ALREADY_EXISTS;
+ }
+ }
+
Ref<GDScriptNativeClass> native;
GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type);
@@ -2116,7 +2200,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
if (err) {
return err;
}
- if (base.is_null() && !base->is_valid()) {
+ if (base.is_null() || !base->is_valid()) {
return ERR_COMPILATION_FAILED;
}
}
@@ -2161,7 +2245,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
}
break;
}
- minfo.rpc_mode = variable->rpc_mode;
minfo.data_type = _gdtype_from_datatype(variable->get_datatype(), p_script);
PropertyInfo prop_info = minfo.data_type;
@@ -2175,7 +2258,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
}
prop_info.hint = export_info.hint;
prop_info.hint_string = export_info.hint_string;
- prop_info.usage = export_info.usage;
+ prop_info.usage = export_info.usage | PROPERTY_USAGE_SCRIPT_VARIABLE;
} else {
prop_info.usage = PROPERTY_USAGE_SCRIPT_VARIABLE;
}
@@ -2233,28 +2316,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
const GDScriptParser::SignalNode *signal = member.signal;
StringName name = signal->identifier->name;
- GDScript *c = p_script;
-
- while (c) {
- if (c->_signals.has(name)) {
- _set_error("Signal '" + name + "' redefined (in current or parent class)", p_class);
- return ERR_ALREADY_EXISTS;
- }
-
- if (c->base.is_valid()) {
- c = c->base.ptr();
- } else {
- c = nullptr;
- }
- }
-
- if (native.is_valid()) {
- if (ClassDB::has_signal(native->get_name(), name)) {
- _set_error("Signal '" + name + "' redefined (original in native class '" + String(native->get_name()) + "')", p_class);
- return ERR_ALREADY_EXISTS;
- }
- }
-
Vector<StringName> parameters_names;
parameters_names.resize(signal->parameters.size());
for (int j = 0; j < signal->parameters.size(); j++) {
@@ -2345,7 +2406,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
if (!has_ready && function->identifier->name == "_ready") {
has_ready = true;
}
- Error err = _parse_function(p_script, p_class, function);
+ Error err = OK;
+ _parse_function(err, p_script, p_class, function);
if (err) {
return err;
}
@@ -2370,7 +2432,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
{
// Create an implicit constructor in any case.
- Error err = _parse_function(p_script, p_class, nullptr);
+ Error err = OK;
+ _parse_function(err, p_script, p_class, nullptr);
if (err) {
return err;
}
@@ -2378,7 +2441,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
if (!has_ready && p_class->onready_used) {
//create a _ready constructor
- Error err = _parse_function(p_script, p_class, nullptr, true);
+ Error err = OK;
+ _parse_function(err, p_script, p_class, nullptr, true);
if (err) {
return err;
}
@@ -2402,14 +2466,14 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
p_script->placeholders.erase(psi); //remove placeholder
GDScriptInstance *instance = memnew(GDScriptInstance);
- instance->base_ref = Object::cast_to<Reference>(E->get());
+ instance->base_ref_counted = Object::cast_to<RefCounted>(E->get());
instance->members.resize(p_script->member_indices.size());
instance->script = Ref<GDScript>(p_script);
instance->owner = E->get();
//needed for hot reloading
- for (Map<StringName, GDScript::MemberInfo>::Element *F = p_script->member_indices.front(); F; F = F->next()) {
- instance->member_indices_cache[F->key()] = F->get().index;
+ for (const KeyValue<StringName, GDScript::MemberInfo> &F : p_script->member_indices) {
+ instance->member_indices_cache[F.key] = F.value.index;
}
instance->owner->set_script_instance(instance);
@@ -2477,7 +2541,7 @@ void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::C
if (orphan_subclass.is_valid()) {
subclass = orphan_subclass;
} else {
- subclass.instance();
+ subclass.instantiate();
}
}