diff options
Diffstat (limited to 'modules/gdscript/gdscript.cpp')
-rw-r--r-- | modules/gdscript/gdscript.cpp | 333 |
1 files changed, 148 insertions, 185 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 42b08f8a68..58aa7a08d4 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -83,7 +83,7 @@ void GDScriptNativeClass::_bind_methods() { Variant GDScriptNativeClass::_new() { Object *o = instantiate(); - ERR_FAIL_COND_V_MSG(!o, Variant(), "Class type: '" + String(name) + "' is not instantiable."); + ERR_FAIL_NULL_V_MSG(o, Variant(), "Class type: '" + String(name) + "' is not instantiable."); RefCounted *rc = Object::cast_to<RefCounted>(o); if (rc) { @@ -215,7 +215,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr } else { owner = memnew(RefCounted); //by default, no base means use reference } - ERR_FAIL_COND_V_MSG(!owner, Variant(), "Can't inherit from a virtual class."); + ERR_FAIL_NULL_V_MSG(owner, Variant(), "Can't inherit from a virtual class."); RefCounted *r = Object::cast_to<RefCounted>(owner); if (r) { @@ -254,7 +254,7 @@ Ref<Script> GDScript::get_base_script() const { } StringName GDScript::get_global_name() const { - return name; + return global_name; } StringName GDScript::get_instance_base_type() const { @@ -278,33 +278,16 @@ struct _GDScriptMemberSort { void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { placeholders.erase(p_placeholder); } + #endif void GDScript::_get_script_method_list(List<MethodInfo> *r_list, bool p_include_base) const { const GDScript *current = this; while (current) { for (const KeyValue<StringName, GDScriptFunction *> &E : current->member_functions) { - GDScriptFunction *func = E.value; - MethodInfo mi; - mi.name = E.key; - - if (func->is_static()) { - mi.flags |= METHOD_FLAG_STATIC; - } - - for (int i = 0; i < func->get_argument_count(); i++) { - PropertyInfo arginfo = func->get_argument_type(i); -#ifdef TOOLS_ENABLED - arginfo.name = func->get_argument_name(i); -#endif - mi.arguments.push_back(arginfo); - } -#ifdef TOOLS_ENABLED - mi.default_arguments.append_array(func->get_default_arg_values()); -#endif - mi.return_val = func->get_return_type(); - r_list->push_back(mi); + r_list->push_back(E.value->get_method_info()); } + if (!p_include_base) { return; } @@ -323,10 +306,12 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl while (sptr) { Vector<_GDScriptMemberSort> msort; - for (const KeyValue<StringName, PropertyInfo> &E : sptr->member_info) { + for (const KeyValue<StringName, MemberInfo> &E : sptr->member_indices) { + if (!sptr->members.has(E.key)) { + continue; // Skip base class members. + } _GDScriptMemberSort ms; - ERR_CONTINUE(!sptr->member_indices.has(E.key)); - ms.index = sptr->member_indices[E.key].index; + ms.index = E.value.index; ms.name = E.key; msort.push_back(ms); } @@ -334,7 +319,7 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl msort.sort(); msort.reverse(); for (int i = 0; i < msort.size(); i++) { - props.push_front(sptr->member_info[msort[i].name]); + props.push_front(sptr->member_indices[msort[i].name].property_info); } #ifdef TOOLS_ENABLED @@ -362,21 +347,17 @@ bool GDScript::has_method(const StringName &p_method) const { return member_functions.has(p_method); } +bool GDScript::has_static_method(const StringName &p_method) const { + return member_functions.has(p_method) && member_functions[p_method]->is_static(); +} + MethodInfo GDScript::get_method_info(const StringName &p_method) const { HashMap<StringName, GDScriptFunction *>::ConstIterator E = member_functions.find(p_method); if (!E) { return MethodInfo(); } - GDScriptFunction *func = E->value; - MethodInfo mi; - mi.name = E->key; - for (int i = 0; i < func->get_argument_count(); i++) { - mi.arguments.push_back(func->get_argument_type(i)); - } - - mi.return_val = func->get_return_type(); - return mi; + return E->value->get_method_info(); } bool GDScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { @@ -482,9 +463,13 @@ void GDScript::_clear_doc() { docs.clear(); doc = DocData::ClassDoc(); } + +String GDScript::get_class_icon_path() const { + return simplified_icon_path; +} #endif -bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderScriptInstance *p_instance_to_update) { +bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderScriptInstance *p_instance_to_update, bool p_base_exports_changed) { #ifdef TOOLS_ENABLED static Vector<GDScript *> base_caches; @@ -493,7 +478,7 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc } base_caches.append(this); - bool changed = false; + bool changed = p_base_exports_changed; if (source_changed_cache) { source_changed_cache = false; @@ -553,13 +538,7 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc member_default_values_cache[member.variable->identifier->name] = default_value; } break; case GDScriptParser::ClassNode::Member::SIGNAL: { - // TODO: Cache this in parser to avoid loops like this. - Vector<StringName> parameters_names; - parameters_names.resize(member.signal->parameters.size()); - for (int j = 0; j < member.signal->parameters.size(); j++) { - parameters_names.write[j] = member.signal->parameters[j]->identifier->name; - } - _signals[member.signal->identifier->name] = parameters_names; + _signals[member.signal->identifier->name] = member.signal->method_info; } break; case GDScriptParser::ClassNode::Member::GROUP: { members_cache.push_back(member.annotation->export_info); @@ -626,9 +605,15 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc void GDScript::update_exports() { #ifdef TOOLS_ENABLED + _update_exports_down(false); +#endif +} +#ifdef TOOLS_ENABLED +void GDScript::_update_exports_down(bool p_base_exports_changed) { bool cyclic_error = false; - _update_exports(&cyclic_error); + bool changed = _update_exports(&cyclic_error, false, nullptr, p_base_exports_changed); + if (cyclic_error) { return; } @@ -638,14 +623,14 @@ void GDScript::update_exports() { for (const ObjectID &E : copy) { Object *id = ObjectDB::get_instance(E); GDScript *s = Object::cast_to<GDScript>(id); + if (!s) { continue; } - s->update_exports(); + s->_update_exports_down(p_base_exports_changed || changed); } - -#endif } +#endif String GDScript::_get_debug_path() const { if (is_built_in() && !get_name().is_empty()) { @@ -973,22 +958,26 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) { void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const { p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); - List<PropertyInfo> property_list; - + List<const GDScript *> classes; const GDScript *top = this; while (top) { - for (const KeyValue<StringName, MemberInfo> &E : top->static_variables_indices) { - PropertyInfo pi = PropertyInfo(E.value.data_type); - pi.name = E.key; - pi.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; // For the script (as a class) it is a non-static property. - property_list.push_back(pi); - } - + classes.push_back(top); top = top->_base; } - for (const List<PropertyInfo>::Element *E = property_list.back(); E; E = E->prev()) { - p_properties->push_back(E->get()); + for (const List<const GDScript *>::Element *E = classes.back(); E; E = E->prev()) { + Vector<_GDScriptMemberSort> msort; + for (const KeyValue<StringName, MemberInfo> &F : E->get()->static_variables_indices) { + _GDScriptMemberSort ms; + ms.index = F.value.index; + ms.name = F.key; + msort.push_back(ms); + } + msort.sort(); + + for (int i = 0; i < msort.size(); i++) { + p_properties->push_back(E->get()->static_variables_indices[msort[i].name].property_info); + } } } @@ -1106,7 +1095,7 @@ GDScript *GDScript::find_class(const String &p_qualified_name) { Vector<String> class_names; GDScript *result = nullptr; // Empty initial name means start here. - if (first.is_empty() || first == name) { + if (first.is_empty() || first == global_name) { class_names = p_qualified_name.split("::"); result = this; } else if (p_qualified_name.begins_with(get_root_script()->path)) { @@ -1241,15 +1230,8 @@ bool GDScript::has_script_signal(const StringName &p_signal) const { } void GDScript::_get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const { - for (const KeyValue<StringName, Vector<StringName>> &E : _signals) { - MethodInfo mi; - mi.name = E.key; - for (int i = 0; i < E.value.size(); i++) { - PropertyInfo arg; - arg.name = E.value[i]; - mi.arguments.push_back(arg); - } - r_list->push_back(mi); + for (const KeyValue<StringName, MethodInfo> &E : _signals) { + r_list->push_back(E.value); } if (!p_include_base) { @@ -1270,21 +1252,6 @@ void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const { _get_script_signal_list(r_signals, true); } -String GDScript::_get_gdscript_reference_class_name(const GDScript *p_gdscript) { - ERR_FAIL_NULL_V(p_gdscript, String()); - - String class_name; - while (p_gdscript) { - if (class_name.is_empty()) { - class_name = p_gdscript->get_script_class_name(); - } else { - class_name = p_gdscript->get_script_class_name() + "." + class_name; - } - p_gdscript = p_gdscript->_owner; - } - return class_name; -} - GDScript *GDScript::_get_gdscript_from_variant(const Variant &p_variant) { Object *obj = p_variant; if (obj == nullptr || obj->get_instance_id().is_null()) { @@ -1395,29 +1362,13 @@ void GDScript::_save_orphaned_subclasses(ClearData *p_clear_data) { } } -void GDScript::_init_rpc_methods_properties() { - // Copy the base rpc methods so we don't mask their IDs. - rpc_config.clear(); - if (base.is_valid()) { - rpc_config = base->rpc_config.duplicate(); - } - - // RPC Methods - for (KeyValue<StringName, GDScriptFunction *> &E : member_functions) { - Variant config = E.value->get_rpc_config(); - if (config.get_type() != Variant::NIL) { - rpc_config[E.value->get_name()] = config; - } - } -} - #ifdef DEBUG_ENABLED String GDScript::debug_get_script_name(const Ref<Script> &p_script) { if (p_script.is_valid()) { Ref<GDScript> gdscript = p_script; if (gdscript.is_valid()) { - if (!gdscript->get_script_class_name().is_empty()) { - return gdscript->get_script_class_name(); + if (gdscript->get_local_name() != StringName()) { + return gdscript->get_local_name(); } return gdscript->get_fully_qualified_name().get_file(); } @@ -1663,7 +1614,7 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { } { - HashMap<StringName, Vector<StringName>>::ConstIterator E = sptr->_signals.find(p_name); + HashMap<StringName, MethodInfo>::ConstIterator E = sptr->_signals.find(p_name); if (E) { r_ret = Signal(this->owner, E->key); return true; @@ -1711,15 +1662,11 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { } Variant::Type GDScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { - const GDScript *sptr = script.ptr(); - while (sptr) { - if (sptr->member_info.has(p_name)) { - if (r_is_valid) { - *r_is_valid = true; - } - return sptr->member_info[p_name].type; + if (script->member_indices.has(p_name)) { + if (r_is_valid) { + *r_is_valid = true; } - sptr = sptr->_base; + return script->member_indices[p_name].property_info.type; } if (r_is_valid) { @@ -1728,6 +1675,25 @@ Variant::Type GDScriptInstance::get_property_type(const StringName &p_name, bool return Variant::NIL; } +void GDScriptInstance::validate_property(PropertyInfo &p_property) const { + Variant property = (Dictionary)p_property; + const Variant *args[1] = { &property }; + + const GDScript *sptr = script.ptr(); + while (sptr) { + HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._validate_property); + if (E) { + Callable::CallError err; + Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err); + if (err.error == Callable::CallError::CALL_OK) { + p_property = PropertyInfo::from_dict(property); + return; + } + } + sptr = sptr->_base; + } +} + void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { // exported members, not done yet! @@ -1775,10 +1741,12 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const //instance a fake script for editing the values Vector<_GDScriptMemberSort> msort; - for (const KeyValue<StringName, PropertyInfo> &F : sptr->member_info) { + for (const KeyValue<StringName, GDScript::MemberInfo> &F : sptr->member_indices) { + if (!sptr->members.has(F.key)) { + continue; // Skip base class members. + } _GDScriptMemberSort ms; - ERR_CONTINUE(!sptr->member_indices.has(F.key)); - ms.index = sptr->member_indices[F.key].index; + ms.index = F.value.index; ms.name = F.key; msort.push_back(ms); } @@ -1786,14 +1754,15 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const msort.sort(); msort.reverse(); for (int i = 0; i < msort.size(); i++) { - props.push_front(sptr->member_info[msort[i].name]); + props.push_front(sptr->member_indices[msort[i].name].property_info); } #ifdef TOOLS_ENABLED p_properties->push_back(sptr->get_class_category()); #endif // TOOLS_ENABLED - for (const PropertyInfo &prop : props) { + for (PropertyInfo &prop : props) { + validate_property(prop); p_properties->push_back(prop); } @@ -1848,12 +1817,7 @@ void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const { const GDScript *sptr = script.ptr(); while (sptr) { for (const KeyValue<StringName, GDScriptFunction *> &E : sptr->member_functions) { - MethodInfo mi; - mi.name = E.key; - for (int i = 0; i < E.value->get_argument_count(); i++) { - mi.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i))); - } - p_list->push_back(mi); + p_list->push_back(E.value->get_method_info()); } sptr = sptr->_base; } @@ -1897,14 +1861,23 @@ Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_ar return Variant(); } -void GDScriptInstance::notification(int p_notification) { +void GDScriptInstance::notification(int p_notification, bool p_reversed) { //notification is not virtual, it gets called at ALL levels just like in C. Variant value = p_notification; const Variant *args[1] = { &value }; + List<GDScript *> pl; GDScript *sptr = script.ptr(); while (sptr) { - HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification); + if (p_reversed) { + pl.push_back(sptr); + } else { + pl.push_front(sptr); + } + sptr = sptr->_base; + } + for (GDScript *sc : pl) { + HashMap<StringName, GDScriptFunction *>::Iterator E = sc->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification); if (E) { Callable::CallError err; E->value->call(this, args, 1, err); @@ -1912,7 +1885,6 @@ void GDScriptInstance::notification(int p_notification) { //print error about notification call } } - sptr = sptr->_base; } } @@ -2407,61 +2379,60 @@ void GDScriptLanguage::frame() { /* EDITOR FUNCTIONS */ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { - // TODO: Add annotations here? + // Please keep alphabetical order within categories. static const char *_reserved_words[] = { - // operators + // Control flow. + "break", + "continue", + "elif", + "else", + "for", + "if", + "match", + "pass", + "return", + "when", + "while", + // Declarations. + "class", + "class_name", + "const", + "enum", + "extends", + "func", + "namespace", // Reserved for potential future use. + "signal", + "static", + "trait", // Reserved for potential future use. + "var", + // Other keywords. + "await", + "breakpoint", + "self", + "super", + "yield", // Reserved for potential future use. + // Operators. "and", + "as", "in", + "is", "not", "or", - // types and values + // Special values (tokenizer treats them as literals, not as tokens). "false", - "float", - "int", - "bool", "null", - "PI", - "TAU", + "true", + // Constants. "INF", "NAN", - "self", - "true", - "void", - // functions - "as", + "PI", + "TAU", + // Functions (highlighter uses global function color instead). "assert", - "await", - "breakpoint", - "class", - "class_name", - "extends", - "is", - "func", "preload", - "signal", - "super", - // var - "const", - "enum", - "static", - "var", - // control flow - "break", - "continue", - "if", - "elif", - "else", - "for", - "pass", - "return", - "match", - "while", - // These keywords are not implemented currently, but reserved for (potential) future use. - // We highlight them as keywords to make errors easier to understand. - "trait", - "namespace", - "yield", - nullptr + // Types (highlighter uses type color instead). + "void", + nullptr, }; const char **w = _reserved_words; @@ -2470,25 +2441,20 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { p_words->push_back(*w); w++; } - - List<StringName> functions; - GDScriptUtilityFunctions::get_function_list(&functions); - - for (const StringName &E : functions) { - p_words->push_back(String(E)); - } } bool GDScriptLanguage::is_control_flow_keyword(String p_keyword) const { + // Please keep alphabetical order. return p_keyword == "break" || p_keyword == "continue" || p_keyword == "elif" || p_keyword == "else" || - p_keyword == "if" || p_keyword == "for" || + p_keyword == "if" || p_keyword == "match" || p_keyword == "pass" || p_keyword == "return" || + p_keyword == "when" || p_keyword == "while"; } @@ -2527,13 +2493,6 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b * Before changing this function, please ask the current maintainer of EditorFileSystem. */ - if (r_icon_path) { - if (c->icon_path.is_empty() || c->icon_path.is_absolute_path()) { - *r_icon_path = c->icon_path.simplify_path(); - } else if (c->icon_path.is_relative_path()) { - *r_icon_path = p_path.get_base_dir().path_join(c->icon_path).simplify_path(); - } - } if (r_base_type) { const GDScriptParser::ClassNode *subclass = c; String path = p_path; @@ -2601,6 +2560,9 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b } } } + if (r_icon_path) { + *r_icon_path = c->simplified_icon_path; + } return c->identifier != nullptr ? String(c->identifier->name) : String(); } @@ -2616,6 +2578,7 @@ GDScriptLanguage::GDScriptLanguage() { strings._set = StaticCString::create("_set"); strings._get = StaticCString::create("_get"); strings._get_property_list = StaticCString::create("_get_property_list"); + strings._validate_property = StaticCString::create("_validate_property"); strings._property_can_revert = StaticCString::create("_property_can_revert"); strings._property_get_revert = StaticCString::create("_property_get_revert"); strings._script_source = StaticCString::create("script/source"); |