|
@@ -139,17 +139,32 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
|
|
|
result.native_type = result.script_type->get_instance_base_type();
|
|
|
} break;
|
|
|
case GDScriptParser::DataType::CLASS: {
|
|
|
- result.kind = GDScriptDataType::GDSCRIPT;
|
|
|
- if (!p_datatype.class_type->owner) {
|
|
|
- result.script_type = Ref<GDScript>(main_script);
|
|
|
- } else {
|
|
|
- result.script_type = class_map[p_datatype.class_type->name];
|
|
|
+ // Locate class by constructing the path to it and following that path
|
|
|
+ GDScriptParser::ClassNode *class_type = p_datatype.class_type;
|
|
|
+ List<StringName> names;
|
|
|
+ while (class_type->owner) {
|
|
|
+ names.push_back(class_type->name);
|
|
|
+ class_type = class_type->owner;
|
|
|
}
|
|
|
- result.native_type = result.script_type->get_instance_base_type();
|
|
|
+
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+
|
|
|
+ result.kind = GDScriptDataType::GDSCRIPT;
|
|
|
+ result.script_type = script;
|
|
|
+ result.native_type = script->get_instance_base_type();
|
|
|
} break;
|
|
|
default: {
|
|
|
ERR_PRINT("Parser bug: converting unresolved type.");
|
|
|
- result.has_type = false;
|
|
|
+ return GDScriptDataType();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -460,12 +475,14 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
|
|
|
codegen.alloc_stack(slevel);
|
|
|
}
|
|
|
|
|
|
- switch (cn->cast_type.kind) {
|
|
|
- case GDScriptParser::DataType::BUILTIN: {
|
|
|
+ GDScriptDataType cast_type = _gdtype_from_datatype(cn->cast_type);
|
|
|
+
|
|
|
+ switch (cast_type.kind) {
|
|
|
+ case GDScriptDataType::BUILTIN: {
|
|
|
codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_BUILTIN);
|
|
|
codegen.opcodes.push_back(cn->cast_type.builtin_type);
|
|
|
} break;
|
|
|
- case GDScriptParser::DataType::NATIVE: {
|
|
|
+ case GDScriptDataType::NATIVE: {
|
|
|
int class_idx;
|
|
|
if (GDScriptLanguage::get_singleton()->get_global_map().has(cn->cast_type.native_type)) {
|
|
|
|
|
@@ -478,32 +495,8 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
|
|
|
codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_NATIVE); // perform operator
|
|
|
codegen.opcodes.push_back(class_idx); // variable type
|
|
|
} break;
|
|
|
- case GDScriptParser::DataType::CLASS: {
|
|
|
-
|
|
|
- Variant script;
|
|
|
- int idx = -1;
|
|
|
- if (!cn->cast_type.class_type->owner) {
|
|
|
- script = codegen.script;
|
|
|
- } else {
|
|
|
- StringName name = cn->cast_type.class_type->name;
|
|
|
- if (codegen.script->subclasses.has(name) && class_map[name] == codegen.script->subclasses[name]) {
|
|
|
- idx = codegen.get_name_map_pos(name);
|
|
|
- idx |= GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS;
|
|
|
- } else {
|
|
|
- script = class_map[name];
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (idx < 0) {
|
|
|
- idx = codegen.get_constant_pos(script);
|
|
|
- idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access)
|
|
|
- }
|
|
|
-
|
|
|
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_SCRIPT); // perform operator
|
|
|
- codegen.opcodes.push_back(idx); // variable type
|
|
|
- } break;
|
|
|
- case GDScriptParser::DataType::SCRIPT:
|
|
|
- case GDScriptParser::DataType::GDSCRIPT: {
|
|
|
+ case GDScriptDataType::SCRIPT:
|
|
|
+ case GDScriptDataType::GDSCRIPT: {
|
|
|
|
|
|
Variant script = cn->cast_type.script_type;
|
|
|
int idx = codegen.get_constant_pos(script);
|
|
@@ -1149,18 +1142,18 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
|
|
|
if (src_address_b < 0)
|
|
|
return -1;
|
|
|
|
|
|
- GDScriptParser::DataType assign_type = on->arguments[0]->get_datatype();
|
|
|
+ GDScriptDataType assign_type = _gdtype_from_datatype(on->arguments[0]->get_datatype());
|
|
|
|
|
|
if (assign_type.has_type && !on->arguments[1]->get_datatype().has_type) {
|
|
|
// Typed assignment
|
|
|
switch (assign_type.kind) {
|
|
|
- case GDScriptParser::DataType::BUILTIN: {
|
|
|
+ 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 GDScriptParser::DataType::NATIVE: {
|
|
|
+ case GDScriptDataType::NATIVE: {
|
|
|
int class_idx;
|
|
|
if (GDScriptLanguage::get_singleton()->get_global_map().has(assign_type.native_type)) {
|
|
|
|
|
@@ -1175,34 +1168,8 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
|
|
|
codegen.opcodes.push_back(dst_address_a); // argument 1
|
|
|
codegen.opcodes.push_back(src_address_b); // argument 2
|
|
|
} break;
|
|
|
- case GDScriptParser::DataType::CLASS: {
|
|
|
-
|
|
|
- Variant script;
|
|
|
- int idx = -1;
|
|
|
- if (!assign_type.class_type->owner) {
|
|
|
- script = codegen.script;
|
|
|
- } else {
|
|
|
- StringName name = assign_type.class_type->name;
|
|
|
- if (codegen.script->subclasses.has(name) && class_map[name] == codegen.script->subclasses[name]) {
|
|
|
- idx = codegen.get_name_map_pos(name);
|
|
|
- idx |= GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS;
|
|
|
- } else {
|
|
|
- script = class_map[name];
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (idx < 0) {
|
|
|
- idx = codegen.get_constant_pos(script);
|
|
|
- idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //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;
|
|
|
- case GDScriptParser::DataType::SCRIPT:
|
|
|
- case GDScriptParser::DataType::GDSCRIPT: {
|
|
|
+ case GDScriptDataType::SCRIPT:
|
|
|
+ case GDScriptDataType::GDSCRIPT: {
|
|
|
|
|
|
Variant script = assign_type.script_type;
|
|
|
int idx = codegen.get_constant_pos(script);
|
|
@@ -1850,22 +1817,21 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
|
|
|
return OK;
|
|
|
}
|
|
|
|
|
|
-Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
|
|
|
+Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
|
|
|
+
|
|
|
+ parsing_classes.insert(p_script);
|
|
|
|
|
|
if (p_class->owner && p_class->owner->owner) {
|
|
|
// Owner is not root
|
|
|
- StringName owner_name = p_class->owner->name;
|
|
|
- if (!parsed_classes.has(owner_name)) {
|
|
|
- if (parsing_classes.has(owner_name)) {
|
|
|
- _set_error("Cyclic class reference for '" + String(owner_name) + "'.", p_class);
|
|
|
+ if (!parsed_classes.has(p_script->_owner)) {
|
|
|
+ if (parsing_classes.has(p_script->_owner)) {
|
|
|
+ _set_error("Cyclic class reference for '" + String(p_class->name) + "'.", p_class);
|
|
|
return ERR_PARSE_ERROR;
|
|
|
}
|
|
|
- parsing_classes.insert(owner_name);
|
|
|
- Error err = _parse_class_level(class_map[owner_name].ptr(), class_map[owner_name]->_owner, p_class->owner, p_keep_state);
|
|
|
+ Error err = _parse_class_level(p_script->_owner, p_class->owner, p_keep_state);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
|
- parsing_classes.erase(owner_name);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1883,47 +1849,26 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
|
|
|
p_script->_signals.clear();
|
|
|
p_script->initializer = NULL;
|
|
|
|
|
|
- p_script->subclasses.clear();
|
|
|
- p_script->_owner = p_owner;
|
|
|
p_script->tool = p_class->tool;
|
|
|
p_script->name = p_class->name;
|
|
|
|
|
|
Ref<GDScriptNativeClass> native;
|
|
|
|
|
|
+ GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type);
|
|
|
// Inheritance
|
|
|
- switch (p_class->base_type.kind) {
|
|
|
- case GDScriptParser::DataType::CLASS: {
|
|
|
- StringName base_name = p_class->base_type.class_type->name;
|
|
|
- // Make sure dependency is parsed first
|
|
|
- if (!parsed_classes.has(base_name)) {
|
|
|
- if (parsing_classes.has(base_name)) {
|
|
|
- _set_error("Cyclic class reference for '" + String(base_name) + "'.", p_class);
|
|
|
- return ERR_PARSE_ERROR;
|
|
|
- }
|
|
|
- parsing_classes.insert(base_name);
|
|
|
- Error err = _parse_class_level(class_map[base_name].ptr(), class_map[base_name]->_owner, p_class->base_type.class_type, p_keep_state);
|
|
|
- if (err) {
|
|
|
- return err;
|
|
|
- }
|
|
|
- parsing_classes.erase(base_name);
|
|
|
- }
|
|
|
- Ref<GDScript> base = class_map[base_name];
|
|
|
- p_script->base = base;
|
|
|
- p_script->_base = p_script->base.ptr();
|
|
|
- p_script->member_indices = base->member_indices;
|
|
|
- } break;
|
|
|
- case GDScriptParser::DataType::GDSCRIPT: {
|
|
|
- Ref<GDScript> base = p_class->base_type.script_type;
|
|
|
- p_script->base = base;
|
|
|
- p_script->_base = p_script->base.ptr();
|
|
|
- p_script->member_indices = base->member_indices;
|
|
|
- } break;
|
|
|
- case GDScriptParser::DataType::NATIVE: {
|
|
|
- int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_class->base_type.native_type];
|
|
|
+ switch (base_type.kind) {
|
|
|
+ case GDScriptDataType::NATIVE: {
|
|
|
+ int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[base_type.native_type];
|
|
|
native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx];
|
|
|
ERR_FAIL_COND_V(native.is_null(), ERR_BUG);
|
|
|
p_script->native = native;
|
|
|
} break;
|
|
|
+ case GDScriptDataType::GDSCRIPT: {
|
|
|
+ Ref<GDScript> base = base_type.script_type;
|
|
|
+ p_script->base = base;
|
|
|
+ p_script->_base = base.ptr();
|
|
|
+ p_script->member_indices = base->member_indices;
|
|
|
+ } break;
|
|
|
default: {
|
|
|
_set_error("Parser bug: invalid inheritance.", p_class);
|
|
|
return ERR_BUG;
|
|
@@ -2017,24 +1962,19 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
|
|
|
p_script->_signals[name] = p_class->_signals[i].arguments;
|
|
|
}
|
|
|
|
|
|
- if (p_class->owner) {
|
|
|
- parsed_classes.insert(p_class->name);
|
|
|
- if (parsing_classes.has(p_class->name)) {
|
|
|
- parsing_classes.erase(p_class->name);
|
|
|
- }
|
|
|
- }
|
|
|
+ parsed_classes.insert(p_script);
|
|
|
+ parsing_classes.erase(p_script);
|
|
|
|
|
|
//parse sub-classes
|
|
|
|
|
|
for (int i = 0; i < p_class->subclasses.size(); i++) {
|
|
|
StringName name = p_class->subclasses[i]->name;
|
|
|
|
|
|
- Ref<GDScript> subclass = class_map[name];
|
|
|
+ GDScript *subclass = p_script->subclasses[name].ptr();
|
|
|
|
|
|
// Subclass might still be parsing, just skip it
|
|
|
- if (!parsed_classes.has(name) && !parsing_classes.has(name)) {
|
|
|
- parsing_classes.insert(name);
|
|
|
- Error err = _parse_class_level(subclass.ptr(), p_script, p_class->subclasses[i], p_keep_state);
|
|
|
+ if (!parsed_classes.has(subclass) && !parsing_classes.has(subclass)) {
|
|
|
+ Error err = _parse_class_level(subclass, p_class->subclasses[i], p_keep_state);
|
|
|
if (err)
|
|
|
return err;
|
|
|
}
|
|
@@ -2045,7 +1985,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
|
|
|
#endif
|
|
|
|
|
|
p_script->constants.insert(name, subclass); //once parsed, goes to the list of constants
|
|
|
- p_script->subclasses.insert(name, subclass);
|
|
|
}
|
|
|
|
|
|
return OK;
|
|
@@ -2144,9 +2083,9 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
|
|
|
|
|
|
for (int i = 0; i < p_class->subclasses.size(); i++) {
|
|
|
StringName name = p_class->subclasses[i]->name;
|
|
|
- Ref<GDScript> subclass = class_map[name];
|
|
|
+ GDScript *subclass = p_script->subclasses[name].ptr();
|
|
|
|
|
|
- Error err = _parse_class_blocks(subclass.ptr(), p_class->subclasses[i], p_keep_state);
|
|
|
+ Error err = _parse_class_blocks(subclass, p_class->subclasses[i], p_keep_state);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
@@ -2156,7 +2095,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
|
|
|
return OK;
|
|
|
}
|
|
|
|
|
|
-void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
|
|
|
+void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
|
|
|
|
|
|
Map<StringName, Ref<GDScript> > old_subclasses;
|
|
|
|
|
@@ -2164,6 +2103,8 @@ void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptPar
|
|
|
old_subclasses = p_script->subclasses;
|
|
|
}
|
|
|
|
|
|
+ p_script->subclasses.clear();
|
|
|
+
|
|
|
for (int i = 0; i < p_class->subclasses.size(); i++) {
|
|
|
StringName name = p_class->subclasses[i]->name;
|
|
|
|
|
@@ -2175,10 +2116,10 @@ void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptPar
|
|
|
subclass.instance();
|
|
|
}
|
|
|
|
|
|
- subclass->_owner = const_cast<GDScript *>(p_script);
|
|
|
- class_map.insert(name, subclass);
|
|
|
+ subclass->_owner = p_script;
|
|
|
+ p_script->subclasses.insert(name, subclass);
|
|
|
|
|
|
- _make_scripts(subclass.ptr(), p_class->subclasses[i], p_keep_state);
|
|
|
+ _make_scripts(subclass.ptr(), p_class->subclasses[i], false);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2197,7 +2138,8 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri
|
|
|
// Create scripts for subclasses beforehand so they can be referenced
|
|
|
_make_scripts(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state);
|
|
|
|
|
|
- Error err = _parse_class_level(p_script, NULL, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state);
|
|
|
+ p_script->_owner = NULL;
|
|
|
+ Error err = _parse_class_level(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state);
|
|
|
|
|
|
if (err)
|
|
|
return err;
|