Move inheritance resolution to the parser

This commit is contained in:
George Marques 2018-05-29 23:16:52 -03:00
parent 8aab9a06d4
commit b7a00aead0
No known key found for this signature in database
GPG key ID: 046BD46A3201E43D
5 changed files with 396 additions and 235 deletions

View file

@ -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<const GDScriptParser::ClassNode *>(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<GDScript> 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;
}

View file

@ -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<<GDScriptFunction::ADDR_BITS); //make it a local constant (faster access)
}*/
if (GDScriptLanguage::get_singleton()->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<StringName, Ref<GDScript> > 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<GDScriptNativeClass>();
@ -1686,177 +1688,46 @@ Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, cons
Ref<GDScriptNativeClass> native;
if (p_class->extends_used) {
//do inheritance
String path = p_class->extends_file;
Ref<GDScript> 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<Script> subclass = script->subclasses[sub]; //avoid reference from disappearing
script = subclass;
} else {
_set_error("Could not find subclass: " + sub, p_class);
return ERR_FILE_NOT_FOUND;
}
}
}
} else {
ERR_FAIL_COND_V(p_class->extends_class.size() == 0, ERR_BUG);
//look around for the subclasses
String base = p_class->extends_class[0];
GDScript *p = p_owner;
Ref<GDScript> base_class;
while (p) {
if (p->subclasses.has(base)) {
base_class = p->subclasses[base];
break;
}
if (p->constants.has(base)) {
base_class = p->constants[base];
if (base_class.is_null()) {
_set_error("Constant is not a class: " + base, p_class);
return ERR_SCRIPT_FAILED;
}
break;
}
p = p->_owner;
}
if (base_class.is_valid()) {
String ident = base;
for (int i = 1; i < p_class->extends_class.size(); i++) {
String subclass = p_class->extends_class[i];
ident += ("." + subclass);
if (base_class->subclasses.has(subclass)) {
base_class = base_class->subclasses[subclass];
} else if (base_class->constants.has(subclass)) {
Ref<GDScript> new_base_class = base_class->constants[subclass];
if (new_base_class.is_null()) {
_set_error("Constant is not a class: " + ident, p_class);
return ERR_SCRIPT_FAILED;
}
base_class = new_base_class;
} else {
_set_error("Could not find subclass: " + ident, p_class);
return ERR_FILE_NOT_FOUND;
}
}
script = base_class;
} else {
if (p_class->extends_class.size() > 1) {
_set_error("Invalid inheritance (unknown class+subclasses)", p_class);
return ERR_FILE_NOT_FOUND;
}
//if not found, try engine classes
if (!GDScriptLanguage::get_singleton()->get_global_map().has(base)) {
_set_error("Unknown class: '" + base + "'", p_class);
return ERR_FILE_NOT_FOUND;
}
int base_idx = GDScriptLanguage::get_singleton()->get_global_map()[base];
native = GDScriptLanguage::get_singleton()->get_global_array()[base_idx];
if (!native.is_valid()) {
_set_error("Global not a class: '" + base + "'", p_class);
return ERR_FILE_NOT_FOUND;
}
}
}
if (script.is_valid()) {
p_script->base = script;
Ref<GDScript> base = class_map[base_name];
p_script->base = base;
p_script->_base = p_script->base.ptr();
p_script->member_indices = script->member_indices;
} else if (native.is_valid()) {
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];
native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx];
ERR_FAIL_COND_V(native.is_null(), ERR_BUG);
p_script->native = native;
} else {
_set_error("Could not determine inheritance", p_class);
return ERR_FILE_NOT_FOUND;
}
} else {
// without extends, implicitly extend Reference
int native_idx = GDScriptLanguage::get_singleton()->get_global_map()["Reference"];
native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx];
ERR_FAIL_COND_V(native.is_null(), ERR_BUG);
p_script->native = native;
} break;
default: {
_set_error("Parser bug: invalid inheritance.", p_class);
return ERR_BUG;
} break;
}
//print_line("Script: "+p_script->get_path()+" indices: "+itos(p_script->member_indices.size()));
for (int i = 0; i < p_class->variables.size(); i++) {
StringName name = p_class->variables[i].identifier;
@ -1902,6 +1773,7 @@ Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, cons
for (int i = 0; i < p_class->constant_expressions.size(); i++) {
StringName name = p_class->constant_expressions[i].identifier;
ERR_CONTINUE(p_class->constant_expressions[i].expression->type != GDScriptParser::Node::TYPE_CONSTANT);
if (_is_class_member_property(p_script, name)) {
@ -1948,23 +1820,27 @@ Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, cons
p_script->_signals[name] = p_class->_signals[i].arguments;
}
if (p_class->name != StringName()) {
parsed_classes.insert(p_class->name);
}
//parse sub-classes
for (int i = 0; i < p_class->subclasses.size(); i++) {
StringName name = p_class->subclasses[i]->name;
Ref<GDScript> subclass;
Ref<GDScript> subclass = class_map[name];
if (old_subclasses.has(name)) {
subclass = old_subclasses[name];
} else {
subclass.instance();
// 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 (err)
return err;
parsing_classes.erase(name);
}
Error err = _parse_class(subclass.ptr(), p_script, p_class->subclasses[i], p_keep_state);
if (err)
return err;
#ifdef TOOLS_ENABLED
p_script->member_lines[name] = p_class->subclasses[i]->line;
@ -1974,6 +1850,11 @@ Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, cons
p_script->subclasses.insert(name, subclass);
}
p_script->valid = true;
return OK;
}
Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
//parse methods
bool has_initializer = false;
@ -2014,44 +1895,6 @@ Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, cons
}
#ifdef DEBUG_ENABLED
//validate setters/getters if debug is enabled
for (int i = 0; i < p_class->variables.size(); i++) {
if (p_class->variables[i].setter) {
const Map<StringName, GDScriptFunction *>::Element *E = p_script->get_member_functions().find(p_class->variables[i].setter);
if (!E) {
_set_error("Setter function '" + String(p_class->variables[i].setter) + "' not found in class.", NULL);
err_line = p_class->variables[i].line;
err_column = 0;
return ERR_PARSE_ERROR;
}
if (E->get()->is_static()) {
_set_error("Setter function '" + String(p_class->variables[i].setter) + "' is static.", NULL);
err_line = p_class->variables[i].line;
err_column = 0;
return ERR_PARSE_ERROR;
}
}
if (p_class->variables[i].getter) {
const Map<StringName, GDScriptFunction *>::Element *E = p_script->get_member_functions().find(p_class->variables[i].getter);
if (!E) {
_set_error("Getter function '" + String(p_class->variables[i].getter) + "' not found in class.", NULL);
err_line = p_class->variables[i].line;
err_column = 0;
return ERR_PARSE_ERROR;
}
if (E->get()->is_static()) {
_set_error("Getter function '" + String(p_class->variables[i].getter) + "' is static.", NULL);
err_line = p_class->variables[i].line;
err_column = 0;
return ERR_PARSE_ERROR;
}
}
}
//validate instances if keeping state
@ -2104,10 +1947,45 @@ Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, cons
}
#endif
p_script->valid = true;
for (int i = 0; i < p_class->subclasses.size(); i++) {
StringName name = p_class->subclasses[i]->name;
Ref<GDScript> subclass = class_map[name];
Error err = _parse_class_blocks(subclass.ptr(), p_class->subclasses[i], p_keep_state);
if (err) {
return err;
}
}
return OK;
}
void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
Map<StringName, Ref<GDScript> > old_subclasses;
if (p_keep_state) {
old_subclasses = p_script->subclasses;
}
for (int i = 0; i < p_class->subclasses.size(); i++) {
StringName name = p_class->subclasses[i]->name;
Ref<GDScript> subclass;
if (old_subclasses.has(name)) {
subclass = old_subclasses[name];
} else {
subclass.instance();
}
subclass->_owner = const_cast<GDScript *>(p_script);
class_map.insert(name, subclass);
_make_scripts(subclass.ptr(), p_class->subclasses[i], p_keep_state);
}
}
Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_script, bool p_keep_state) {
err_line = -1;
@ -2119,7 +1997,15 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri
source = p_script->get_path();
Error err = _parse_class(p_script, NULL, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state);
// 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);
if (err)
return err;
err = _parse_class_blocks(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state);
if (err)
return err;

View file

@ -31,12 +31,16 @@
#ifndef GDSCRIPT_COMPILER_H
#define GDSCRIPT_COMPILER_H
#include "core/set.h"
#include "gdscript.h"
#include "gdscript_parser.h"
class GDScriptCompiler {
const GDScriptParser *parser;
Map<StringName, Ref<GDScript> > class_map;
Set<StringName> parsed_classes;
Set<StringName> parsing_classes;
struct CodeGen {
GDScript *script;
@ -142,7 +146,9 @@ class GDScriptCompiler {
int _parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root = false, bool p_initializer = false);
Error _parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level = 0, int p_break_addr = -1, int p_continue_addr = -1);
Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false);
Error _parse_class(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
Error _parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
Error _parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
void _make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
int err_line;
int err_column;
StringName source;

View file

@ -3188,10 +3188,25 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
name = tokenizer->get_token_identifier(1);
tokenizer->advance(2);
// Check if name is shadowing something else
if (ClassDB::class_exists(name)) {
_set_error("Class '" + String(name) + "' shadows a native class.");
return;
}
if (ScriptServer::is_global_class(name)) {
_set_error("Can't override name of unique global class '" + name + "' already exists at path: " + ScriptServer::get_global_class_path(p_class->name));
return;
}
if (class_map.has(name)) {
_set_error("Class '" + String(name) + "' shadows another class in the file.");
return;
}
for (int i = 0; i < p_class->constant_expressions.size(); i++) {
if (p_class->constant_expressions[i].identifier == name) {
_set_error("Class '" + String(name) + "' shadows a constant of the outer class.");
return;
}
}
ClassNode *newclass = alloc_node<ClassNode>();
newclass->initializer = alloc_node<BlockNode>();
@ -3202,6 +3217,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
newclass->owner = p_class;
p_class->subclasses.push_back(newclass);
class_map.insert(name, newclass);
if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_EXTENDS) {
@ -4337,6 +4353,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
int line = tokenizer->get_token_line();
tokenizer->advance();
Node *subexpr = _parse_and_reduce_expression(p_class, true, true);
@ -4348,14 +4366,15 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
if (subexpr->type != Node::TYPE_CONSTANT) {
_set_error("Expected constant expression");
_set_error("Expected constant expression", line);
return;
}
constant.expression = subexpr;
p_class->constant_expressions.push_back(constant);
if (!_end_statement()) {
_set_error("Expected end of statement (constant)");
_set_error("Expected end of statement (constant)", line);
return;
}
@ -4415,17 +4434,19 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (subexpr->type != Node::TYPE_CONSTANT) {
_set_error("Expected constant expression");
return;
}
const ConstantNode *subexpr_const = static_cast<const ConstantNode *>(subexpr);
ConstantNode *subexpr_const = static_cast<ConstantNode *>(subexpr);
if (subexpr_const->value.get_type() != Variant::INT) {
_set_error("Expected an int value for enum");
return;
}
last_assign = subexpr_const->value;
constant.expression = subexpr;
constant.expression = subexpr_const;
} else {
last_assign = last_assign + 1;
@ -4483,6 +4504,212 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
}
void GDScriptParser::_determine_inheritance(ClassNode *p_class) {
if (p_class->extends_used) {
//do inheritance
String path = p_class->extends_file;
Ref<GDScript> script;
StringName native;
ClassNode *base_class = NULL;
if (path != "") {
//path (and optionally subclasses)
if (path.is_rel_path()) {
String base = self_path;
if (base == "" || base.is_rel_path()) {
_set_error("Could not resolve relative path for parent class: " + path, p_class->line);
return;
}
path = base.get_base_dir().plus_file(path).simplify_path();
}
script = ResourceLoader::load(path);
if (script.is_null()) {
_set_error("Could not load base class: " + path, p_class->line);
return;
}
if (!script->is_valid()) {
_set_error("Script not fully loaded (cyclic preload?): " + path, p_class->line);
return;
}
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->get_subclasses().has(sub)) {
Ref<Script> subclass = script->get_subclasses()[sub]; //avoid reference from disappearing
script = subclass;
} else {
_set_error("Could not find subclass: " + sub, p_class->line);
return;
}
}
}
} else {
if (p_class->extends_class.size() == 0) {
_set_error("Parser bug: undecidable inheritance.", p_class->line);
ERR_FAIL();
}
//look around for the subclasses
int extend_iter = 1;
String base = p_class->extends_class[0];
ClassNode *p = p_class->owner;
Ref<GDScript> base_script;
if (ScriptServer::is_global_class(base)) {
base_script = ResourceLoader::load(ScriptServer::get_global_class_path(base));
if (!base_script.is_valid()) {
_set_error("Class '" + base + "' could not be fully loaded (script error or cyclic inheritance).", p_class->line);
return;
}
p = NULL;
}
while (p) {
bool found = false;
for (int i = 0; i < p->subclasses.size(); i++) {
if (p->subclasses[i]->name == base) {
ClassNode *test = p->subclasses[i];
while (test) {
if (test == p_class) {
_set_error("Cyclic inheritance.", test->line);
return;
}
if (test->base_type.kind == DataType::CLASS) {
test = test->base_type.class_type;
} else {
break;
}
}
found = true;
if (extend_iter < p_class->extends_class.size()) {
// Keep looking at current classes if possible
base = p_class->extends_class[extend_iter++];
p = p->subclasses[i];
} else {
base_class = p->subclasses[i];
}
break;
}
}
if (base_class) break;
if (found) continue;
for (int i = 0; i < p->constant_expressions.size(); i++) {
if (p->constant_expressions[i].identifier == base) {
if (!p->constant_expressions[i].expression->type == Node::TYPE_CONSTANT) {
_set_error("Could not resolve constant '" + base + "'.", p_class->line);
return;
}
const ConstantNode *cn = static_cast<const ConstantNode *>(p->constant_expressions[i].expression);
base_script = cn->value;
if (base_script.is_null()) {
_set_error("Constant is not a class: " + base, p_class->line);
return;
}
found = true;
}
}
if (found) break;
p = p->owner;
}
if (base_script.is_valid()) {
String ident = base;
for (int i = extend_iter; i < p_class->extends_class.size(); i++) {
String subclass = p_class->extends_class[i];
ident += ("." + subclass);
if (base_script->get_subclasses().has(subclass)) {
base_script = base_script->get_subclasses()[subclass];
} else if (base_script->get_constants().has(subclass)) {
Ref<GDScript> new_base_class = base_script->get_constants()[subclass];
if (new_base_class.is_null()) {
_set_error("Constant is not a class: " + ident, p_class->line);
return;
}
base_script = new_base_class;
} else {
_set_error("Could not find subclass: " + ident, p_class->line);
return;
}
}
script = base_script;
} else if (!base_class) {
if (p_class->extends_class.size() > 1) {
_set_error("Invalid inheritance (unknown class + subclasses)", p_class->line);
return;
}
//if not found, try engine classes
if (!GDScriptLanguage::get_singleton()->get_global_map().has(base)) {
_set_error("Unknown class: '" + base + "'", p_class->line);
return;
}
native = base;
}
}
if (base_class) {
p_class->base_type.has_type = true;
p_class->base_type.kind = DataType::CLASS;
p_class->base_type.class_type = base_class;
} else if (script.is_valid()) {
p_class->base_type.has_type = true;
p_class->base_type.kind = DataType::GDSCRIPT;
p_class->base_type.script_type = script;
p_class->base_type.native_type = script->get_instance_base_type();
} else if (native != StringName()) {
p_class->base_type.has_type = true;
p_class->base_type.kind = DataType::NATIVE;
p_class->base_type.native_type = native;
} else {
_set_error("Could not determine inheritance", p_class->line);
return;
}
} else {
// without extends, implicitly extend Reference
p_class->base_type.has_type = true;
p_class->base_type.kind = DataType::NATIVE;
p_class->base_type.native_type = "Reference";
}
// Recursively determine subclasses
for (int i = 0; i < p_class->subclasses.size(); i++) {
_determine_inheritance(p_class->subclasses[i]);
}
}
bool GDScriptParser::_parse_type(DataType &r_type, bool p_can_be_void) {
tokenizer->advance();
@ -4553,9 +4780,15 @@ Error GDScriptParser::_parse(const String &p_base_path) {
}
if (error_set) {
return ERR_PARSE_ERROR;
}
_determine_inheritance(main_class);
if (error_set) {
return ERR_PARSE_ERROR;
}
return OK;
}

View file

@ -107,6 +107,7 @@ public:
struct FunctionNode;
struct BlockNode;
struct ConstantNode;
struct ClassNode : public Node {
@ -115,6 +116,7 @@ public:
bool extends_used;
StringName extends_file;
Vector<StringName> extends_class;
DataType base_type;
struct Member {
PropertyInfo _export;
@ -446,6 +448,7 @@ private:
ClassNode *current_class;
FunctionNode *current_function;
BlockNode *current_block;
Map<StringName, ClassNode *> class_map;
bool _get_completable_identifier(CompletionType p_type, StringName &identifier);
void _make_completable_call(int p_arg);
@ -487,6 +490,7 @@ private:
void _parse_class(ClassNode *p_class);
bool _end_statement();
void _determine_inheritance(ClassNode *p_class);
bool _parse_type(DataType &r_type, bool p_can_be_void = false);
Error _parse(const String &p_base_path);