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.cpp292
1 files changed, 159 insertions, 133 deletions
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index da19ce5000..3d37c7f803 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -31,6 +31,7 @@
#include "gdscript_compiler.h"
#include "gdscript.h"
+#include "gdscript_cache.h"
bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) {
if (codegen.function_node && codegen.function_node->is_static) {
@@ -114,7 +115,7 @@ bool GDScriptCompiler::_create_binary_operator(CodeGen &codegen, const GDScriptP
}
GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::DataType &p_datatype) const {
- if (!p_datatype.is_set()) {
+ if (!p_datatype.is_set() || !p_datatype.is_hard_type()) {
return GDScriptDataType();
}
@@ -122,6 +123,9 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
result.has_type = true;
switch (p_datatype.kind) {
+ case GDScriptParser::DataType::VARIANT: {
+ result.has_type = false;
+ } break;
case GDScriptParser::DataType::BUILTIN: {
result.kind = GDScriptDataType::BUILTIN;
result.builtin_type = p_datatype.builtin_type;
@@ -139,38 +143,48 @@ 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) {
- List<StringName> names;
- while (class_type->outer) {
- names.push_back(class_type->identifier->name);
- class_type = class_type->outer;
- }
-
- Ref<GDScript> script = Ref<GDScript>(main_script);
- while (names.back()) {
- if (!script->subclasses.has(names.back()->get())) {
- ERR_PRINT("Parser bug: Cannot locate datatype class.");
- result.has_type = false;
- return GDScriptDataType();
+ if (class_type->fqcn.begins_with(main_script->path) || (!main_script->name.empty() && class_type->fqcn.begins_with(main_script->name))) {
+ // Local class.
+ List<StringName> names;
+ while (class_type->outer) {
+ names.push_back(class_type->identifier->name);
+ class_type = class_type->outer;
+ }
+
+ Ref<GDScript> script = Ref<GDScript>(main_script);
+ while (names.back()) {
+ if (!script->subclasses.has(names.back()->get())) {
+ ERR_PRINT("Parser bug: Cannot locate datatype class.");
+ result.has_type = false;
+ return GDScriptDataType();
+ }
+ script = script->subclasses[names.back()->get()];
+ names.pop_back();
}
- script = script->subclasses[names.back()->get()];
- names.pop_back();
+ result.kind = GDScriptDataType::GDSCRIPT;
+ result.script_type = script;
+ result.native_type = script->get_instance_base_type();
+ } else {
+ result.kind = GDScriptDataType::GDSCRIPT;
+ result.script_type = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path);
+ result.native_type = p_datatype.native_type;
}
- result.kind = GDScriptDataType::GDSCRIPT;
- result.script_type = script;
- result.native_type = script->get_instance_base_type();
- } else {
- result.kind = GDScriptDataType::GDSCRIPT;
- result.script_type = p_datatype.script_type;
- result.native_type = result.script_type->get_instance_base_type();
}
-
} break;
+ 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();
}
- default:
- break; // FIXME
}
return result;
@@ -234,6 +248,66 @@ int GDScriptCompiler::_parse_assign_right_expression(CodeGen &codegen, const GDS
return dst_addr;
}
+bool GDScriptCompiler::_generate_typed_assign(CodeGen &codegen, int p_src_address, int p_dst_address, const GDScriptDataType &p_datatype, const GDScriptParser::DataType &p_value_type) {
+ if (p_datatype.has_type && p_value_type.is_variant()) {
+ // Typed assignment
+ switch (p_datatype.kind) {
+ case GDScriptDataType::BUILTIN: {
+ codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN); // perform operator
+ codegen.opcodes.push_back(p_datatype.builtin_type); // variable type
+ codegen.opcodes.push_back(p_dst_address); // argument 1
+ codegen.opcodes.push_back(p_src_address); // argument 2
+ } break;
+ case GDScriptDataType::NATIVE: {
+ int class_idx;
+ if (GDScriptLanguage::get_singleton()->get_global_map().has(p_datatype.native_type)) {
+ class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_datatype.native_type];
+ class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root)
+ } else {
+ // _set_error("Invalid native class type '" + String(p_datatype.native_type) + "'.", on->arguments[0]);
+ return false;
+ }
+ codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE); // perform operator
+ codegen.opcodes.push_back(class_idx); // variable type
+ codegen.opcodes.push_back(p_dst_address); // argument 1
+ codegen.opcodes.push_back(p_src_address); // argument 2
+ } break;
+ case GDScriptDataType::SCRIPT:
+ case GDScriptDataType::GDSCRIPT: {
+ Variant script = p_datatype.script_type;
+ int idx = codegen.get_constant_pos(script); //make it a local constant (faster access)
+
+ codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT); // perform operator
+ codegen.opcodes.push_back(idx); // variable type
+ codegen.opcodes.push_back(p_dst_address); // argument 1
+ codegen.opcodes.push_back(p_src_address); // argument 2
+ } break;
+ default: {
+ ERR_PRINT("Compiler bug: unresolved assign.");
+
+ // Shouldn't get here, but fail-safe to a regular assignment
+ codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN); // perform operator
+ codegen.opcodes.push_back(p_dst_address); // argument 1
+ codegen.opcodes.push_back(p_src_address); // argument 2 (unary only takes one parameter)
+ }
+ }
+ } else {
+ if (p_datatype.kind == GDScriptDataType::BUILTIN && p_value_type.kind == GDScriptParser::DataType::BUILTIN && p_datatype.builtin_type != p_value_type.builtin_type) {
+ // Need conversion.
+ codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN); // perform operator
+ codegen.opcodes.push_back(p_datatype.builtin_type); // variable type
+ codegen.opcodes.push_back(p_dst_address); // argument 1
+ codegen.opcodes.push_back(p_src_address); // argument 2
+ } else {
+ // Either untyped assignment or already type-checked by the parser
+ codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN); // perform operator
+ codegen.opcodes.push_back(p_dst_address); // argument 1
+ codegen.opcodes.push_back(p_src_address); // argument 2 (unary only takes one parameter)
+ }
+ }
+ return true;
+}
+
int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::ExpressionNode *p_expression, int p_stack_level, bool p_root, bool p_initializer, int p_index_addr) {
if (p_expression->is_constant) {
return codegen.get_constant_pos(p_expression->reduced_value);
@@ -368,15 +442,16 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
class_node = class_node->outer;
}
- if (class_node->identifier && class_node->identifier->name == identifier) {
- _set_error("Using own name in class file is not allowed (creates a cyclic reference)", p_expression);
- return -1;
- }
+ RES res;
- RES res = ResourceLoader::load(ScriptServer::get_global_class_path(identifier));
- if (res.is_null()) {
- _set_error("Can't load global class " + String(identifier) + ", cyclic reference?", p_expression);
- return -1;
+ if (class_node->identifier && class_node->identifier->name == identifier) {
+ res = Ref<GDScript>(main_script);
+ } else {
+ res = ResourceLoader::load(ScriptServer::get_global_class_path(identifier));
+ if (res.is_null()) {
+ _set_error("Can't load global class " + String(identifier) + ", cyclic reference?", p_expression);
+ return -1;
+ }
}
Variant key = res;
@@ -534,8 +609,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
codegen.alloc_stack(slevel);
}
- // FIXME: Allow actual cast.
- GDScriptDataType cast_type; // = _gdtype_from_datatype(cn->cast_type);
+ GDScriptDataType cast_type = _gdtype_from_datatype(cn->cast_type->get_datatype());
switch (cast_type.kind) {
case GDScriptDataType::BUILTIN: {
@@ -685,8 +759,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
arguments.push_back(ret);
arguments.push_back(codegen.get_name_map_pos(subscript->attribute->name));
} else {
- // TODO: Validate this at parse time.
- // TODO: Though might not be the case if callables are a thing.
_set_error("Cannot call something that isn't a function.", call->callee);
return -1;
}
@@ -1329,55 +1401,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
GDScriptDataType assign_type = _gdtype_from_datatype(assignment->assignee->get_datatype());
- if (assign_type.has_type && !assignment->assigned_value->get_datatype().is_variant()) {
- // Typed assignment
- switch (assign_type.kind) {
- case GDScriptDataType::BUILTIN: {
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN); // perform operator
- codegen.opcodes.push_back(assign_type.builtin_type); // variable type
- codegen.opcodes.push_back(dst_address_a); // argument 1
- codegen.opcodes.push_back(src_address_b); // argument 2
- } break;
- case GDScriptDataType::NATIVE: {
- int class_idx;
- if (GDScriptLanguage::get_singleton()->get_global_map().has(assign_type.native_type)) {
- class_idx = GDScriptLanguage::get_singleton()->get_global_map()[assign_type.native_type];
- class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root)
- } else {
- // _set_error("Invalid native class type '" + String(assign_type.native_type) + "'.", on->arguments[0]);
- return -1;
- }
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE); // perform operator
- codegen.opcodes.push_back(class_idx); // variable type
- codegen.opcodes.push_back(dst_address_a); // argument 1
- codegen.opcodes.push_back(src_address_b); // argument 2
- } break;
- case GDScriptDataType::SCRIPT:
- case GDScriptDataType::GDSCRIPT: {
- Variant script = assign_type.script_type;
- int idx = codegen.get_constant_pos(script); //make it a local constant (faster access)
-
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT); // perform operator
- codegen.opcodes.push_back(idx); // variable type
- codegen.opcodes.push_back(dst_address_a); // argument 1
- codegen.opcodes.push_back(src_address_b); // argument 2
- } break;
- default: {
- ERR_PRINT("Compiler bug: unresolved assign.");
-
- // Shouldn't get here, but fail-safe to a regular assignment
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN); // perform operator
- codegen.opcodes.push_back(dst_address_a); // argument 1
- codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter)
- }
- }
- } else {
- // Either untyped assignment or already type-checked by the parser
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN); // perform operator
- codegen.opcodes.push_back(dst_address_a); // argument 1
- codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter)
- }
-
if (has_setter && !is_in_setter) {
// Call setter.
codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL);
@@ -1387,6 +1410,8 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
codegen.opcodes.push_back(dst_address_a); // Argument.
codegen.opcodes.push_back(dst_address_a); // Result address (won't be used here).
codegen.alloc_call(1);
+ } else if (!_generate_typed_assign(codegen, src_address_b, dst_address_a, assign_type, assignment->assigned_value->get_datatype())) {
+ return -1;
}
return dst_address_a; //if anything, returns wathever was assigned or correct stack position
@@ -1662,7 +1687,7 @@ Error GDScriptCompiler::_parse_match_pattern(CodeGen &codegen, const GDScriptPar
// Evaluate element by element.
for (int i = 0; i < p_pattern->dictionary.size(); i++) {
const GDScriptParser::PatternNode::Pair &element = p_pattern->dictionary[i];
- if (element.value_pattern->pattern_type == GDScriptParser::PatternNode::PT_REST) {
+ if (element.value_pattern && element.value_pattern->pattern_type == GDScriptParser::PatternNode::PT_REST) {
// Ignore rest pattern.
continue;
}
@@ -1698,28 +1723,30 @@ Error GDScriptCompiler::_parse_match_pattern(CodeGen &codegen, const GDScriptPar
r_patch_addresses.push_back(codegen.opcodes.size());
codegen.opcodes.push_back(0); // Will be replaced.
- // Get actual value from user dictionary.
- int value_addr = stlevel++;
- codegen.alloc_stack(stlevel);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_GET);
- codegen.opcodes.push_back(p_value_addr); // Source.
- codegen.opcodes.push_back(pattern_key_addr); // Index.
- codegen.opcodes.push_back(value_addr); // Destination.
-
- // Also get type of value.
- int value_type_addr = stlevel++;
- value_type_addr |= GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
- codegen.alloc_stack(stlevel);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL_BUILT_IN);
- codegen.opcodes.push_back(GDScriptFunctions::TYPE_OF);
- codegen.opcodes.push_back(1); // One argument.
- codegen.opcodes.push_back(value_addr); // Argument is the value we want to test.
- codegen.opcodes.push_back(value_type_addr); // Address to result.
-
- // Try the pattern inside the value.
- Error err = _parse_match_pattern(codegen, element.value_pattern, stlevel, value_addr, value_type_addr, r_bound_variables, r_patch_addresses, element_block_patches);
- if (err != OK) {
- return err;
+ if (element.value_pattern != nullptr) {
+ // Get actual value from user dictionary.
+ int value_addr = stlevel++;
+ codegen.alloc_stack(stlevel);
+ codegen.opcodes.push_back(GDScriptFunction::OPCODE_GET);
+ codegen.opcodes.push_back(p_value_addr); // Source.
+ codegen.opcodes.push_back(pattern_key_addr); // Index.
+ codegen.opcodes.push_back(value_addr); // Destination.
+
+ // Also get type of value.
+ int value_type_addr = stlevel++;
+ value_type_addr |= GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
+ codegen.alloc_stack(stlevel);
+ codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL_BUILT_IN);
+ codegen.opcodes.push_back(GDScriptFunctions::TYPE_OF);
+ codegen.opcodes.push_back(1); // One argument.
+ codegen.opcodes.push_back(value_addr); // Argument is the value we want to test.
+ codegen.opcodes.push_back(value_type_addr); // Address to result.
+
+ // Try the pattern inside the value.
+ Error err = _parse_match_pattern(codegen, element.value_pattern, stlevel, value_addr, value_type_addr, r_bound_variables, r_patch_addresses, element_block_patches);
+ if (err != OK) {
+ return err;
+ }
}
// Patch jumps to block to try the next element.
@@ -2055,20 +2082,19 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
if (src_address < 0) {
return ERR_PARSE_ERROR;
}
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN);
- codegen.opcodes.push_back(dst_address);
- codegen.opcodes.push_back(src_address);
+ if (!_generate_typed_assign(codegen, src_address, dst_address, _gdtype_from_datatype(lv->get_datatype()), lv->initializer->get_datatype())) {
+ return ERR_PARSE_ERROR;
+ }
}
} break;
case GDScriptParser::Node::CONSTANT: {
// Local constants.
const GDScriptParser::ConstantNode *lc = static_cast<const GDScriptParser::ConstantNode *>(s);
- // FIXME: Need to properly reduce expressions to avoid limiting this so much.
- if (lc->initializer->type != GDScriptParser::Node::LITERAL) {
- _set_error("Local constant must have a literal as initializer.", lc->initializer);
+ if (!lc->initializer->is_constant) {
+ _set_error("Local constant must have a constant value as initializer.", lc->initializer);
return ERR_PARSE_ERROR;
}
- codegen.local_named_constants[lc->identifier->name] = codegen.get_constant_pos(static_cast<const GDScriptParser::LiteralNode *>(lc->initializer)->value);
+ codegen.local_named_constants[lc->identifier->name] = codegen.get_constant_pos(lc->initializer->reduced_value);
} break;
case GDScriptParser::Node::PASS:
// Nothing to do.
@@ -2158,9 +2184,9 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
int dst_address = codegen.script->member_indices[field->identifier->name].index;
dst_address |= GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS;
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN);
- codegen.opcodes.push_back(dst_address);
- codegen.opcodes.push_back(src_address);
+ if (!_generate_typed_assign(codegen, src_address, dst_address, _gdtype_from_datatype(field->get_datatype()), field->initializer->get_datatype())) {
+ return ERR_PARSE_ERROR;
+ }
}
}
}
@@ -2188,9 +2214,9 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
int dst_address = codegen.script->member_indices[field->identifier->name].index;
dst_address |= GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS;
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN);
- codegen.opcodes.push_back(dst_address);
- codegen.opcodes.push_back(src_address);
+ if (!_generate_typed_assign(codegen, src_address, dst_address, _gdtype_from_datatype(field->get_datatype()), field->initializer->get_datatype())) {
+ return ERR_PARSE_ERROR;
+ }
}
}
}
@@ -2209,9 +2235,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
if (src_addr < 0) {
return ERR_PARSE_ERROR;
}
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN);
- codegen.opcodes.push_back(codegen.stack_identifiers[p_func->parameters[i]->identifier->name] | (GDScriptFunction::ADDR_TYPE_STACK_VARIABLE << GDScriptFunction::ADDR_BITS));
- codegen.opcodes.push_back(src_addr);
+ int dst_addr = codegen.stack_identifiers[p_func->parameters[i]->identifier->name] | (GDScriptFunction::ADDR_TYPE_STACK_VARIABLE << GDScriptFunction::ADDR_BITS);
+ if (!_generate_typed_assign(codegen, src_addr, dst_addr, _gdtype_from_datatype(p_func->parameters[i]->get_datatype()), p_func->parameters[i]->default_value->get_datatype())) {
+ return ERR_PARSE_ERROR;
+ }
defarg_addr.push_back(codegen.opcodes.size());
}
defarg_addr.invert();
@@ -2247,12 +2274,11 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
if (p_func) {
gdfunc->_static = p_func->is_static;
gdfunc->rpc_mode = p_func->rpc_mode;
- // FIXME: Add actual parameters types;
gdfunc->argument_types.resize(p_func->parameters.size());
for (int i = 0; i < p_func->parameters.size(); i++) {
- gdfunc->argument_types.write[i] = GDScriptDataType(); //_gdtype_from_datatype(p_func->argument_types[i]);
+ gdfunc->argument_types.write[i] = _gdtype_from_datatype(p_func->parameters[i]->get_datatype());
}
- gdfunc->return_type = GDScriptDataType(); //_gdtype_from_datatype(p_func->return_type);
+ gdfunc->return_type = _gdtype_from_datatype(p_func->get_datatype());
} else {
gdfunc->_static = false;
gdfunc->rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
@@ -2432,7 +2458,7 @@ Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptP
gdfunc->_static = false;
gdfunc->rpc_mode = p_variable->rpc_mode;
gdfunc->argument_types.resize(p_is_setter ? 1 : 0);
- gdfunc->return_type = GDScriptDataType(); // TODO
+ gdfunc->return_type = _gdtype_from_datatype(p_variable->get_datatype());
#ifdef TOOLS_ENABLED
gdfunc->arg_names = argnames;
#endif
@@ -2581,7 +2607,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
Ref<GDScript> base = base_type.script_type;
p_script->base = base;
p_script->_base = base.ptr();
- p_script->member_indices = base->member_indices;
if (p_class->base_type.kind == GDScriptParser::DataType::CLASS && p_class->base_type.class_type != nullptr) {
if (!parsed_classes.has(p_script->_base)) {
@@ -2596,6 +2621,8 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
}
}
}
+
+ p_script->member_indices = base->member_indices;
} break;
default: {
_set_error("Parser bug: invalid inheritance.", p_class);
@@ -2633,8 +2660,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
break;
}
minfo.rpc_mode = variable->rpc_mode;
- // FIXME: Types.
- // minfo.data_type = _gdtype_from_datatype(p_class->variables[i].data_type);
+ minfo.data_type = _gdtype_from_datatype(variable->get_datatype());
PropertyInfo prop_info = minfo.data_type;
prop_info.name = name;
@@ -2965,7 +2991,7 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri
return err;
}
- return OK;
+ return GDScriptCache::finish_compiling(p_script->get_path());
}
String GDScriptCompiler::get_error() const {