diff options
Diffstat (limited to 'modules/gdscript/gdscript_parser.cpp')
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 132 |
1 files changed, 80 insertions, 52 deletions
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index f1a35c84b7..a1ea94667d 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -137,11 +137,22 @@ GDScriptParser::GDScriptParser() { #endif #ifdef TOOLS_ENABLED - if (theme_color_names.is_empty()) { + if (unlikely(theme_color_names.is_empty())) { + // Vectors. theme_color_names.insert("x", "axis_x_color"); theme_color_names.insert("y", "axis_y_color"); theme_color_names.insert("z", "axis_z_color"); theme_color_names.insert("w", "axis_w_color"); + + // Color. + theme_color_names.insert("r", "axis_x_color"); + theme_color_names.insert("r8", "axis_x_color"); + theme_color_names.insert("g", "axis_y_color"); + theme_color_names.insert("g8", "axis_y_color"); + theme_color_names.insert("b", "axis_z_color"); + theme_color_names.insert("b8", "axis_z_color"); + theme_color_names.insert("a", "axis_w_color"); + theme_color_names.insert("a8", "axis_w_color"); } #endif } @@ -298,13 +309,14 @@ void GDScriptParser::set_last_completion_call_arg(int p_argument) { completion_call_stack.back()->get().argument = p_argument; } -Error GDScriptParser::parse(const String &p_source_code, const String &p_script_path, bool p_for_completion) { +Error GDScriptParser::parse(const String &p_source_code, const String &p_script_path, bool p_for_completion, bool p_parse_body) { clear(); String source = p_source_code; int cursor_line = -1; int cursor_column = -1; for_completion = p_for_completion; + parse_body = p_parse_body; int tab_size = 4; #ifdef TOOLS_ENABLED @@ -678,6 +690,12 @@ void GDScriptParser::parse_program() { } } + // When the only thing needed is the class name and the icon, we don't need to parse the hole file. + // It really speed up the call to GDScriptLanguage::get_global_class_name especially for large script. + if (!parse_body) { + return; + } + #undef PUSH_PENDING_ANNOTATIONS_TO_HEAD parse_class_body(true); @@ -4160,6 +4178,64 @@ static String _get_annotation_error_string(const StringName &p_annotation_name, return vformat(R"("%s" annotation requires a variable of type %s, but type "%s" was given instead.)", p_annotation_name, string, p_provided_type.to_string()); } +static StringName _find_narrowest_native_or_global_class(const GDScriptParser::DataType &p_type) { + switch (p_type.kind) { + case GDScriptParser::DataType::NATIVE: { + if (p_type.is_meta_type) { + return Object::get_class_static(); // `GDScriptNativeClass` is not an exposed class. + } + return p_type.native_type; + } break; + case GDScriptParser::DataType::SCRIPT: { + Ref<Script> script; + if (p_type.script_type.is_valid()) { + script = p_type.script_type; + } else { + script = ResourceLoader::load(p_type.script_path, SNAME("Script")); + } + + if (p_type.is_meta_type) { + return script.is_valid() ? script->get_class() : Script::get_class_static(); + } + if (script.is_null()) { + return p_type.native_type; + } + if (script->get_global_name() != StringName()) { + return script->get_global_name(); + } + + Ref<Script> base_script = script->get_base_script(); + if (base_script.is_null()) { + return script->get_instance_base_type(); + } + + GDScriptParser::DataType base_type; + base_type.kind = GDScriptParser::DataType::SCRIPT; + base_type.builtin_type = Variant::OBJECT; + base_type.native_type = base_script->get_instance_base_type(); + base_type.script_type = base_script; + base_type.script_path = base_script->get_path(); + + return _find_narrowest_native_or_global_class(base_type); + } break; + case GDScriptParser::DataType::CLASS: { + if (p_type.is_meta_type) { + return GDScript::get_class_static(); + } + if (p_type.class_type == nullptr) { + return p_type.native_type; + } + if (p_type.class_type->get_global_name() != StringName()) { + return p_type.class_type->get_global_name(); + } + return _find_narrowest_native_or_global_class(p_type.class_type->base_type); + } break; + default: { + ERR_FAIL_V(StringName()); + } break; + } +} + template <PropertyHint t_hint, Variant::Type t_type> bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) { ERR_FAIL_COND_V_MSG(p_target->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name)); @@ -4302,57 +4378,9 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.hint_string = String(); break; case GDScriptParser::DataType::NATIVE: - if (ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) { - variable->export_info.type = Variant::OBJECT; - variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE; - variable->export_info.hint_string = export_type.native_type; - } else if (ClassDB::is_parent_class(export_type.native_type, SNAME("Node"))) { - variable->export_info.type = Variant::OBJECT; - variable->export_info.hint = PROPERTY_HINT_NODE_TYPE; - variable->export_info.hint_string = export_type.native_type; - } else { - push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", p_annotation); - return false; - } - break; + case GDScriptParser::DataType::SCRIPT: case GDScriptParser::DataType::CLASS: { - StringName class_name; - if (export_type.class_type) { - class_name = export_type.class_type->get_global_name(); - } - if (class_name == StringName()) { - push_error(R"(Script export type must be a global class.)", p_annotation); - return false; - } - if (ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) { - variable->export_info.type = Variant::OBJECT; - variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE; - variable->export_info.hint_string = class_name; - } else if (ClassDB::is_parent_class(export_type.native_type, SNAME("Node"))) { - variable->export_info.type = Variant::OBJECT; - variable->export_info.hint = PROPERTY_HINT_NODE_TYPE; - variable->export_info.hint_string = class_name; - } else { - push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", p_annotation); - return false; - } - } break; - - case GDScriptParser::DataType::SCRIPT: { - StringName class_name; - if (export_type.script_type.is_valid()) { - class_name = export_type.script_type->get_global_name(); - } - if (class_name == StringName()) { - Ref<Script> script = ResourceLoader::load(export_type.script_path, SNAME("Script")); - if (script.is_valid()) { - class_name = script->get_global_name(); - } - } - if (class_name == StringName()) { - push_error(R"(Script export type must be a global class.)", p_annotation); - return false; - } + const StringName class_name = _find_narrowest_native_or_global_class(export_type); if (ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) { variable->export_info.type = Variant::OBJECT; variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE; |