From b7a00aead039a988f9e224ef5ad19688a17c971c Mon Sep 17 00:00:00 2001 From: George Marques Date: Tue, 29 May 2018 23:16:52 -0300 Subject: [PATCH] Move inheritance resolution to the parser --- modules/gdscript/gdscript.cpp | 36 ++- modules/gdscript/gdscript_compiler.cpp | 340 ++++++++----------------- modules/gdscript/gdscript_compiler.h | 8 +- modules/gdscript/gdscript_parser.cpp | 243 +++++++++++++++++- modules/gdscript/gdscript_parser.h | 4 + 5 files changed, 396 insertions(+), 235 deletions(-) diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index f221aac5fea..ae8dcfc3707 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1826,8 +1826,40 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b if (parser.get_parse_tree() && parser.get_parse_tree()->type == GDScriptParser::Node::TYPE_CLASS) { const GDScriptParser::ClassNode *c = static_cast(parser.get_parse_tree()); - if (r_base_type && c->extends_used && c->extends_class.size() == 1) { - *r_base_type = c->extends_class[0]; //todo, should work much better + if (r_base_type) { + GDScriptParser::DataType base_type; + if (c->base_type.has_type) { + base_type = c->base_type; + while (base_type.has_type && base_type.kind != GDScriptParser::DataType::NATIVE) { + switch (base_type.kind) { + case GDScriptParser::DataType::CLASS: { + base_type = base_type.class_type->base_type; + } break; + case GDScriptParser::DataType::GDSCRIPT: { + Ref gds = base_type.script_type; + if (gds.is_valid()) { + base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.native_type = gds->get_instance_base_type(); + } else { + base_type = GDScriptParser::DataType(); + } + } break; + default: { + base_type = GDScriptParser::DataType(); + } break; + } + } + } + if (base_type.has_type) { + *r_base_type = base_type.native_type; + } else { + // Fallback + if (c->extends_used && c->extends_class.size() == 1) { + *r_base_type = c->extends_class[0]; + } else if (!c->extends_used) { + *r_base_type = "Reference"; + } + } } return c->name; } diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 69a0575efe6..f15b4b83b9a 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -263,15 +263,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: owner = owner->_owner; } - /* - handled in constants now - if (codegen.script->subclasses.has(identifier)) { - //same with a subclass, make it a local constant. - int idx = codegen.get_constant_pos(codegen.script->subclasses[identifier]); - return idx|(GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT<get_global_map().has(identifier)) { int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier]; @@ -1657,12 +1648,23 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser return OK; } -Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { +Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { - Map > old_subclasses; - - if (p_keep_state) { - old_subclasses = p_script->subclasses; + 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); + 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); + if (err) { + return err; + } + parsing_classes.erase(owner_name); + } } p_script->native = Ref(); @@ -1686,177 +1688,46 @@ Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, cons Ref native; - if (p_class->extends_used) { - //do inheritance - String path = p_class->extends_file; - - Ref script; - - if (path != "") { - //path (and optionally subclasses) - - if (path.is_rel_path()) { - - String base; - - if (p_owner) { - GDScript *current_class = p_owner; - while (current_class != NULL) { - base = current_class->get_path(); - if (base == "") - current_class = current_class->_owner; - else - break; - } - } else { - base = p_script->get_path(); + // 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; } - - if (base == "" || base.is_rel_path()) { - _set_error("Could not resolve relative path for parent class: " + path, p_class); - return ERR_FILE_NOT_FOUND; + 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; } - path = base.get_base_dir().plus_file(path).simplify_path(); + parsing_classes.erase(base_name); } - script = ResourceLoader::load(path); - if (script.is_null()) { - _set_error("Could not load base class: " + path, p_class); - return ERR_FILE_NOT_FOUND; - } - if (!script->valid) { - - _set_error("Script not fully loaded (cyclic preload?): " + path, p_class); - return ERR_BUSY; - } - //print_line("EXTENDS PATH: "+path+" script is "+itos(script.is_valid())+" indices is "+itos(script->member_indices.size())+" valid? "+itos(script->valid)); - - if (p_class->extends_class.size()) { - - for (int i = 0; i < p_class->extends_class.size(); i++) { - - String sub = p_class->extends_class[i]; - if (script->subclasses.has(sub)) { - - Ref