You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-05 12:10:55 +00:00
Add a dependency search mode for GDScript parser
- This mode avoids loading any other resource. - Search for class_name now uses this mode, to avoid loading in the scan thread. - Implement get_dependencies() for GDScript loader, now exporting dependencies only should include the preloaded resources.
This commit is contained in:
@@ -1840,68 +1840,86 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
|
|||||||
return String();
|
return String();
|
||||||
}
|
}
|
||||||
|
|
||||||
int len = f->get_len();
|
String source = f->get_as_utf8_string();
|
||||||
sourcef.resize(len + 1);
|
|
||||||
PoolVector<uint8_t>::Write w = sourcef.write();
|
|
||||||
int r = f->get_buffer(w.ptr(), len);
|
|
||||||
f->close();
|
|
||||||
memdelete(f);
|
|
||||||
ERR_FAIL_COND_V(r != len, String());
|
|
||||||
w[len] = 0;
|
|
||||||
|
|
||||||
String s;
|
|
||||||
if (s.parse_utf8((const char *)w.ptr())) {
|
|
||||||
return String();
|
|
||||||
}
|
|
||||||
|
|
||||||
GDScriptParser parser;
|
GDScriptParser parser;
|
||||||
|
parser.parse(source, p_path.get_base_dir(), true, p_path, false, NULL, true);
|
||||||
parser.parse(s, p_path.get_base_dir(), true, p_path);
|
|
||||||
|
|
||||||
if (parser.get_parse_tree() && parser.get_parse_tree()->type == GDScriptParser::Node::TYPE_CLASS) {
|
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());
|
const GDScriptParser::ClassNode *c = static_cast<const GDScriptParser::ClassNode *>(parser.get_parse_tree());
|
||||||
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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (r_icon_path) {
|
if (r_icon_path) {
|
||||||
if (c->icon_path.empty() || c->icon_path.is_abs_path())
|
if (c->icon_path.empty() || c->icon_path.is_abs_path())
|
||||||
*r_icon_path = c->icon_path;
|
*r_icon_path = c->icon_path;
|
||||||
else if (c->icon_path.is_rel_path())
|
else if (c->icon_path.is_rel_path())
|
||||||
*r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path();
|
*r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path();
|
||||||
}
|
}
|
||||||
|
if (r_base_type) {
|
||||||
|
|
||||||
|
const GDScriptParser::ClassNode *subclass = c;
|
||||||
|
String path = p_path;
|
||||||
|
GDScriptParser subparser;
|
||||||
|
while (subclass) {
|
||||||
|
if (subclass->extends_used) {
|
||||||
|
if (subclass->extends_file) {
|
||||||
|
if (subclass->extends_class.size() == 0) {
|
||||||
|
get_global_class_name(subclass->extends_file, r_base_type);
|
||||||
|
subclass = NULL;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
Vector<StringName> extend_classes = subclass->extends_class;
|
||||||
|
|
||||||
|
FileAccess *subfile = FileAccess::open(subclass->extends_file, FileAccess::READ);
|
||||||
|
if (!subfile) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String subsource = subfile->get_as_utf8_string();
|
||||||
|
if (subsource.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String subpath = subclass->extends_file;
|
||||||
|
if (subpath.is_rel_path()) {
|
||||||
|
subpath = path.get_base_dir().plus_file(subpath).simplify_path();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OK != subparser.parse(subsource, subpath.get_base_dir(), true, subpath, false, NULL, true)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
path = subpath;
|
||||||
|
if (!subparser.get_parse_tree() || subparser.get_parse_tree()->type != GDScriptParser::Node::TYPE_CLASS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
subclass = static_cast<const GDScriptParser::ClassNode *>(subparser.get_parse_tree());
|
||||||
|
|
||||||
|
while (extend_classes.size() > 0) {
|
||||||
|
bool found = false;
|
||||||
|
for (int i = 0; i < subclass->subclasses.size(); i++) {
|
||||||
|
const GDScriptParser::ClassNode *inner_class = subclass->subclasses[i];
|
||||||
|
if (inner_class->name == extend_classes[0]) {
|
||||||
|
extend_classes.remove(0);
|
||||||
|
found = true;
|
||||||
|
subclass = inner_class;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
subclass = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (subclass->extends_class.size() == 1) {
|
||||||
|
*r_base_type = subclass->extends_class[0];
|
||||||
|
subclass = NULL;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*r_base_type = "Reference";
|
||||||
|
subclass = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return c->name;
|
return c->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2183,6 +2201,26 @@ String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) con
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
|
||||||
|
|
||||||
|
FileAccess *file = FileAccess::open(p_path, FileAccess::READ);
|
||||||
|
ERR_FAIL_COND(!file);
|
||||||
|
|
||||||
|
String source = file->get_as_utf8_string();
|
||||||
|
if (source.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GDScriptParser parser;
|
||||||
|
if (OK != parser.parse(source, p_path.get_base_dir(), true, p_path, false, NULL, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const List<String>::Element *E = parser.get_dependencies().front(); E; E = E->next()) {
|
||||||
|
p_dependencies->push_back(E->get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
|
Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
|
||||||
|
|
||||||
Ref<GDScript> sqscr = p_resource;
|
Ref<GDScript> sqscr = p_resource;
|
||||||
|
|||||||
@@ -511,6 +511,7 @@ public:
|
|||||||
virtual void get_recognized_extensions(List<String> *p_extensions) const;
|
virtual void get_recognized_extensions(List<String> *p_extensions) const;
|
||||||
virtual bool handles_type(const String &p_type) const;
|
virtual bool handles_type(const String &p_type) const;
|
||||||
virtual String get_resource_type(const String &p_path) const;
|
virtual String get_resource_type(const String &p_path) const;
|
||||||
|
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ResourceFormatSaverGDScript : public ResourceFormatSaver {
|
class ResourceFormatSaverGDScript : public ResourceFormatSaver {
|
||||||
|
|||||||
@@ -473,6 +473,8 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ref<Resource> res;
|
Ref<Resource> res;
|
||||||
|
dependencies.push_back(path);
|
||||||
|
if (!dependencies_only) {
|
||||||
if (!validating) {
|
if (!validating) {
|
||||||
|
|
||||||
//this can be too slow for just validating code
|
//this can be too slow for just validating code
|
||||||
@@ -490,11 +492,11 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
|
|||||||
res = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(path);
|
res = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res.is_valid()) {
|
if (!res.is_valid()) {
|
||||||
_set_error("Can't preload resource at path: " + path);
|
_set_error("Can't preload resource at path: " + path);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
|
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {
|
||||||
_set_error("Expected ')' after 'preload' path");
|
_set_error("Expected ')' after 'preload' path");
|
||||||
@@ -812,6 +814,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
|
|||||||
bfn = true;
|
bfn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!dependencies_only) {
|
||||||
// Check parents for the constant
|
// Check parents for the constant
|
||||||
if (!bfn && cln->extends_file != StringName()) {
|
if (!bfn && cln->extends_file != StringName()) {
|
||||||
Ref<GDScript> parent = ResourceLoader::load(cln->extends_file);
|
Ref<GDScript> parent = ResourceLoader::load(cln->extends_file);
|
||||||
@@ -827,6 +830,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!bfn) {
|
if (!bfn) {
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
@@ -3378,6 +3382,13 @@ void GDScriptParser::_parse_extends(ClassNode *p_class) {
|
|||||||
p_class->extends_file = constant;
|
p_class->extends_file = constant;
|
||||||
tokenizer->advance();
|
tokenizer->advance();
|
||||||
|
|
||||||
|
// Add parent script as a dependency
|
||||||
|
String parent = constant;
|
||||||
|
if (parent.is_rel_path()) {
|
||||||
|
parent = base_path.plus_file(parent).simplify_path();
|
||||||
|
}
|
||||||
|
dependencies.push_back(parent);
|
||||||
|
|
||||||
if (tokenizer->get_token() != GDScriptTokenizer::TK_PERIOD) {
|
if (tokenizer->get_token() != GDScriptTokenizer::TK_PERIOD) {
|
||||||
return;
|
return;
|
||||||
} else
|
} else
|
||||||
@@ -8149,6 +8160,10 @@ Error GDScriptParser::_parse(const String &p_base_path) {
|
|||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dependencies_only) {
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
_determine_inheritance(main_class);
|
_determine_inheritance(main_class);
|
||||||
|
|
||||||
if (error_set) {
|
if (error_set) {
|
||||||
@@ -8227,7 +8242,7 @@ Error GDScriptParser::parse_bytecode(const Vector<uint8_t> &p_bytecode, const St
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error GDScriptParser::parse(const String &p_code, const String &p_base_path, bool p_just_validate, const String &p_self_path, bool p_for_completion, Set<int> *r_safe_lines) {
|
Error GDScriptParser::parse(const String &p_code, const String &p_base_path, bool p_just_validate, const String &p_self_path, bool p_for_completion, Set<int> *r_safe_lines, bool p_dependencies_only) {
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
@@ -8237,6 +8252,7 @@ Error GDScriptParser::parse(const String &p_code, const String &p_base_path, boo
|
|||||||
|
|
||||||
validating = p_just_validate;
|
validating = p_just_validate;
|
||||||
for_completion = p_for_completion;
|
for_completion = p_for_completion;
|
||||||
|
dependencies_only = p_dependencies_only;
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
safe_lines = r_safe_lines;
|
safe_lines = r_safe_lines;
|
||||||
#endif // DEBUG_ENABLED
|
#endif // DEBUG_ENABLED
|
||||||
@@ -8293,6 +8309,8 @@ void GDScriptParser::clear() {
|
|||||||
parenthesis = 0;
|
parenthesis = 0;
|
||||||
current_export.type = Variant::NIL;
|
current_export.type = Variant::NIL;
|
||||||
check_types = true;
|
check_types = true;
|
||||||
|
dependencies_only = false;
|
||||||
|
dependencies.clear();
|
||||||
error = "";
|
error = "";
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
safe_lines = NULL;
|
safe_lines = NULL;
|
||||||
|
|||||||
@@ -533,6 +533,8 @@ private:
|
|||||||
int error_line;
|
int error_line;
|
||||||
int error_column;
|
int error_column;
|
||||||
bool check_types;
|
bool check_types;
|
||||||
|
bool dependencies_only;
|
||||||
|
List<String> dependencies;
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
Set<int> *safe_lines;
|
Set<int> *safe_lines;
|
||||||
#endif // DEBUG_ENABLED
|
#endif // DEBUG_ENABLED
|
||||||
@@ -634,7 +636,7 @@ public:
|
|||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
const List<GDScriptWarning> &get_warnings() const { return warnings; }
|
const List<GDScriptWarning> &get_warnings() const { return warnings; }
|
||||||
#endif // DEBUG_ENABLED
|
#endif // DEBUG_ENABLED
|
||||||
Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false, Set<int> *r_safe_lines = NULL);
|
Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false, Set<int> *r_safe_lines = NULL, bool p_dependencies_only = false);
|
||||||
Error parse_bytecode(const Vector<uint8_t> &p_bytecode, const String &p_base_path = "", const String &p_self_path = "");
|
Error parse_bytecode(const Vector<uint8_t> &p_bytecode, const String &p_base_path = "", const String &p_self_path = "");
|
||||||
|
|
||||||
bool is_tool_script() const;
|
bool is_tool_script() const;
|
||||||
@@ -653,6 +655,8 @@ public:
|
|||||||
int get_completion_argument_index();
|
int get_completion_argument_index();
|
||||||
int get_completion_identifier_is_function();
|
int get_completion_identifier_is_function();
|
||||||
|
|
||||||
|
const List<String> &get_dependencies() const { return dependencies; }
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
GDScriptParser();
|
GDScriptParser();
|
||||||
~GDScriptParser();
|
~GDScriptParser();
|
||||||
|
|||||||
Reference in New Issue
Block a user