diff options
Diffstat (limited to 'modules/gdscript')
25 files changed, 1619 insertions, 1686 deletions
diff --git a/modules/gdscript/config.py b/modules/gdscript/config.py index 185a10bcb2..6fc227e7f5 100644 --- a/modules/gdscript/config.py +++ b/modules/gdscript/config.py @@ -11,7 +11,6 @@ def get_doc_classes(): "@GDScript", "GDScript", "GDScriptFunctionState", - "GDScriptNativeClass", ] diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 9324691df5..be159b6407 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -568,7 +568,7 @@ <description> Linearly interpolates between two values by a normalized value. This is the opposite of [method inverse_lerp]. If the [code]from[/code] and [code]to[/code] arguments are of type [int] or [float], the return value is a [float]. - If both are of the same vector type ([Vector2], [Vector3] or [Color]), the return value will be of the same type ([code]lerp[/code] then calls the vector type's [code]linear_interpolate[/code] method). + If both are of the same vector type ([Vector2], [Vector3] or [Color]), the return value will be of the same type ([code]lerp[/code] then calls the vector type's [code]lerp[/code] method). [codeblock] lerp(0, 4, 0.75) # Returns 3.0 lerp(Vector2(1, 5), Vector2(3, 2), 0.5) # Returns Vector2(2, 3.5) diff --git a/modules/gdscript/doc_classes/GDScriptNativeClass.xml b/modules/gdscript/doc_classes/GDScriptNativeClass.xml deleted file mode 100644 index 0a8982de8e..0000000000 --- a/modules/gdscript/doc_classes/GDScriptNativeClass.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="GDScriptNativeClass" inherits="Reference" version="4.0"> - <brief_description> - </brief_description> - <description> - </description> - <tutorials> - </tutorials> - <methods> - <method name="new"> - <return type="Variant"> - </return> - <description> - </description> - </method> - </methods> - <constants> - </constants> -</class> diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index 0aca4dbc5e..d0f27b632b 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -34,17 +34,14 @@ #include "scene/gui/text_edit.h" inline bool _is_symbol(CharType c) { - return is_symbol(c); } static bool _is_text_char(CharType c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; } static bool _is_char(CharType c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; } @@ -180,10 +177,10 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_ } if (in_region == -1 && !in_keyword && is_char && !prev_is_char) { - int to = j; - while (to < str.length() && _is_text_char(str[to])) + while (to < str.length() && _is_text_char(str[to])) { to++; + } String word = str.substr(j, to - j); Color col = Color(); @@ -208,7 +205,6 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_ } if (!in_function_name && in_word && !in_keyword) { - int k = j; while (k < str.length() && !_is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') { k++; @@ -238,7 +234,6 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_ } if (is_symbol) { - if (in_function_name) { in_function_args = true; } diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 9a4fa5cc86..632407c61f 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -44,12 +44,10 @@ /////////////////////////// GDScriptNativeClass::GDScriptNativeClass(const StringName &p_name) { - name = p_name; } bool GDScriptNativeClass::_get(const StringName &p_name, Variant &r_ret) const { - bool ok; int v = ClassDB::get_integer_constant(name, p_name, &ok); @@ -62,12 +60,10 @@ bool GDScriptNativeClass::_get(const StringName &p_name, Variant &r_ret) const { } void GDScriptNativeClass::_bind_methods() { - ClassDB::bind_method(D_METHOD("new"), &GDScriptNativeClass::_new); } Variant GDScriptNativeClass::_new() { - Object *o = instance(); ERR_FAIL_COND_V_MSG(!o, Variant(), "Class type: '" + String(name) + "' is not instantiable."); @@ -80,12 +76,10 @@ Variant GDScriptNativeClass::_new() { } Object *GDScriptNativeClass::instance() { - return ClassDB::instance(name); } GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error) { - /* STEP 1, CREATE */ GDScriptInstance *instance = memnew(GDScriptInstance); @@ -103,15 +97,14 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco instance->owner->set_script_instance(instance); /* STEP 2, INITIALIZE AND CONSTRUCT */ - { MutexLock lock(GDScriptLanguage::singleton->lock); - instances.insert(instance->owner); } - + if (p_argcount < 0) { + return instance; + } initializer->call(instance, p_args, p_argcount, r_error); - if (r_error.error != Callable::CallError::CALL_OK) { instance->script = Ref<GDScript>(); instance->owner->set_script_instance(nullptr); @@ -119,16 +112,13 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco MutexLock lock(GDScriptLanguage::singleton->lock); instances.erase(p_owner); } - - ERR_FAIL_COND_V(r_error.error != Callable::CallError::CALL_OK, nullptr); //error constructing + ERR_FAIL_V_MSG(nullptr, "Error constructing a GDScriptInstance."); } - //@TODO make thread safe return instance; } Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - /* STEP 1, CREATE */ if (!valid) { @@ -174,7 +164,6 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr } bool GDScript::can_instance() const { - #ifdef TOOLS_ENABLED return valid && (tool || ScriptServer::is_scripting_enabled()); #else @@ -183,7 +172,6 @@ bool GDScript::can_instance() const { } Ref<Script> GDScript::get_base_script() const { - if (_base) { return Ref<GDScript>(_base); } else { @@ -192,16 +180,16 @@ Ref<Script> GDScript::get_base_script() const { } StringName GDScript::get_instance_base_type() const { - - if (native.is_valid()) + if (native.is_valid()) { return native->get_name(); - if (base.is_valid() && base->is_valid()) + } + if (base.is_valid() && base->is_valid()) { return base->get_instance_base_type(); + } return StringName(); } struct _GDScriptMemberSort { - int index; StringName name; _FORCE_INLINE_ bool operator<(const _GDScriptMemberSort &p_member) const { return index < p_member.index; } @@ -210,13 +198,11 @@ struct _GDScriptMemberSort { #ifdef TOOLS_ENABLED void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { - placeholders.erase(p_placeholder); } #endif void GDScript::get_script_method_list(List<MethodInfo> *p_list) const { - const GDScript *current = this; while (current) { for (const Map<StringName, GDScriptFunction *>::Element *E = current->member_functions.front(); E; E = E->next()) { @@ -236,15 +222,12 @@ void GDScript::get_script_method_list(List<MethodInfo> *p_list) const { } void GDScript::get_script_property_list(List<PropertyInfo> *p_list) const { - const GDScript *sptr = this; List<PropertyInfo> props; while (sptr) { - Vector<_GDScriptMemberSort> msort; for (Map<StringName, PropertyInfo>::Element *E = sptr->member_info.front(); E; E = E->next()) { - _GDScriptMemberSort ms; ERR_CONTINUE(!sptr->member_indices.has(E->key())); ms.index = sptr->member_indices[E->key()].index; @@ -255,7 +238,6 @@ void GDScript::get_script_property_list(List<PropertyInfo> *p_list) const { msort.sort(); msort.invert(); for (int i = 0; i < msort.size(); i++) { - props.push_front(sptr->member_info[msort[i].name]); } @@ -268,15 +250,14 @@ void GDScript::get_script_property_list(List<PropertyInfo> *p_list) const { } bool GDScript::has_method(const StringName &p_method) const { - return member_functions.has(p_method); } MethodInfo GDScript::get_method_info(const StringName &p_method) const { - const Map<StringName, GDScriptFunction *>::Element *E = member_functions.find(p_method); - if (!E) + if (!E) { return MethodInfo(); + } GDScriptFunction *func = E->get(); MethodInfo mi; @@ -290,7 +271,6 @@ MethodInfo GDScript::get_method_info(const StringName &p_method) const { } bool GDScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { - #ifdef TOOLS_ENABLED const Map<StringName, Variant>::Element *E = member_default_values_cache.find(p_property); @@ -307,14 +287,13 @@ bool GDScript::get_property_default_value(const StringName &p_property, Variant } ScriptInstance *GDScript::instance_create(Object *p_this) { - GDScript *top = this; - while (top->_base) + while (top->_base) { top = top->_base; + } if (top->native.is_valid()) { if (!ClassDB::is_parent_class(p_this->get_class_name(), top->native->get_name())) { - if (EngineDebugger::is_active()) { GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'"); } @@ -338,24 +317,23 @@ PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) } bool GDScript::instance_has(const Object *p_this) const { - MutexLock lock(GDScriptLanguage::singleton->lock); return instances.has((Object *)p_this); } bool GDScript::has_source_code() const { - return source != ""; } -String GDScript::get_source_code() const { +String GDScript::get_source_code() const { return source; } -void GDScript::set_source_code(const String &p_code) { - if (source == p_code) +void GDScript::set_source_code(const String &p_code) { + if (source == p_code) { return; + } source = p_code; #ifdef TOOLS_ENABLED source_changed_cache = true; @@ -364,7 +342,6 @@ void GDScript::set_source_code(const String &p_code) { #ifdef TOOLS_ENABLED void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames) { - if (base_cache.is_valid()) { base_cache->_update_exports_values(values, propnames); } @@ -379,10 +356,15 @@ void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<Pro } #endif -bool GDScript::_update_exports() { - +bool GDScript::_update_exports(bool *r_err, bool p_recursive_call) { #ifdef TOOLS_ENABLED + static Vector<GDScript *> base_caches; + if (!p_recursive_call) { + base_caches.clear(); + } + base_caches.append(this); + bool changed = false; if (source_changed_cache) { @@ -391,17 +373,18 @@ bool GDScript::_update_exports() { String basedir = path; - if (basedir == "") + if (basedir == "") { basedir = get_path(); + } - if (basedir != "") + if (basedir != "") { basedir = basedir.get_base_dir(); + } GDScriptParser parser; Error err = parser.parse(source, basedir, true, path); if (err == OK) { - const GDScriptParser::Node *root = parser.get_parse_tree(); ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, false); @@ -417,10 +400,8 @@ bool GDScript::_update_exports() { if (String(c->extends_file) != "" && String(c->extends_file) != get_path()) { path = c->extends_file; if (path.is_rel_path()) { - String base = get_path(); if (base == "" || base.is_rel_path()) { - ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data()); } else { path = base.get_base_dir().plus_file(path); @@ -429,17 +410,16 @@ bool GDScript::_update_exports() { } else if (c->extends_class.size() != 0) { String base = c->extends_class[0]; - if (ScriptServer::is_global_class(base)) + if (ScriptServer::is_global_class(base)) { path = ScriptServer::get_global_class_path(base); + } } if (path != "") { if (path != get_path()) { - Ref<GDScript> bf = ResourceLoader::load(path); if (bf.is_valid()) { - base_cache = bf; bf->inheriters_cache.insert(get_instance_id()); } @@ -453,8 +433,9 @@ bool GDScript::_update_exports() { member_default_values_cache.clear(); for (int i = 0; i < c->variables.size(); i++) { - if (c->variables[i]._export.type == Variant::NIL) + if (c->variables[i]._export.type == Variant::NIL) { continue; + } members_cache.push_back(c->variables[i]._export); member_default_values_cache[c->variables[i].identifier] = c->variables[i].default_value; @@ -476,7 +457,24 @@ bool GDScript::_update_exports() { placeholder_fallback_enabled = false; if (base_cache.is_valid() && base_cache->is_valid()) { - if (base_cache->_update_exports()) { + for (int i = 0; i < base_caches.size(); i++) { + if (base_caches[i] == base_cache.ptr()) { + if (r_err) { + *r_err = true; + } + valid = false; // to show error in the editor + base_cache->valid = false; + base_cache->inheriters_cache.clear(); // to prevent future stackoverflows + base_cache.unref(); + base.unref(); + _base = nullptr; + ERR_FAIL_V_MSG(false, "Cyclic inheritance in script class."); + } + } + if (base_cache->_update_exports(r_err, true)) { + if (r_err && *r_err) { + return false; + } changed = true; } } @@ -501,18 +499,22 @@ bool GDScript::_update_exports() { } void GDScript::update_exports() { - #ifdef TOOLS_ENABLED - _update_exports(); + bool cyclic_error = false; + _update_exports(&cyclic_error); + if (cyclic_error) { + return; + } Set<ObjectID> copy = inheriters_cache; //might get modified for (Set<ObjectID>::Element *E = copy.front(); E; E = E->next()) { Object *id = ObjectDB::get_instance(E->get()); GDScript *s = Object::cast_to<GDScript>(id); - if (!s) + if (!s) { continue; + } s->update_exports(); } @@ -520,16 +522,13 @@ void GDScript::update_exports() { } void GDScript::_set_subclass_path(Ref<GDScript> &p_sc, const String &p_path) { - p_sc->path = p_path; for (Map<StringName, Ref<GDScript>>::Element *E = p_sc->subclasses.front(); E; E = E->next()) { - _set_subclass_path(E->get(), p_path); } } Error GDScript::reload(bool p_keep_state) { - bool has_instances; { MutexLock lock(GDScriptLanguage::singleton->lock); @@ -541,11 +540,13 @@ Error GDScript::reload(bool p_keep_state) { String basedir = path; - if (basedir == "") + if (basedir == "") { basedir = get_path(); + } - if (basedir != "") + if (basedir != "") { basedir = basedir.get_base_dir(); + } if (source.find("%BASE%") != -1) { //loading a template, don't parse @@ -569,7 +570,6 @@ Error GDScript::reload(bool p_keep_state) { err = compiler.compile(&parser, this, p_keep_state); if (err) { - if (can_run) { if (EngineDebugger::is_active()) { GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error()); @@ -593,7 +593,6 @@ Error GDScript::reload(bool p_keep_state) { valid = true; for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) { - _set_subclass_path(E->get(), path); } @@ -603,12 +602,10 @@ Error GDScript::reload(bool p_keep_state) { } ScriptLanguage *GDScript::get_language() const { - return GDScriptLanguage::get_singleton(); } void GDScript::get_constants(Map<StringName, Variant> *p_constants) { - if (p_constants) { for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { (*p_constants)[E->key()] = E->value(); @@ -638,12 +635,16 @@ uint16_t GDScript::get_rpc_method_id(const StringName &p_method) const { } StringName GDScript::get_rpc_method(const uint16_t p_rpc_method_id) const { - ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), StringName()); + if (p_rpc_method_id >= rpc_functions.size()) { + return StringName(); + } return rpc_functions[p_rpc_method_id].name; } MultiplayerAPI::RPCMode GDScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED); + if (p_rpc_method_id >= rpc_functions.size()) { + return MultiplayerAPI::RPC_MODE_DISABLED; + } return rpc_functions[p_rpc_method_id].mode; } @@ -665,12 +666,16 @@ uint16_t GDScript::get_rset_property_id(const StringName &p_variable) const { } StringName GDScript::get_rset_property(const uint16_t p_rset_member_id) const { - ERR_FAIL_COND_V(p_rset_member_id >= rpc_variables.size(), StringName()); + if (p_rset_member_id >= rpc_variables.size()) { + return StringName(); + } return rpc_variables[p_rset_member_id].name; } MultiplayerAPI::RPCMode GDScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const { - ERR_FAIL_COND_V(p_rset_member_id >= rpc_variables.size(), MultiplayerAPI::RPC_MODE_DISABLED); + if (p_rset_member_id >= rpc_variables.size()) { + return MultiplayerAPI::RPC_MODE_DISABLED; + } return rpc_variables[p_rset_member_id].mode; } @@ -679,13 +684,10 @@ MultiplayerAPI::RPCMode GDScript::get_rset_mode(const StringName &p_variable) co } Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - GDScript *top = this; while (top) { - Map<StringName, GDScriptFunction *>::Element *E = top->member_functions.find(p_method); if (E) { - ERR_FAIL_COND_V_MSG(!E->get()->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script."); return E->get()->call(nullptr, p_args, p_argcount, r_error); @@ -699,16 +701,12 @@ Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p } bool GDScript::_get(const StringName &p_name, Variant &r_ret) const { - { - const GDScript *top = this; while (top) { - { const Map<StringName, Variant>::Element *E = top->constants.find(p_name); if (E) { - r_ret = E->get(); return true; } @@ -717,7 +715,6 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const { { const Map<StringName, Ref<GDScript>>::Element *E = subclasses.find(p_name); if (E) { - r_ret = E->get(); return true; } @@ -726,7 +723,6 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const { } if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) { - r_ret = get_source_code(); return true; } @@ -734,42 +730,37 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const { return false; } -bool GDScript::_set(const StringName &p_name, const Variant &p_value) { +bool GDScript::_set(const StringName &p_name, const Variant &p_value) { if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) { - set_source_code(p_value); reload(); - } else + } else { return false; + } return true; } void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const { - p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); } void GDScript::_bind_methods() { - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &GDScript::_new, MethodInfo("new")); ClassDB::bind_method(D_METHOD("get_as_byte_code"), &GDScript::get_as_byte_code); } Vector<uint8_t> GDScript::get_as_byte_code() const { - GDScriptTokenizerBuffer tokenizer; return tokenizer.parse_code_string(source); }; Error GDScript::load_byte_code(const String &p_path) { - Vector<uint8_t> bytecode; if (p_path.ends_with("gde")) { - FileAccess *fa = FileAccess::open(p_path, FileAccess::READ); ERR_FAIL_COND_V(!fa, ERR_CANT_OPEN); @@ -798,7 +789,6 @@ Error GDScript::load_byte_code(const String &p_path) { memdelete(fae); } else { - bytecode = FileAccess::get_file_as_array(p_path); } @@ -807,11 +797,13 @@ Error GDScript::load_byte_code(const String &p_path) { String basedir = path; - if (basedir == "") + if (basedir == "") { basedir = get_path(); + } - if (basedir != "") + if (basedir != "") { basedir = basedir.get_base_dir(); + } valid = false; GDScriptParser parser; @@ -832,7 +824,6 @@ Error GDScript::load_byte_code(const String &p_path) { valid = true; for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) { - _set_subclass_path(E->get(), path); } @@ -842,12 +833,10 @@ Error GDScript::load_byte_code(const String &p_path) { } Error GDScript::load_source_code(const String &p_path) { - Vector<uint8_t> sourcef; Error err; FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { - ERR_FAIL_COND_V(err, err); } @@ -862,7 +851,6 @@ Error GDScript::load_source_code(const String &p_path) { String s; if (s.parse_utf8((const char *)w)) { - ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded. Please ensure that scripts are saved in valid UTF-8 unicode."); } @@ -875,29 +863,45 @@ Error GDScript::load_source_code(const String &p_path) { } const Map<StringName, GDScriptFunction *> &GDScript::debug_get_member_functions() const { - return member_functions; } StringName GDScript::debug_get_member_by_index(int p_idx) const { - for (const Map<StringName, MemberInfo>::Element *E = member_indices.front(); E; E = E->next()) { - - if (E->get().index == p_idx) + if (E->get().index == p_idx) { return E->key(); + } } return "<error>"; } Ref<GDScript> GDScript::get_base() const { - return base; } +bool GDScript::inherits_script(const Ref<Script> &p_script) const { + Ref<GDScript> gd = p_script; + if (gd.is_null()) { + return false; + } + + const GDScript *s = this; + + while (s) { + if (s == p_script.ptr()) { + return true; + } + s = s->_base; + } + + return false; +} + bool GDScript::has_script_signal(const StringName &p_signal) const { - if (_signals.has(p_signal)) + if (_signals.has(p_signal)) { return true; + } if (base.is_valid()) { return base->has_script_signal(p_signal); } @@ -908,10 +912,9 @@ bool GDScript::has_script_signal(const StringName &p_signal) const { #endif return false; } -void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const { +void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const { for (const Map<StringName, Vector<StringName>>::Element *E = _signals.front(); E; E = E->next()) { - MethodInfo mi; mi.name = E->key(); for (int i = 0; i < E->get().size(); i++) { @@ -935,7 +938,6 @@ void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const { GDScript::GDScript() : script_list(this) { - valid = false; subclass_count = 0; initializer = nullptr; @@ -980,8 +982,9 @@ void GDScript::_save_orphaned_subclasses() { for (int i = 0; i < weak_subclasses.size(); i++) { ClassRefWithName subclass = weak_subclasses[i]; Object *obj = ObjectDB::get_instance(subclass.id); - if (!obj) + if (!obj) { continue; + } // subclass is not released GDScriptLanguage::get_singleton()->add_orphan_subclass(subclass.fully_qualified_name, subclass.id); } @@ -1022,13 +1025,15 @@ void GDScript::_init_rpc_methods_properties() { } } - if (cscript != this) + if (cscript != this) { sub_E = sub_E->next(); + } - if (sub_E) + if (sub_E) { cscript = sub_E->get().ptr(); - else + } else { cscript = nullptr; + } } // Sort so we are 100% that they are always the same. @@ -1037,6 +1042,15 @@ void GDScript::_init_rpc_methods_properties() { } GDScript::~GDScript() { + { + MutexLock lock(GDScriptLanguage::get_singleton()->lock); + + while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) { + E->self()->_clear_stack(); + pending_func_states.remove(E); + } + } + for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) { memdelete(E->get()); } @@ -1057,7 +1071,6 @@ GDScript::~GDScript() { ////////////////////////////// bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { - //member { const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name); @@ -1092,17 +1105,16 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { GDScript *sptr = script.ptr(); while (sptr) { - Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set); if (E) { - Variant name = p_name; const Variant *args[2] = { &name, &p_value }; Callable::CallError err; Variant ret = E->get()->call(this, (const Variant **)args, 2, err); - if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) + if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) { return true; + } } sptr = sptr->_base; } @@ -1111,10 +1123,8 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { } bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { - const GDScript *sptr = script.ptr(); while (sptr) { - { const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name); if (E) { @@ -1131,7 +1141,6 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { } { - const GDScript *sl = sptr; while (sl) { const Map<StringName, Variant>::Element *E = sl->constants.find(p_name); @@ -1146,7 +1155,6 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { { const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get); if (E) { - Variant name = p_name; const Variant *args[1] = { &name }; @@ -1165,20 +1173,20 @@ 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) + if (r_is_valid) { *r_is_valid = true; + } return sptr->member_info[p_name].type; } sptr = sptr->_base; } - if (r_is_valid) + if (r_is_valid) { *r_is_valid = false; + } return Variant::NIL; } @@ -1189,19 +1197,15 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const List<PropertyInfo> props; while (sptr) { - const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list); if (E) { - Callable::CallError err; Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), nullptr, 0, err); if (err.error == Callable::CallError::CALL_OK) { - ERR_FAIL_COND_MSG(ret.get_type() != Variant::ARRAY, "Wrong type for _get_property_list, must be an array of dictionaries."); Array arr = ret; for (int i = 0; i < arr.size(); i++) { - Dictionary d = arr[i]; ERR_CONTINUE(!d.has("name")); ERR_CONTINUE(!d.has("type")); @@ -1210,12 +1214,15 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const ERR_CONTINUE(pinfo.type < 0 || pinfo.type >= Variant::VARIANT_MAX); pinfo.name = d["name"]; ERR_CONTINUE(pinfo.name == ""); - if (d.has("hint")) + if (d.has("hint")) { pinfo.hint = PropertyHint(d["hint"].operator int()); - if (d.has("hint_string")) + } + if (d.has("hint_string")) { pinfo.hint_string = d["hint_string"]; - if (d.has("usage")) + } + if (d.has("usage")) { pinfo.usage = d["usage"]; + } props.push_back(pinfo); } @@ -1226,7 +1233,6 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const Vector<_GDScriptMemberSort> msort; for (Map<StringName, PropertyInfo>::Element *F = sptr->member_info.front(); F; F = F->next()) { - _GDScriptMemberSort ms; ERR_CONTINUE(!sptr->member_indices.has(F->key())); ms.index = sptr->member_indices[F->key()].index; @@ -1237,7 +1243,6 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const msort.sort(); msort.invert(); for (int i = 0; i < msort.size(); i++) { - props.push_front(sptr->member_info[msort[i].name]); } @@ -1245,23 +1250,20 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const } for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - p_properties->push_back(E->get()); } } void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const { - const GDScript *sptr = script.ptr(); while (sptr) { - for (Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.front(); E; E = E->next()) { - MethodInfo mi; mi.name = E->key(); mi.flags |= METHOD_FLAG_FROM_SCRIPT; - for (int i = 0; i < E->get()->get_argument_count(); i++) + for (int i = 0; i < E->get()->get_argument_count(); i++) { mi.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i))); + } p_list->push_back(mi); } sptr = sptr->_base; @@ -1269,19 +1271,19 @@ void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const { } bool GDScriptInstance::has_method(const StringName &p_method) const { - const GDScript *sptr = script.ptr(); while (sptr) { const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method); - if (E) + if (E) { return true; + } sptr = sptr->_base; } return false; } -Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { +Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { GDScript *sptr = script.ptr(); while (sptr) { Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method); @@ -1295,7 +1297,6 @@ Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_arg } void GDScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - GDScript *sptr = script.ptr(); Callable::CallError ce; @@ -1309,9 +1310,9 @@ void GDScriptInstance::call_multilevel(const StringName &p_method, const Variant } void GDScriptInstance::_ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount) { - - if (sptr->_base) + if (sptr->_base) { _ml_call_reversed(sptr->_base, p_method, p_args, p_argcount); + } Callable::CallError ce; @@ -1322,14 +1323,12 @@ void GDScriptInstance::_ml_call_reversed(GDScript *sptr, const StringName &p_met } void GDScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - if (script.ptr()) { _ml_call_reversed(script.ptr(), p_method, p_args, p_argcount); } } void GDScriptInstance::notification(int p_notification) { - //notification is not virtual, it gets called at ALL levels just like in C. Variant value = p_notification; const Variant *args[1] = { &value }; @@ -1354,27 +1353,28 @@ String GDScriptInstance::to_string(bool *r_valid) { Variant ret = call(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce); if (ce.error == Callable::CallError::CALL_OK) { if (ret.get_type() != Variant::STRING) { - if (r_valid) + if (r_valid) { *r_valid = false; + } ERR_FAIL_V_MSG(String(), "Wrong type for " + CoreStringNames::get_singleton()->_to_string + ", must be a String."); } - if (r_valid) + if (r_valid) { *r_valid = true; + } return ret.operator String(); } } - if (r_valid) + if (r_valid) { *r_valid = false; + } return String(); } Ref<Script> GDScriptInstance::get_script() const { - return script; } ScriptLanguage *GDScriptInstance::get_language() { - return GDScriptLanguage::get_singleton(); } @@ -1419,7 +1419,6 @@ MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_vari } void GDScriptInstance::reload_members() { - #ifdef DEBUG_ENABLED members.resize(script->member_indices.size()); //resize @@ -1429,7 +1428,6 @@ void GDScriptInstance::reload_members() { //pass the values to the new indices for (Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.front(); E; E = E->next()) { - if (member_indices_cache.has(E->key())) { Variant value = members[member_indices_cache[E->key()]]; new_members.write[E->get().index] = value; @@ -1442,7 +1440,6 @@ void GDScriptInstance::reload_members() { //pass the values to the new indices member_indices_cache.clear(); for (Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.front(); E; E = E->next()) { - member_indices_cache[E->key()] = E->get().index; } @@ -1455,9 +1452,14 @@ GDScriptInstance::GDScriptInstance() { } GDScriptInstance::~GDScriptInstance() { - if (script.is_valid() && owner) { - MutexLock lock(GDScriptLanguage::singleton->lock); + MutexLock lock(GDScriptLanguage::get_singleton()->lock); + + while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) { + E->self()->_clear_stack(); + pending_func_states.remove(E); + } + if (script.is_valid() && owner) { script->instances.erase(owner); } } @@ -1467,14 +1469,12 @@ GDScriptInstance::~GDScriptInstance() { GDScriptLanguage *GDScriptLanguage::singleton = nullptr; String GDScriptLanguage::get_name() const { - return "GDScript"; } /* LANGUAGE FUNCTIONS */ void GDScriptLanguage::_add_global(const StringName &p_name, const Variant &p_value) { - if (globals.has(p_name)) { //overwrite existing global_array.write[globals[p_name]] = p_value; @@ -1486,7 +1486,6 @@ void GDScriptLanguage::_add_global(const StringName &p_name, const Variant &p_va } void GDScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) { - _add_global(p_variable, p_value); } @@ -1500,11 +1499,9 @@ void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) { } void GDScriptLanguage::init() { - //populate global constants int gcc = GlobalConstants::get_global_constant_count(); for (int i = 0; i < gcc; i++) { - _add_global(StaticCString::create(GlobalConstants::get_global_constant_name(i)), GlobalConstants::get_global_constant_value(i)); } @@ -1518,14 +1515,15 @@ void GDScriptLanguage::init() { List<StringName> class_list; ClassDB::get_class_list(&class_list); for (List<StringName>::Element *E = class_list.front(); E; E = E->next()) { - StringName n = E->get(); String s = String(n); - if (s.begins_with("_")) + if (s.begins_with("_")) { n = s.substr(1, s.length()); + } - if (globals.has(n)) + if (globals.has(n)) { continue; + } Ref<GDScriptNativeClass> nc = memnew(GDScriptNativeClass(E->get())); _add_global(n, nc); } @@ -1535,29 +1533,27 @@ void GDScriptLanguage::init() { List<Engine::Singleton> singletons; Engine::get_singleton()->get_singletons(&singletons); for (List<Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) { - _add_global(E->get().name, E->get().ptr); } } String GDScriptLanguage::get_type() const { - return "GDScript"; } -String GDScriptLanguage::get_extension() const { +String GDScriptLanguage::get_extension() const { return "gd"; } -Error GDScriptLanguage::execute_file(const String &p_path) { +Error GDScriptLanguage::execute_file(const String &p_path) { // ?? return OK; } + void GDScriptLanguage::finish() { } void GDScriptLanguage::profiling_start() { - #ifdef DEBUG_ENABLED MutexLock lock(this->lock); @@ -1580,7 +1576,6 @@ void GDScriptLanguage::profiling_start() { } void GDScriptLanguage::profiling_stop() { - #ifdef DEBUG_ENABLED MutexLock lock(this->lock); @@ -1589,7 +1584,6 @@ void GDScriptLanguage::profiling_stop() { } int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) { - int current = 0; #ifdef DEBUG_ENABLED @@ -1597,8 +1591,9 @@ int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, SelfList<GDScriptFunction> *elem = function_list.first(); while (elem) { - if (current >= p_info_max) + if (current >= p_info_max) { break; + } p_info_arr[current].call_count = elem->self()->profile.call_count; p_info_arr[current].self_time = elem->self()->profile.self_time; p_info_arr[current].total_time = elem->self()->profile.total_time; @@ -1612,7 +1607,6 @@ int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, } int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) { - int current = 0; #ifdef DEBUG_ENABLED @@ -1620,8 +1614,9 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_ SelfList<GDScriptFunction> *elem = function_list.first(); while (elem) { - if (current >= p_info_max) + if (current >= p_info_max) { break; + } if (elem->self()->profile.last_frame_call_count > 0) { p_info_arr[current].call_count = elem->self()->profile.last_frame_call_count; p_info_arr[current].self_time = elem->self()->profile.last_frame_self_time; @@ -1637,12 +1632,11 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_ } struct GDScriptDepSort { - //must support sorting so inheritance works properly (parent must be reloaded first) bool operator()(const Ref<GDScript> &A, const Ref<GDScript> &B) const { - - if (A == B) + if (A == B) { return false; //shouldn't happen but.. + } const GDScript *I = B->get_base().ptr(); while (I) { if (I == A.ptr()) { @@ -1658,7 +1652,6 @@ struct GDScriptDepSort { }; void GDScriptLanguage::reload_all_scripts() { - #ifdef DEBUG_ENABLED print_verbose("GDScript: Reloading all scripts"); List<Ref<GDScript>> scripts; @@ -1680,7 +1673,6 @@ void GDScriptLanguage::reload_all_scripts() { scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order for (List<Ref<GDScript>>::Element *E = scripts.front(); E; E = E->next()) { - print_verbose("GDScript: Reloading: " + E->get()->get_path()); E->get()->load_source_code(E->get()->get_path()); E->get()->reload(true); @@ -1689,7 +1681,6 @@ void GDScriptLanguage::reload_all_scripts() { } void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) { - #ifdef DEBUG_ENABLED List<Ref<GDScript>> scripts; @@ -1699,7 +1690,6 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so SelfList<GDScript> *elem = script_list.first(); while (elem) { if (elem->self()->get_path().is_resource_file()) { - scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident } elem = elem->next(); @@ -1715,16 +1705,15 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order for (List<Ref<GDScript>>::Element *E = scripts.front(); E; E = E->next()) { - bool reload = E->get() == p_script || to_reload.has(E->get()->get_base()); - if (!reload) + if (!reload) { continue; + } to_reload.insert(E->get(), Map<ObjectID, List<Pair<StringName, Variant>>>()); if (!p_soft_reload) { - //save state and remove script from instances Map<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[E->get()]; @@ -1733,7 +1722,6 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so //save instance info List<Pair<StringName, Variant>> state; if (obj->get_script_instance()) { - obj->get_script_instance()->get_property_state(state); map[obj->get_instance_id()] = state; obj->set_script(Variant()); @@ -1748,7 +1736,6 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so //save instance info if (obj->get_script_instance()) { - map.insert(obj->get_instance_id(), List<Pair<StringName, Variant>>()); List<Pair<StringName, Variant>> &state = map[obj->get_instance_id()]; obj->get_script_instance()->get_property_state(state); @@ -1768,18 +1755,17 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so } for (Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant>>>>::Element *E = to_reload.front(); E; E = E->next()) { - Ref<GDScript> scr = E->key(); scr->reload(p_soft_reload); //restore state if saved for (Map<ObjectID, List<Pair<StringName, Variant>>>::Element *F = E->get().front(); F; F = F->next()) { - List<Pair<StringName, Variant>> &saved_state = F->get(); Object *obj = ObjectDB::get_instance(F->key()); - if (!obj) + if (!obj) { continue; + } if (!p_soft_reload) { //clear it just in case (may be a pending reload state) @@ -1818,7 +1804,6 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so } void GDScriptLanguage::frame() { - calls = 0; #ifdef DEBUG_ENABLED @@ -1842,7 +1827,6 @@ void GDScriptLanguage::frame() { /* EDITOR FUNCTIONS */ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { - static const char *_reserved_words[] = { // operators "and", @@ -1906,7 +1890,6 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { const char **w = _reserved_words; while (*w) { - p_words->push_back(*w); w++; } @@ -1917,12 +1900,10 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { } bool GDScriptLanguage::handles_global_class_type(const String &p_type) const { - return p_type == "GDScript"; } String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const { - Vector<uint8_t> sourcef; Error err; FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); @@ -1936,16 +1917,15 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b parser.parse(source, p_path.get_base_dir(), true, p_path, false, nullptr, true); 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_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; - 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(); + } } if (r_base_type) { - const GDScriptParser::ClassNode *subclass = c; String path = p_path; GDScriptParser subparser; @@ -2019,7 +1999,6 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b #ifdef DEBUG_ENABLED String GDScriptWarning::get_message() const { - #define CHECK_SYMBOLS(m_amount) ERR_FAIL_COND_V(symbols.size() < m_amount, String()); switch (code) { @@ -2126,7 +2105,8 @@ String GDScriptWarning::get_message() const { case STANDALONE_TERNARY: { return "Standalone ternary conditional operator: the return value is being discarded."; } - case WARNING_MAX: break; // Can't happen, but silences warning + case WARNING_MAX: + break; // Can't happen, but silences warning } ERR_FAIL_V_MSG(String(), "Invalid GDScript warning code: " + get_name_from_code(code) + "."); @@ -2187,7 +2167,6 @@ GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name) #endif // DEBUG_ENABLED GDScriptLanguage::GDScriptLanguage() { - calls = 0; ERR_FAIL_COND(singleton); singleton = this; @@ -2232,7 +2211,6 @@ GDScriptLanguage::GDScriptLanguage() { } GDScriptLanguage::~GDScriptLanguage() { - if (_call_stack) { memdelete_arr(_call_stack); } @@ -2245,29 +2223,30 @@ void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_name) { Map<String, ObjectID>::Element *orphan_subclass_element = orphan_subclasses.find(p_qualified_name); - if (!orphan_subclass_element) + if (!orphan_subclass_element) { return Ref<GDScript>(); + } ObjectID orphan_subclass = orphan_subclass_element->get(); Object *obj = ObjectDB::get_instance(orphan_subclass); orphan_subclasses.erase(orphan_subclass_element); - if (!obj) + if (!obj) { return Ref<GDScript>(); + } return Ref<GDScript>(Object::cast_to<GDScript>(obj)); } /*************** RESOURCE ***************/ -RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) { - - if (r_error) +RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { + if (r_error) { *r_error = ERR_FILE_CANT_OPEN; + } GDScript *script = memnew(GDScript); Ref<GDScript> scriptres(script); if (p_path.ends_with(".gde") || p_path.ends_with(".gdc")) { - script->set_script_path(p_original_path); // script needs this. script->set_path(p_original_path); Error err = script->load_byte_code(p_path); @@ -2282,34 +2261,32 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_ori script->reload(); } - if (r_error) + if (r_error) { *r_error = OK; + } return scriptres; } void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("gd"); p_extensions->push_back("gdc"); p_extensions->push_back("gde"); } bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const { - return (p_type == "Script" || p_type == "GDScript"); } String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const { - String el = p_path.get_extension().to_lower(); - if (el == "gd" || el == "gdc" || el == "gde") + if (el == "gd" || el == "gdc" || el == "gde") { return "GDScript"; + } return ""; } void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { - FileAccessRef file = FileAccess::open(p_path, FileAccess::READ); ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_path + "'."); @@ -2329,7 +2306,6 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S } Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - Ref<GDScript> sqscr = p_resource; ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER); @@ -2356,12 +2332,11 @@ Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resou } void ResourceFormatSaverGDScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { - if (Object::cast_to<GDScript>(*p_resource)) { p_extensions->push_back("gd"); } } -bool ResourceFormatSaverGDScript::recognize(const RES &p_resource) const { +bool ResourceFormatSaverGDScript::recognize(const RES &p_resource) const { return Object::cast_to<GDScript>(*p_resource) != nullptr; } diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 2c5876372b..e770dc3abd 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -39,7 +39,6 @@ #include "gdscript_function.h" class GDScriptNativeClass : public Reference { - GDCLASS(GDScriptNativeClass, Reference); StringName name; @@ -56,7 +55,6 @@ public: }; class GDScript : public Script { - GDCLASS(GDScript, Script); bool tool; bool valid; @@ -117,6 +115,8 @@ class GDScript : public Script { String fully_qualified_name; SelfList<GDScript> script_list; + SelfList<GDScriptFunctionState>::List pending_func_states; + GDScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error); void _set_subclass_path(Ref<GDScript> &p_sc, const String &p_path); @@ -133,7 +133,7 @@ class GDScript : public Script { #endif - bool _update_exports(); + bool _update_exports(bool *r_err = nullptr, bool p_recursive_call = false); void _save_orphaned_subclasses(); void _init_rpc_methods_properties(); @@ -151,6 +151,8 @@ protected: public: virtual bool is_valid() const { return valid; } + bool inherits_script(const Ref<Script> &p_script) const; + const Map<StringName, Ref<GDScript>> &get_subclasses() const { return subclasses; } const Map<StringName, Variant> &get_constants() const { return constants; } const Set<StringName> &get_members() const { return members; } @@ -207,11 +209,11 @@ public: virtual int get_member_line(const StringName &p_member) const { #ifdef TOOLS_ENABLED - if (member_lines.has(p_member)) + if (member_lines.has(p_member)) { return member_lines[p_member]; - else + } #endif - return -1; + return -1; } virtual void get_constants(Map<StringName, Variant> *p_constants); @@ -252,6 +254,8 @@ class GDScriptInstance : public ScriptInstance { Vector<Variant> members; bool base_ref; + SelfList<GDScriptFunctionState>::List pending_func_states; + void _ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount); public: @@ -328,22 +332,23 @@ struct GDScriptWarning { DEPRECATED_KEYWORD, // The keyword is deprecated and should be replaced STANDALONE_TERNARY, // Return value of ternary expression is discarded WARNING_MAX, - } code; + }; + + Code code = WARNING_MAX; Vector<String> symbols; - int line; + int line = -1; String get_name() const; String get_message() const; static String get_name_from_code(Code p_code); static Code get_code_from_name(const String &p_name); - GDScriptWarning() : - code(WARNING_MAX), - line(-1) {} + GDScriptWarning() {} }; #endif // DEBUG_ENABLED class GDScriptLanguage : public ScriptLanguage { + friend class GDScriptFunctionState; static GDScriptLanguage *singleton; @@ -353,7 +358,6 @@ class GDScriptLanguage : public ScriptLanguage { Map<StringName, Variant> named_globals; struct CallLevel { - Variant *stack; GDScriptFunction *function; GDScriptInstance *instance; @@ -392,12 +396,13 @@ public: bool debug_break_parse(const String &p_file, int p_line, const String &p_error); _FORCE_INLINE_ void enter_function(GDScriptInstance *p_instance, GDScriptFunction *p_function, Variant *p_stack, int *p_ip, int *p_line) { - - if (Thread::get_main_id() != Thread::get_caller_id()) + if (Thread::get_main_id() != Thread::get_caller_id()) { return; //no support for other threads than main for now + } - if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) + if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) { EngineDebugger::get_script_debugger()->set_depth(EngineDebugger::get_script_debugger()->get_depth() + 1); + } if (_debug_call_stack_pos >= _debug_max_call_stack) { //stack overflow @@ -415,15 +420,15 @@ public: } _FORCE_INLINE_ void exit_function() { - - if (Thread::get_main_id() != Thread::get_caller_id()) + if (Thread::get_main_id() != Thread::get_caller_id()) { return; //no support for other threads than main for now + } - if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) + if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) { EngineDebugger::get_script_debugger()->set_depth(EngineDebugger::get_script_debugger()->get_depth() - 1); + } if (_debug_call_stack_pos == 0) { - _debug_error = "Stack Underflow (Engine Bug)"; EngineDebugger::get_script_debugger()->debug(this); return; @@ -433,8 +438,9 @@ public: } virtual Vector<StackInfo> debug_get_current_stack_info() { - if (Thread::get_main_id() != Thread::get_caller_id()) + if (Thread::get_main_id() != Thread::get_caller_id()) { return Vector<StackInfo>(); + } Vector<StackInfo> csi; csi.resize(_debug_call_stack_pos); @@ -449,7 +455,6 @@ public: } struct { - StringName _init; StringName _notification; StringName _set; @@ -545,7 +550,7 @@ public: class ResourceFormatLoaderGDScript : public ResourceFormatLoader { public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr); + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 2bbec29043..bc095ae1f9 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -33,24 +33,24 @@ #include "gdscript.h" bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) { - - if (codegen.function_node && codegen.function_node->_static) + if (codegen.function_node && codegen.function_node->_static) { return false; + } - if (codegen.stack_identifiers.has(p_name)) + if (codegen.stack_identifiers.has(p_name)) { return false; //shadowed + } return _is_class_member_property(codegen.script, p_name); } bool GDScriptCompiler::_is_class_member_property(GDScript *owner, const StringName &p_name) { - GDScript *scr = owner; GDScriptNativeClass *nc = nullptr; while (scr) { - - if (scr->native.is_valid()) + if (scr->native.is_valid()) { nc = scr->native.ptr(); + } scr = scr->_base; } @@ -60,9 +60,9 @@ bool GDScriptCompiler::_is_class_member_property(GDScript *owner, const StringNa } void GDScriptCompiler::_set_error(const String &p_error, const GDScriptParser::Node *p_node) { - - if (error != "") + if (error != "") { return; + } error = p_error; if (p_node) { @@ -75,12 +75,12 @@ void GDScriptCompiler::_set_error(const String &p_error, const GDScriptParser::N } bool GDScriptCompiler::_create_unary_operator(CodeGen &codegen, const GDScriptParser::OperatorNode *on, Variant::Operator op, int p_stack_level) { - ERR_FAIL_COND_V(on->arguments.size() != 1, false); int src_address_a = _parse_expression(codegen, on->arguments[0], p_stack_level); - if (src_address_a < 0) + if (src_address_a < 0) { return false; + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_OPERATOR); // perform operator codegen.opcodes.push_back(op); //which operator @@ -91,18 +91,20 @@ bool GDScriptCompiler::_create_unary_operator(CodeGen &codegen, const GDScriptPa } bool GDScriptCompiler::_create_binary_operator(CodeGen &codegen, const GDScriptParser::OperatorNode *on, Variant::Operator op, int p_stack_level, bool p_initializer, int p_index_addr) { - ERR_FAIL_COND_V(on->arguments.size() != 2, false); int src_address_a = _parse_expression(codegen, on->arguments[0], p_stack_level, false, p_initializer, p_index_addr); - if (src_address_a < 0) + if (src_address_a < 0) { return false; - if (src_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) + } + if (src_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) { p_stack_level++; //uses stack for return, increase stack + } int src_address_b = _parse_expression(codegen, on->arguments[1], p_stack_level, false, p_initializer); - if (src_address_b < 0) + if (src_address_b < 0) { return false; + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_OPERATOR); // perform operator codegen.opcodes.push_back(op); //which operator @@ -172,28 +174,44 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D } int GDScriptCompiler::_parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::OperatorNode *p_expression, int p_stack_level, int p_index_addr) { - Variant::Operator var_op = Variant::OP_MAX; switch (p_expression->op) { - - case GDScriptParser::OperatorNode::OP_ASSIGN_ADD: var_op = Variant::OP_ADD; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_SUB: var_op = Variant::OP_SUBTRACT; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_MUL: var_op = Variant::OP_MULTIPLY; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_DIV: var_op = Variant::OP_DIVIDE; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_MOD: var_op = Variant::OP_MODULE; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: var_op = Variant::OP_SHIFT_LEFT; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: var_op = Variant::OP_SHIFT_RIGHT; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_AND: var_op = Variant::OP_BIT_AND; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_OR: var_op = Variant::OP_BIT_OR; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_XOR: var_op = Variant::OP_BIT_XOR; break; + case GDScriptParser::OperatorNode::OP_ASSIGN_ADD: + var_op = Variant::OP_ADD; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_SUB: + var_op = Variant::OP_SUBTRACT; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_MUL: + var_op = Variant::OP_MULTIPLY; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_DIV: + var_op = Variant::OP_DIVIDE; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_MOD: + var_op = Variant::OP_MODULE; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: + var_op = Variant::OP_SHIFT_LEFT; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: + var_op = Variant::OP_SHIFT_RIGHT; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_AND: + var_op = Variant::OP_BIT_AND; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_OR: + var_op = Variant::OP_BIT_OR; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_XOR: + var_op = Variant::OP_BIT_XOR; + break; case GDScriptParser::OperatorNode::OP_INIT_ASSIGN: case GDScriptParser::OperatorNode::OP_ASSIGN: { - //none } break; default: { - ERR_FAIL_V(-1); } } @@ -201,12 +219,12 @@ int GDScriptCompiler::_parse_assign_right_expression(CodeGen &codegen, const GDS bool initializer = p_expression->op == GDScriptParser::OperatorNode::OP_INIT_ASSIGN; if (var_op == Variant::OP_MAX) { - return _parse_expression(codegen, p_expression->arguments[1], p_stack_level, false, initializer); } - if (!_create_binary_operator(codegen, p_expression, var_op, p_stack_level, initializer, p_index_addr)) + if (!_create_binary_operator(codegen, p_expression, var_op, p_stack_level, initializer, p_index_addr)) { return -1; + } int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode @@ -215,7 +233,6 @@ int GDScriptCompiler::_parse_assign_right_expression(CodeGen &codegen, const GDS } int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root, bool p_initializer, int p_index_addr) { - switch (p_expression->type) { //should parse variable declaration and adjust stack accordingly... case GDScriptParser::Node::TYPE_IDENTIFIER: { @@ -231,7 +248,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: // TRY STACK! if (!p_initializer && codegen.stack_identifiers.has(identifier)) { - int pos = codegen.stack_identifiers[identifier]; return pos | (GDScriptFunction::ADDR_TYPE_STACK_VARIABLE << GDScriptFunction::ADDR_BITS); } @@ -249,11 +265,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: //TRY MEMBERS! if (!codegen.function_node || !codegen.function_node->_static) { - // TRY MEMBER VARIABLES! //static function if (codegen.script->member_indices.has(identifier)) { - int idx = codegen.script->member_indices[identifier].index; return idx | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS); //argument (stack root) } @@ -263,26 +277,23 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: GDScript *owner = codegen.script; while (owner) { - GDScript *scr = owner; GDScriptNativeClass *nc = nullptr; while (scr) { - if (scr->constants.has(identifier)) { - //int idx=scr->constants[identifier]; int idx = codegen.get_name_map_pos(identifier); return idx | (GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS); //argument (stack root) } - if (scr->native.is_valid()) + if (scr->native.is_valid()) { nc = scr->native.ptr(); + } scr = scr->_base; } // CLASS C++ Integer Constant if (nc) { - bool success = false; int constant = ClassDB::get_integer_constant(nc->get_name(), identifier, &success); if (success) { @@ -290,7 +301,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: int idx; if (!codegen.constant_map.has(key)) { - idx = codegen.constant_map.size(); codegen.constant_map[key] = idx; @@ -306,7 +316,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) { - int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier]; return idx | (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root) } @@ -314,7 +323,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: /* TRY GLOBAL CLASSES */ if (ScriptServer::is_global_class(identifier)) { - const GDScriptParser::ClassNode *class_node = codegen.class_node; while (class_node->owner) { class_node = class_node->owner; @@ -335,7 +343,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: int idx; if (!codegen.constant_map.has(key)) { - idx = codegen.constant_map.size(); codegen.constant_map[key] = idx; @@ -348,7 +355,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: #ifdef TOOLS_ENABLED if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) { - int idx = codegen.named_globals.find(identifier); if (idx == -1) { idx = codegen.named_globals.size(); @@ -372,7 +378,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: int idx; if (!codegen.constant_map.has(cn->value)) { - idx = codegen.constant_map.size(); codegen.constant_map[cn->value] = idx; @@ -392,17 +397,16 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: return (GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS); } break; case GDScriptParser::Node::TYPE_ARRAY: { - const GDScriptParser::ArrayNode *an = static_cast<const GDScriptParser::ArrayNode *>(p_expression); Vector<int> values; int slevel = p_stack_level; for (int i = 0; i < an->elements.size(); i++) { - int ret = _parse_expression(codegen, an->elements[i], slevel); - if (ret < 0) + if (ret < 0) { return ret; + } if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) { slevel++; codegen.alloc_stack(slevel); @@ -413,8 +417,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(GDScriptFunction::OPCODE_CONSTRUCT_ARRAY); codegen.opcodes.push_back(values.size()); - for (int i = 0; i < values.size(); i++) + for (int i = 0; i < values.size(); i++) { codegen.opcodes.push_back(values[i]); + } int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode @@ -423,17 +428,16 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } break; case GDScriptParser::Node::TYPE_DICTIONARY: { - const GDScriptParser::DictionaryNode *dn = static_cast<const GDScriptParser::DictionaryNode *>(p_expression); Vector<int> values; int slevel = p_stack_level; for (int i = 0; i < dn->elements.size(); i++) { - int ret = _parse_expression(codegen, dn->elements[i].key, slevel); - if (ret < 0) + if (ret < 0) { return ret; + } if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) { slevel++; codegen.alloc_stack(slevel); @@ -442,8 +446,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: values.push_back(ret); ret = _parse_expression(codegen, dn->elements[i].value, slevel); - if (ret < 0) + if (ret < 0) { return ret; + } if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) { slevel++; codegen.alloc_stack(slevel); @@ -454,8 +459,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY); codegen.opcodes.push_back(dn->elements.size()); - for (int i = 0; i < values.size(); i++) + for (int i = 0; i < values.size(); i++) { codegen.opcodes.push_back(values[i]); + } int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode @@ -468,8 +474,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: int slevel = p_stack_level; int src_addr = _parse_expression(codegen, cn->source_node, slevel); - if (src_addr < 0) + if (src_addr < 0) { return src_addr; + } if (src_addr & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) { slevel++; codegen.alloc_stack(slevel); @@ -485,7 +492,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: case GDScriptDataType::NATIVE: { int class_idx; if (GDScriptLanguage::get_singleton()->get_global_map().has(cast_type.native_type)) { - class_idx = GDScriptLanguage::get_singleton()->get_global_map()[cast_type.native_type]; class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root) } else { @@ -497,7 +503,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } break; case GDScriptDataType::SCRIPT: case GDScriptDataType::GDSCRIPT: { - Variant script = cast_type.script_type; int idx = codegen.get_constant_pos(script); idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access) @@ -523,10 +528,8 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: const GDScriptParser::OperatorNode *on = static_cast<const GDScriptParser::OperatorNode *>(p_expression); switch (on->op) { - //call/constructor operator case GDScriptParser::OperatorNode::OP_PARENT_CALL: { - ERR_FAIL_COND_V(on->arguments.size() < 1, -1); const GDScriptParser::IdentifierNode *in = (const GDScriptParser::IdentifierNode *)on->arguments[0]; @@ -534,10 +537,10 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: Vector<int> arguments; int slevel = p_stack_level; for (int i = 1; i < on->arguments.size(); i++) { - int ret = _parse_expression(codegen, on->arguments[i], slevel); - if (ret < 0) + if (ret < 0) { return ret; + } if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) { slevel++; codegen.alloc_stack(slevel); @@ -551,12 +554,12 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(codegen.get_name_map_pos(in->name)); //instance codegen.opcodes.push_back(arguments.size()); //argument count codegen.alloc_call(arguments.size()); - for (int i = 0; i < arguments.size(); i++) + for (int i = 0; i < arguments.size(); i++) { codegen.opcodes.push_back(arguments[i]); //arguments + } } break; case GDScriptParser::OperatorNode::OP_CALL: { - if (on->arguments[0]->type == GDScriptParser::Node::TYPE_TYPE) { //construct a basic type ERR_FAIL_COND_V(on->arguments.size() < 1, -1); @@ -567,10 +570,10 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: Vector<int> arguments; int slevel = p_stack_level; for (int i = 1; i < on->arguments.size(); i++) { - int ret = _parse_expression(codegen, on->arguments[i], slevel); - if (ret < 0) + if (ret < 0) { return ret; + } if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) { slevel++; codegen.alloc_stack(slevel); @@ -583,8 +586,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(vtype); //instance codegen.opcodes.push_back(arguments.size()); //argument count codegen.alloc_call(arguments.size()); - for (int i = 0; i < arguments.size(); i++) + for (int i = 0; i < arguments.size(); i++) { codegen.opcodes.push_back(arguments[i]); //arguments + } } else if (on->arguments[0]->type == GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION) { //built in function @@ -594,10 +598,10 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: Vector<int> arguments; int slevel = p_stack_level; for (int i = 1; i < on->arguments.size(); i++) { - int ret = _parse_expression(codegen, on->arguments[i], slevel); - if (ret < 0) + if (ret < 0) { return ret; + } if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) { slevel++; @@ -611,8 +615,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(static_cast<const GDScriptParser::BuiltInFunctionNode *>(on->arguments[0])->function); codegen.opcodes.push_back(on->arguments.size() - 1); codegen.alloc_call(on->arguments.size() - 1); - for (int i = 0; i < arguments.size(); i++) + for (int i = 0; i < arguments.size(); i++) { codegen.opcodes.push_back(arguments[i]); + } } else { //regular function @@ -628,14 +633,12 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: int slevel = p_stack_level; for (int i = 0; i < on->arguments.size(); i++) { - int ret; if (i == 0 && on->arguments[i]->type == GDScriptParser::Node::TYPE_SELF && codegen.function_node && codegen.function_node->_static) { //static call to self ret = (GDScriptFunction::ADDR_TYPE_CLASS << GDScriptFunction::ADDR_BITS); } else if (i == 1) { - if (on->arguments[i]->type != GDScriptParser::Node::TYPE_IDENTIFIER) { _set_error("Attempt to call a non-identifier.", on); return -1; @@ -644,10 +647,10 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: ret = codegen.get_name_map_pos(id->name); } else { - ret = _parse_expression(codegen, on->arguments[i], slevel); - if (ret < 0) + if (ret < 0) { return ret; + } if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) { slevel++; codegen.alloc_stack(slevel); @@ -659,21 +662,21 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(p_root ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN); // perform operator codegen.opcodes.push_back(on->arguments.size() - 2); codegen.alloc_call(on->arguments.size() - 2); - for (int i = 0; i < arguments.size(); i++) + for (int i = 0; i < arguments.size(); i++) { codegen.opcodes.push_back(arguments[i]); + } } } break; case GDScriptParser::OperatorNode::OP_YIELD: { - ERR_FAIL_COND_V(on->arguments.size() && on->arguments.size() != 2, -1); Vector<int> arguments; int slevel = p_stack_level; for (int i = 0; i < on->arguments.size(); i++) { - int ret = _parse_expression(codegen, on->arguments[i], slevel); - if (ret < 0) + if (ret < 0) { return ret; + } if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) { slevel++; codegen.alloc_stack(slevel); @@ -683,8 +686,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: //push call bytecode codegen.opcodes.push_back(arguments.size() == 0 ? GDScriptFunction::OPCODE_YIELD : GDScriptFunction::OPCODE_YIELD_SIGNAL); // basic type constructor - for (int i = 0; i < arguments.size(); i++) + for (int i = 0; i < arguments.size(); i++) { codegen.opcodes.push_back(arguments[i]); //arguments + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_YIELD_RESUME); //next will be where to place the result :) @@ -693,22 +697,21 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: //indexing operator case GDScriptParser::OperatorNode::OP_INDEX: case GDScriptParser::OperatorNode::OP_INDEX_NAMED: { - ERR_FAIL_COND_V(on->arguments.size() != 2, -1); int slevel = p_stack_level; bool named = (on->op == GDScriptParser::OperatorNode::OP_INDEX_NAMED); int from = _parse_expression(codegen, on->arguments[0], slevel); - if (from < 0) + if (from < 0) { return from; + } int index; if (p_index_addr != 0) { index = p_index_addr; } else if (named) { if (on->arguments[0]->type == GDScriptParser::Node::TYPE_SELF && codegen.script && codegen.function_node && !codegen.function_node->_static) { - GDScriptParser::IdentifierNode *identifier = static_cast<GDScriptParser::IdentifierNode *>(on->arguments[1]); const Map<StringName, GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(identifier->name); @@ -729,7 +732,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: index = codegen.get_name_map_pos(static_cast<GDScriptParser::IdentifierNode *>(on->arguments[1])->name); } else { - if (on->arguments[1]->type == GDScriptParser::Node::TYPE_CONSTANT && static_cast<const GDScriptParser::ConstantNode *>(on->arguments[1])->value.get_type() == Variant::STRING) { //also, somehow, named (speed up anyway) StringName name = static_cast<const GDScriptParser::ConstantNode *>(on->arguments[1])->value; @@ -744,8 +746,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } index = _parse_expression(codegen, on->arguments[1], slevel); - if (index < 0) + if (index < 0) { return index; + } } } @@ -755,20 +758,21 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } break; case GDScriptParser::OperatorNode::OP_AND: { - // AND operator with early out on failure int res = _parse_expression(codegen, on->arguments[0], p_stack_level); - if (res < 0) + if (res < 0) { return res; + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT); codegen.opcodes.push_back(res); int jump_fail_pos = codegen.opcodes.size(); codegen.opcodes.push_back(0); res = _parse_expression(codegen, on->arguments[1], p_stack_level); - if (res < 0) + if (res < 0) { return res; + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT); codegen.opcodes.push_back(res); @@ -788,20 +792,21 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } break; case GDScriptParser::OperatorNode::OP_OR: { - // OR operator with early out on success int res = _parse_expression(codegen, on->arguments[0], p_stack_level); - if (res < 0) + if (res < 0) { return res; + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF); codegen.opcodes.push_back(res); int jump_success_pos = codegen.opcodes.size(); codegen.opcodes.push_back(0); res = _parse_expression(codegen, on->arguments[1], p_stack_level); - if (res < 0) + if (res < 0) { return res; + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF); codegen.opcodes.push_back(res); @@ -822,20 +827,21 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } break; // ternary operators case GDScriptParser::OperatorNode::OP_TERNARY_IF: { - // x IF a ELSE y operator with early out on failure int res = _parse_expression(codegen, on->arguments[0], p_stack_level); - if (res < 0) + if (res < 0) { return res; + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT); codegen.opcodes.push_back(res); int jump_fail_pos = codegen.opcodes.size(); codegen.opcodes.push_back(0); res = _parse_expression(codegen, on->arguments[1], p_stack_level); - if (res < 0) + if (res < 0) { return res; + } codegen.alloc_stack(p_stack_level); //it will be used.. codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN); @@ -847,8 +853,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.write[jump_fail_pos] = codegen.opcodes.size(); res = _parse_expression(codegen, on->arguments[2], p_stack_level); - if (res < 0) + if (res < 0) { return res; + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN); codegen.opcodes.push_back(p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); @@ -861,71 +868,113 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } break; //unary operators case GDScriptParser::OperatorNode::OP_NEG: { - if (!_create_unary_operator(codegen, on, Variant::OP_NEGATE, p_stack_level)) return -1; + if (!_create_unary_operator(codegen, on, Variant::OP_NEGATE, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_POS: { - if (!_create_unary_operator(codegen, on, Variant::OP_POSITIVE, p_stack_level)) return -1; + if (!_create_unary_operator(codegen, on, Variant::OP_POSITIVE, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_NOT: { - if (!_create_unary_operator(codegen, on, Variant::OP_NOT, p_stack_level)) return -1; + if (!_create_unary_operator(codegen, on, Variant::OP_NOT, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_BIT_INVERT: { - if (!_create_unary_operator(codegen, on, Variant::OP_BIT_NEGATE, p_stack_level)) return -1; + if (!_create_unary_operator(codegen, on, Variant::OP_BIT_NEGATE, p_stack_level)) { + return -1; + } } break; //binary operators (in precedence order) case GDScriptParser::OperatorNode::OP_IN: { - if (!_create_binary_operator(codegen, on, Variant::OP_IN, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_IN, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_EQUAL: { - if (!_create_binary_operator(codegen, on, Variant::OP_EQUAL, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_EQUAL, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_NOT_EQUAL: { - if (!_create_binary_operator(codegen, on, Variant::OP_NOT_EQUAL, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_NOT_EQUAL, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_LESS: { - if (!_create_binary_operator(codegen, on, Variant::OP_LESS, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_LESS, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_LESS_EQUAL: { - if (!_create_binary_operator(codegen, on, Variant::OP_LESS_EQUAL, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_LESS_EQUAL, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_GREATER: { - if (!_create_binary_operator(codegen, on, Variant::OP_GREATER, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_GREATER, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_GREATER_EQUAL: { - if (!_create_binary_operator(codegen, on, Variant::OP_GREATER_EQUAL, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_GREATER_EQUAL, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_ADD: { - if (!_create_binary_operator(codegen, on, Variant::OP_ADD, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_ADD, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_SUB: { - if (!_create_binary_operator(codegen, on, Variant::OP_SUBTRACT, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_SUBTRACT, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_MUL: { - if (!_create_binary_operator(codegen, on, Variant::OP_MULTIPLY, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_MULTIPLY, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_DIV: { - if (!_create_binary_operator(codegen, on, Variant::OP_DIVIDE, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_DIVIDE, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_MOD: { - if (!_create_binary_operator(codegen, on, Variant::OP_MODULE, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_MODULE, p_stack_level)) { + return -1; + } } break; //case GDScriptParser::OperatorNode::OP_SHIFT_LEFT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_LEFT,p_stack_level)) return -1;} break; //case GDScriptParser::OperatorNode::OP_SHIFT_RIGHT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_RIGHT,p_stack_level)) return -1;} break; case GDScriptParser::OperatorNode::OP_BIT_AND: { - if (!_create_binary_operator(codegen, on, Variant::OP_BIT_AND, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_BIT_AND, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_BIT_OR: { - if (!_create_binary_operator(codegen, on, Variant::OP_BIT_OR, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_BIT_OR, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_BIT_XOR: { - if (!_create_binary_operator(codegen, on, Variant::OP_BIT_XOR, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_BIT_XOR, p_stack_level)) { + return -1; + } } break; //shift case GDScriptParser::OperatorNode::OP_SHIFT_LEFT: { - if (!_create_binary_operator(codegen, on, Variant::OP_SHIFT_LEFT, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_SHIFT_LEFT, p_stack_level)) { + return -1; + } } break; case GDScriptParser::OperatorNode::OP_SHIFT_RIGHT: { - if (!_create_binary_operator(codegen, on, Variant::OP_SHIFT_RIGHT, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_SHIFT_RIGHT, p_stack_level)) { + return -1; + } } break; //assignment operators case GDScriptParser::OperatorNode::OP_ASSIGN_ADD: @@ -940,18 +989,15 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_XOR: case GDScriptParser::OperatorNode::OP_INIT_ASSIGN: case GDScriptParser::OperatorNode::OP_ASSIGN: { - ERR_FAIL_COND_V(on->arguments.size() != 2, -1); if (on->arguments[0]->type == GDScriptParser::Node::TYPE_OPERATOR && (static_cast<GDScriptParser::OperatorNode *>(on->arguments[0])->op == GDScriptParser::OperatorNode::OP_INDEX || static_cast<GDScriptParser::OperatorNode *>(on->arguments[0])->op == GDScriptParser::OperatorNode::OP_INDEX_NAMED)) { - // SET (chained) MODE! #ifdef DEBUG_ENABLED if (static_cast<GDScriptParser::OperatorNode *>(on->arguments[0])->op == GDScriptParser::OperatorNode::OP_INDEX_NAMED) { const GDScriptParser::OperatorNode *inon = static_cast<GDScriptParser::OperatorNode *>(on->arguments[0]); if (inon->arguments[0]->type == GDScriptParser::Node::TYPE_SELF && codegen.script && codegen.function_node && !codegen.function_node->_static) { - const Map<StringName, GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(static_cast<GDScriptParser::IdentifierNode *>(inon->arguments[1])->name); if (MI && MI->get().setter == codegen.function_node->name) { String n = static_cast<GDScriptParser::IdentifierNode *>(inon->arguments[1])->name; @@ -976,13 +1022,10 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: //create get/set chain GDScriptParser::OperatorNode *n = op; while (true) { - chain.push_back(n); if (n->arguments[0]->type != GDScriptParser::Node::TYPE_OPERATOR) { - //check for a built-in property if (n->arguments[0]->type == GDScriptParser::Node::TYPE_IDENTIFIER) { - GDScriptParser::IdentifierNode *identifier = static_cast<GDScriptParser::IdentifierNode *>(n->arguments[0]); if (_is_class_member_property(codegen, identifier->name)) { assign_property = identifier->name; @@ -991,8 +1034,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: break; } n = static_cast<GDScriptParser::OperatorNode *>(n->arguments[0]); - if (n->op != GDScriptParser::OperatorNode::OP_INDEX && n->op != GDScriptParser::OperatorNode::OP_INDEX_NAMED) + if (n->op != GDScriptParser::OperatorNode::OP_INDEX && n->op != GDScriptParser::OperatorNode::OP_INDEX_NAMED) { break; + } } } @@ -1000,8 +1044,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: //get at (potential) root stack pos, so it can be returned int prev_pos = _parse_expression(codegen, chain.back()->get()->arguments[0], slevel); - if (prev_pos < 0) + if (prev_pos < 0) { return prev_pos; + } int retval = prev_pos; if (retval & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) { @@ -1012,7 +1057,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: Vector<int> setchain; if (assign_property != StringName()) { - // recover and assign at the end, this allows stuff like // position.x+=2.0 // in Node2D @@ -1022,20 +1066,18 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } for (List<GDScriptParser::OperatorNode *>::Element *E = chain.back(); E; E = E->prev()) { - - if (E == chain.front()) //ignore first + if (E == chain.front()) { //ignore first break; + } bool named = E->get()->op == GDScriptParser::OperatorNode::OP_INDEX_NAMED; int key_idx; if (named) { - key_idx = codegen.get_name_map_pos(static_cast<const GDScriptParser::IdentifierNode *>(E->get()->arguments[1])->name); //printf("named key %x\n",key_idx); } else { - if (prev_pos & (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS)) { slevel++; codegen.alloc_stack(slevel); @@ -1048,8 +1090,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: //stack was raised here if retval was stack but.. } - if (key_idx < 0) //error + if (key_idx < 0) { //error return key_idx; + } codegen.opcodes.push_back(named ? GDScriptFunction::OPCODE_GET_NAMED : GDScriptFunction::OPCODE_GET); codegen.opcodes.push_back(prev_pos); @@ -1076,17 +1119,16 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: bool named = false; if (op->op == GDScriptParser::OperatorNode::OP_INDEX_NAMED) { - set_index = codegen.get_name_map_pos(static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[1])->name); named = true; } else { - set_index = _parse_expression(codegen, op->arguments[1], slevel + 1); named = false; } - if (set_index < 0) //error + if (set_index < 0) { //error return set_index; + } if (set_index & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) { slevel++; @@ -1094,8 +1136,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } int set_value = _parse_assign_right_expression(codegen, on, slevel + 1, named ? 0 : set_index); - if (set_value < 0) //error + if (set_value < 0) { //error return set_value; + } codegen.opcodes.push_back(named ? GDScriptFunction::OPCODE_SET_NAMED : GDScriptFunction::OPCODE_SET); codegen.opcodes.push_back(prev_pos); @@ -1103,7 +1146,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(set_value); for (int i = 0; i < setchain.size(); i++) { - codegen.opcodes.push_back(setchain[i]); } @@ -1115,8 +1157,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: int slevel = p_stack_level; int src_address = _parse_assign_right_expression(codegen, on, slevel); - if (src_address < 0) + if (src_address < 0) { return -1; + } StringName name = static_cast<GDScriptParser::IdentifierNode *>(on->arguments[0])->name; @@ -1126,14 +1169,14 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: return GDScriptFunction::ADDR_TYPE_NIL << GDScriptFunction::ADDR_BITS; } else { - //REGULAR ASSIGNMENT MODE!! int slevel = p_stack_level; int dst_address_a = _parse_expression(codegen, on->arguments[0], slevel, false, on->op == GDScriptParser::OperatorNode::OP_INIT_ASSIGN); - if (dst_address_a < 0) + if (dst_address_a < 0) { return -1; + } if (dst_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) { slevel++; @@ -1141,8 +1184,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } int src_address_b = _parse_assign_right_expression(codegen, on, slevel); - if (src_address_b < 0) + if (src_address_b < 0) { return -1; + } GDScriptDataType assign_type = _gdtype_from_datatype(on->arguments[0]->get_datatype()); @@ -1158,7 +1202,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: case GDScriptDataType::NATIVE: { int class_idx; if (GDScriptLanguage::get_singleton()->get_global_map().has(assign_type.native_type)) { - class_idx = GDScriptLanguage::get_singleton()->get_global_map()[assign_type.native_type]; class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root) } else { @@ -1172,7 +1215,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } break; case GDScriptDataType::SCRIPT: case GDScriptDataType::GDSCRIPT: { - Variant script = assign_type.script_type; int idx = codegen.get_constant_pos(script); idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access) @@ -1201,21 +1243,23 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } } break; case GDScriptParser::OperatorNode::OP_IS: { - ERR_FAIL_COND_V(on->arguments.size() != 2, false); int slevel = p_stack_level; int src_address_a = _parse_expression(codegen, on->arguments[0], slevel); - if (src_address_a < 0) + if (src_address_a < 0) { return -1; + } - if (src_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) + if (src_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) { slevel++; //uses stack for return, increase stack + } int src_address_b = _parse_expression(codegen, on->arguments[1], slevel); - if (src_address_b < 0) + if (src_address_b < 0) { return -1; + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_EXTENDS_TEST); // perform operator codegen.opcodes.push_back(src_address_a); // argument 1 @@ -1229,11 +1273,13 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: int slevel = p_stack_level; int src_address_a = _parse_expression(codegen, on->arguments[0], slevel); - if (src_address_a < 0) + if (src_address_a < 0) { return -1; + } - if (src_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) + if (src_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) { slevel++; //uses stack for return, increase stack + } const GDScriptParser::TypeNode *tn = static_cast<const GDScriptParser::TypeNode *>(on->arguments[1]); @@ -1242,7 +1288,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back((int)tn->vtype); // argument 2 (unary only takes one parameter) } break; default: { - ERR_FAIL_V_MSG(0, "Bug in bytecode compiler, unexpected operator #" + itos(on->op) + " in parse tree while parsing expression."); //unreachable code } break; @@ -1255,20 +1300,17 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } break; //TYPE_TYPE, default: { - ERR_FAIL_V_MSG(-1, "Bug in bytecode compiler, unexpected node in parse tree while parsing expression."); //unreachable code } break; } } Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level, int p_break_addr, int p_continue_addr) { - codegen.push_stack_identifiers(); int new_identifiers = 0; codegen.current_line = p_block->line; for (int i = 0; i < p_block->statements.size(); i++) { - const GDScriptParser::Node *s = p_block->statements[i]; switch (s->type) { @@ -1286,7 +1328,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo const GDScriptParser::ControlFlowNode *cf = static_cast<const GDScriptParser::ControlFlowNode *>(s); switch (cf->cf_type) { - case GDScriptParser::ControlFlowNode::CF_MATCH: { GDScriptParser::MatchNode *match = cf->match; @@ -1360,10 +1401,10 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo } break; case GDScriptParser::ControlFlowNode::CF_IF: { - int ret2 = _parse_expression(codegen, cf->arguments[0], p_stack_level, false); - if (ret2 < 0) + if (ret2 < 0) { return ERR_PARSE_ERROR; + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT); codegen.opcodes.push_back(ret2); @@ -1371,19 +1412,20 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo codegen.opcodes.push_back(0); //temporary Error err = _parse_block(codegen, cf->body, p_stack_level, p_break_addr, p_continue_addr); - if (err) + if (err) { return err; + } if (cf->body_else) { - codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP); int end_addr = codegen.opcodes.size(); codegen.opcodes.push_back(0); codegen.opcodes.write[else_addr] = codegen.opcodes.size(); Error err2 = _parse_block(codegen, cf->body_else, p_stack_level, p_break_addr, p_continue_addr); - if (err2) + if (err2) { return err2; + } codegen.opcodes.write[end_addr] = codegen.opcodes.size(); } else { @@ -1393,7 +1435,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo } break; case GDScriptParser::ControlFlowNode::CF_FOR: { - int slevel = p_stack_level; int iter_stack_pos = slevel; int iterator_pos = (slevel++) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); @@ -1405,8 +1446,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo codegen.add_stack_identifier(static_cast<const GDScriptParser::IdentifierNode *>(cf->arguments[0])->name, iter_stack_pos); int ret2 = _parse_expression(codegen, cf->arguments[1], slevel, false); - if (ret2 < 0) + if (ret2 < 0) { return ERR_COMPILATION_FAILED; + } //assign container codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN); @@ -1434,8 +1476,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo codegen.opcodes.push_back(iterator_pos); Error err = _parse_block(codegen, cf->body, slevel, break_pos, continue_pos); - if (err) + if (err) { return err; + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP); codegen.opcodes.push_back(continue_pos); @@ -1445,7 +1488,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo } break; case GDScriptParser::ControlFlowNode::CF_WHILE: { - codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP); codegen.opcodes.push_back(codegen.opcodes.size() + 3); int break_addr = codegen.opcodes.size(); @@ -1454,14 +1496,16 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo int continue_addr = codegen.opcodes.size(); int ret2 = _parse_expression(codegen, cf->arguments[0], p_stack_level, false); - if (ret2 < 0) + if (ret2 < 0) { return ERR_PARSE_ERROR; + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT); codegen.opcodes.push_back(ret2); codegen.opcodes.push_back(break_addr); Error err = _parse_block(codegen, cf->body, p_stack_level, break_addr, continue_addr); - if (err) + if (err) { return err; + } codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP); codegen.opcodes.push_back(continue_addr); @@ -1469,9 +1513,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo } break; case GDScriptParser::ControlFlowNode::CF_BREAK: { - if (p_break_addr < 0) { - _set_error("'break'' not within loop", cf); return ERR_COMPILATION_FAILED; } @@ -1480,9 +1522,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo } break; case GDScriptParser::ControlFlowNode::CF_CONTINUE: { - if (p_continue_addr < 0) { - _set_error("'continue' not within loop", cf); return ERR_COMPILATION_FAILED; } @@ -1492,17 +1532,15 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo } break; case GDScriptParser::ControlFlowNode::CF_RETURN: { - int ret2; if (cf->arguments.size()) { - ret2 = _parse_expression(codegen, cf->arguments[0], p_stack_level, false); - if (ret2 < 0) + if (ret2 < 0) { return ERR_PARSE_ERROR; + } } else { - ret2 = GDScriptFunction::ADDR_TYPE_NIL << GDScriptFunction::ADDR_BITS; } @@ -1519,14 +1557,16 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo const GDScriptParser::AssertNode *as = static_cast<const GDScriptParser::AssertNode *>(s); int ret2 = _parse_expression(codegen, as->condition, p_stack_level, false); - if (ret2 < 0) + if (ret2 < 0) { return ERR_PARSE_ERROR; + } int message_ret = 0; if (as->message) { message_ret = _parse_expression(codegen, as->message, p_stack_level + 1, false); - if (message_ret < 0) + if (message_ret < 0) { return ERR_PARSE_ERROR; + } } codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSERT); @@ -1541,7 +1581,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo #endif } break; case GDScriptParser::Node::TYPE_LOCAL_VAR: { - const GDScriptParser::LocalVarNode *lv = static_cast<const GDScriptParser::LocalVarNode *>(s); // since we are using properties now for most class access, allow shadowing of class members to make user's life easier. @@ -1559,8 +1598,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo default: { //expression int ret2 = _parse_expression(codegen, s, p_stack_level, true); - if (ret2 < 0) + if (ret2 < 0) { return ERR_PARSE_ERROR; + } } break; } } @@ -1569,7 +1609,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo } Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready) { - Vector<int> bytecode; CodeGen codegen; @@ -1610,7 +1649,6 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser if (is_initializer || (p_func && String(p_func->name) == "_init")) { //parse initializer for class members if (!p_func && p_class->extends_used && p_script->native.is_null()) { - //call implicit parent constructor codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL_SELF_BASE); codegen.opcodes.push_back(codegen.get_name_map_pos("_init")); @@ -1618,8 +1656,9 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser codegen.opcodes.push_back((GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) | 0); } Error err = _parse_block(codegen, p_class->initializer, stack_level); - if (err) + if (err) { return err; + } is_initializer = true; } @@ -1627,8 +1666,9 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser //parse initializer for class members if (p_class->ready->statements.size()) { Error err = _parse_block(codegen, p_class->ready, stack_level); - if (err) + if (err) { return err; + } } } @@ -1638,13 +1678,10 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser StringName func_name; if (p_func) { - if (p_func->default_values.size()) { - codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_TO_DEF_ARGUMENT); defarg_addr.push_back(codegen.opcodes.size()); for (int i = 0; i < p_func->default_values.size(); i++) { - _parse_expression(codegen, p_func->default_values[i], stack_level, true); defarg_addr.push_back(codegen.opcodes.size()); } @@ -1653,15 +1690,17 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser } Error err = _parse_block(codegen, p_func->body, stack_level); - if (err) + if (err) { return err; + } func_name = p_func->name; } else { - if (p_for_ready) + if (p_for_ready) { func_name = "_ready"; - else + } else { func_name = "_init"; + } } codegen.opcodes.push_back(GDScriptFunction::OPCODE_END); @@ -1706,17 +1745,14 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser gdfunc->constants.write[idx] = *K; } } else { - gdfunc->_constants_ptr = nullptr; gdfunc->_constant_count = 0; } //global names if (codegen.name_map.size()) { - gdfunc->global_names.resize(codegen.name_map.size()); gdfunc->_global_names_ptr = &gdfunc->global_names[0]; for (Map<StringName, int>::Element *E = codegen.name_map.front(); E; E = E->next()) { - gdfunc->global_names.write[E->get()] = E->key(); } gdfunc->_global_names_count = gdfunc->global_names.size(); @@ -1739,19 +1775,16 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser #endif if (codegen.opcodes.size()) { - gdfunc->code = codegen.opcodes; gdfunc->_code_ptr = &gdfunc->code[0]; gdfunc->_code_size = codegen.opcodes.size(); } else { - gdfunc->_code_ptr = nullptr; gdfunc->_code_size = 0; } if (defarg_addr.size()) { - gdfunc->default_arguments = defarg_addr; gdfunc->_default_arg_count = defarg_addr.size() - 1; gdfunc->_default_arg_ptr = &gdfunc->default_arguments[0]; @@ -1768,8 +1801,9 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser if (EngineDebugger::is_active()) { String signature; //path - if (p_script->get_path() != String()) + if (p_script->get_path() != String()) { signature += p_script->get_path(); + } //loc if (p_func) { signature += "::" + itos(p_func->body->line); @@ -1809,17 +1843,18 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser gdfunc->_initial_line = 0; } - if (codegen.debug_stack) + if (codegen.debug_stack) { gdfunc->stack_debug = codegen.stack_debug; + } - if (is_initializer) + if (is_initializer) { p_script->initializer = gdfunc; + } return OK; } Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { - parsing_classes.insert(p_script); if (p_class->owner && p_class->owner->owner) { @@ -1890,7 +1925,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar } for (int i = 0; i < p_class->variables.size(); i++) { - StringName name = p_class->variables[i].identifier; GDScript::MemberInfo minfo; @@ -1905,7 +1939,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar PropertyInfo export_info = p_class->variables[i]._export; if (export_info.type != Variant::NIL) { - if (!minfo.data_type.has_type) { prop_info.type = export_info.type; prop_info.class_name = export_info.class_name; @@ -1932,7 +1965,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar } for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_class->constant_expressions.front(); E; E = E->next()) { - StringName name = E->key(); ERR_CONTINUE(E->get().expression->type != GDScriptParser::Node::TYPE_CONSTANT); @@ -1947,13 +1979,11 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar } for (int i = 0; i < p_class->_signals.size(); i++) { - StringName name = p_class->_signals[i].name; GDScript *c = p_script; while (c) { - if (c->_signals.has(name)) { _set_error("Signal '" + name + "' redefined (in current or parent class)", p_class); return ERR_ALREADY_EXISTS; @@ -1989,8 +2019,9 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar // Subclass might still be parsing, just skip it if (!parsed_classes.has(subclass_ptr) && !parsing_classes.has(subclass_ptr)) { Error err = _parse_class_level(subclass_ptr, p_class->subclasses[i], p_keep_state); - if (err) + if (err) { return err; + } } #ifdef TOOLS_ENABLED @@ -2011,37 +2042,41 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa bool has_ready = false; for (int i = 0; i < p_class->functions.size(); i++) { - - if (!has_initializer && p_class->functions[i]->name == "_init") + if (!has_initializer && p_class->functions[i]->name == "_init") { has_initializer = true; - if (!has_ready && p_class->functions[i]->name == "_ready") + } + if (!has_ready && p_class->functions[i]->name == "_ready") { has_ready = true; + } Error err = _parse_function(p_script, p_class, p_class->functions[i]); - if (err) + if (err) { return err; + } } //parse static methods for (int i = 0; i < p_class->static_functions.size(); i++) { - Error err = _parse_function(p_script, p_class, p_class->static_functions[i]); - if (err) + if (err) { return err; + } } if (!has_initializer) { //create a constructor Error err = _parse_function(p_script, p_class, nullptr); - if (err) + if (err) { return err; + } } if (!has_ready && p_class->ready->statements.size()) { //create a constructor Error err = _parse_function(p_script, p_class, nullptr, true); - if (err) + if (err) { return err; + } } #ifdef DEBUG_ENABLED @@ -2050,7 +2085,6 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa if (p_keep_state) { for (Set<Object *>::Element *E = p_script->instances.front(); E;) { - Set<Object *>::Element *N = E->next(); ScriptInstance *si = E->get()->get_script_instance(); @@ -2085,7 +2119,6 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa } #endif } else { - GDScriptInstance *gi = static_cast<GDScriptInstance *>(si); gi->reload_members(); } @@ -2110,7 +2143,6 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa } void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { - Map<StringName, Ref<GDScript>> old_subclasses; if (p_keep_state) { @@ -2145,7 +2177,6 @@ void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::C } Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_script, bool p_keep_state) { - err_line = -1; err_column = -1; error = ""; @@ -2165,27 +2196,28 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri p_script->_owner = nullptr; Error err = _parse_class_level(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state); - if (err) + if (err) { return err; + } err = _parse_class_blocks(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state); - if (err) + if (err) { return err; + } return OK; } String GDScriptCompiler::get_error() const { - return error; } -int GDScriptCompiler::get_error_line() const { +int GDScriptCompiler::get_error_line() const { return err_line; } -int GDScriptCompiler::get_error_column() const { +int GDScriptCompiler::get_error_column() const { return err_column; } diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index 34b066b5c7..315d4f1842 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -36,13 +36,11 @@ #include "gdscript_parser.h" class GDScriptCompiler { - const GDScriptParser *parser; Set<GDScript *> parsed_classes; Set<GDScript *> parsing_classes; GDScript *main_script; struct CodeGen { - GDScript *script; const GDScriptParser::ClassNode *class_node; const GDScriptParser::FunctionNode *function_node; @@ -71,7 +69,6 @@ class GDScriptCompiler { void push_stack_identifiers() { stack_id_stack.push_back(stack_identifiers); if (debug_stack) { - block_identifier_stack.push_back(block_identifiers); block_identifiers.clear(); } @@ -83,7 +80,6 @@ class GDScriptCompiler { if (debug_stack) { for (Map<StringName, int>::Element *E = block_identifiers.front(); E; E = E->next()) { - GDScriptFunction::StackDebug sd; sd.added = false; sd.identifier = E->key(); @@ -114,8 +110,9 @@ class GDScriptCompiler { } int get_constant_pos(const Variant &p_constant) { - if (constant_map.has(p_constant)) + if (constant_map.has(p_constant)) { return constant_map[p_constant]; + } int pos = constant_map.size(); constant_map[p_constant] = pos; return pos; @@ -123,10 +120,14 @@ class GDScriptCompiler { Vector<int> opcodes; void alloc_stack(int p_level) { - if (p_level >= stack_max) stack_max = p_level + 1; + if (p_level >= stack_max) { + stack_max = p_level + 1; + } } void alloc_call(int p_params) { - if (p_params >= call_max) call_max = p_params; + if (p_params >= call_max) { + call_max = p_params; + } } int current_line; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 2ec3352e70..3a5db3687b 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -41,19 +41,16 @@ #endif void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { - p_delimiters->push_back("#"); } void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { - p_delimiters->push_back("\" \""); p_delimiters->push_back("' '"); p_delimiters->push_back("\"\"\" \"\"\""); } String GDScriptLanguage::_get_processed_template(const String &p_template, const String &p_base_class_name) const { - String processed_template = p_template; #ifdef TOOLS_ENABLED @@ -109,18 +106,15 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str } bool GDScriptLanguage::is_using_templates() { - return true; } void GDScriptLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) { - String _template = _get_processed_template(p_script->get_source_code(), p_base_class_name); p_script->set_source_code(_template); } bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { - GDScriptParser parser; Error err = parser.parse(p_script, p_path.get_base_dir(), true, p_path, false, r_safe_lines); @@ -143,35 +137,29 @@ bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int & r_test_error = parser.get_error(); return false; } else { - const GDScriptParser::Node *root = parser.get_parse_tree(); ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, false); const GDScriptParser::ClassNode *cl = static_cast<const GDScriptParser::ClassNode *>(root); Map<int, String> funcs; for (int i = 0; i < cl->functions.size(); i++) { - funcs[cl->functions[i]->line] = cl->functions[i]->name; } for (int i = 0; i < cl->static_functions.size(); i++) { - funcs[cl->static_functions[i]->line] = cl->static_functions[i]->name; } for (int i = 0; i < cl->subclasses.size(); i++) { for (int j = 0; j < cl->subclasses[i]->functions.size(); j++) { - funcs[cl->subclasses[i]->functions[j]->line] = String(cl->subclasses[i]->name) + "." + cl->subclasses[i]->functions[j]->name; } for (int j = 0; j < cl->subclasses[i]->static_functions.size(); j++) { - funcs[cl->subclasses[i]->static_functions[j]->line] = String(cl->subclasses[i]->name) + "." + cl->subclasses[i]->static_functions[j]->name; } } for (Map<int, String>::Element *E = funcs.front(); E; E = E->next()) { - r_functions->push_back(E->get() + ":" + itos(E->key())); } } @@ -180,27 +168,22 @@ bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int & } bool GDScriptLanguage::has_named_classes() const { - return false; } bool GDScriptLanguage::supports_builtin_mode() const { - return true; } int GDScriptLanguage::find_function(const String &p_function, const String &p_code) const { - GDScriptTokenizerText tokenizer; tokenizer.set_code(p_code); int indent = 0; while (tokenizer.get_token() != GDScriptTokenizer::TK_EOF && tokenizer.get_token() != GDScriptTokenizer::TK_ERROR) { - if (tokenizer.get_token() == GDScriptTokenizer::TK_NEWLINE) { indent = tokenizer.get_token_line_indent(); } if (indent == 0 && tokenizer.get_token() == GDScriptTokenizer::TK_PR_FUNCTION && tokenizer.get_token(1) == GDScriptTokenizer::TK_IDENTIFIER) { - String identifier = tokenizer.get_token_identifier(1); if (identifier == p_function) { return tokenizer.get_token_line(); @@ -212,7 +195,6 @@ int GDScriptLanguage::find_function(const String &p_function, const String &p_co } Script *GDScriptLanguage::create_script() const { - return memnew(GDScript); } @@ -222,7 +204,6 @@ bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const //break because of parse error if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) { - _debug_parse_err_line = p_line; _debug_parse_err_file = p_file; _debug_error = p_error; @@ -234,9 +215,7 @@ bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const } bool GDScriptLanguage::debug_break(const String &p_error, bool p_allow_continue) { - if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) { - _debug_parse_err_line = -1; _debug_parse_err_file = ""; _debug_error = p_error; @@ -249,21 +228,21 @@ bool GDScriptLanguage::debug_break(const String &p_error, bool p_allow_continue) } String GDScriptLanguage::debug_get_error() const { - return _debug_error; } int GDScriptLanguage::debug_get_stack_level_count() const { - - if (_debug_parse_err_line >= 0) + if (_debug_parse_err_line >= 0) { return 1; + } return _debug_call_stack_pos; } -int GDScriptLanguage::debug_get_stack_level_line(int p_level) const { - if (_debug_parse_err_line >= 0) +int GDScriptLanguage::debug_get_stack_level_line(int p_level) const { + if (_debug_parse_err_line >= 0) { return _debug_parse_err_line; + } ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, -1); @@ -271,28 +250,31 @@ int GDScriptLanguage::debug_get_stack_level_line(int p_level) const { return *(_call_stack[l].line); } -String GDScriptLanguage::debug_get_stack_level_function(int p_level) const { - if (_debug_parse_err_line >= 0) +String GDScriptLanguage::debug_get_stack_level_function(int p_level) const { + if (_debug_parse_err_line >= 0) { return ""; + } ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, ""); int l = _debug_call_stack_pos - p_level - 1; return _call_stack[l].function->get_name(); } -String GDScriptLanguage::debug_get_stack_level_source(int p_level) const { - if (_debug_parse_err_line >= 0) +String GDScriptLanguage::debug_get_stack_level_source(int p_level) const { + if (_debug_parse_err_line >= 0) { return _debug_parse_err_file; + } ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, ""); int l = _debug_call_stack_pos - p_level - 1; return _call_stack[l].function->get_source(); } -void GDScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { - if (_debug_parse_err_line >= 0) +void GDScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { + if (_debug_parse_err_line >= 0) { return; + } ERR_FAIL_INDEX(p_level, _debug_call_stack_pos); int l = _debug_call_stack_pos - p_level - 1; @@ -303,23 +285,24 @@ void GDScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p f->debug_get_stack_member_state(*_call_stack[l].line, &locals); for (List<Pair<StringName, int>>::Element *E = locals.front(); E; E = E->next()) { - p_locals->push_back(E->get().first); p_values->push_back(_call_stack[l].stack[E->get().second]); } } -void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { - if (_debug_parse_err_line >= 0) +void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { + if (_debug_parse_err_line >= 0) { return; + } ERR_FAIL_INDEX(p_level, _debug_call_stack_pos); int l = _debug_call_stack_pos - p_level - 1; GDScriptInstance *instance = _call_stack[l].instance; - if (!instance) + if (!instance) { return; + } Ref<GDScript> script = instance->get_script(); ERR_FAIL_COND(script.is_null()); @@ -327,16 +310,15 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> * const Map<StringName, GDScript::MemberInfo> &mi = script->debug_get_member_indices(); for (const Map<StringName, GDScript::MemberInfo>::Element *E = mi.front(); E; E = E->next()) { - p_members->push_back(E->key()); p_values->push_back(instance->debug_get_member_by_index(E->get().index)); } } ScriptInstance *GDScriptLanguage::debug_get_stack_level_instance(int p_level) { - - if (_debug_parse_err_line >= 0) + if (_debug_parse_err_line >= 0) { return nullptr; + } ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, nullptr); @@ -347,7 +329,6 @@ ScriptInstance *GDScriptLanguage::debug_get_stack_level_instance(int p_level) { } void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { - const Map<StringName, int> &name_idx = GDScriptLanguage::get_singleton()->get_global_map(); const Variant *globals = GDScriptLanguage::get_singleton()->get_global_array(); @@ -355,9 +336,9 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> get_public_constants(&cinfo); for (const Map<StringName, int>::Element *E = name_idx.front(); E; E = E->next()) { - - if (ClassDB::class_exists(E->key()) || Engine::get_singleton()->has_singleton(E->key())) + if (ClassDB::class_exists(E->key()) || Engine::get_singleton()->has_singleton(E->key())) { continue; + } bool is_script_constant = false; for (List<Pair<String, Variant>>::Element *CE = cinfo.front(); CE; CE = CE->next()) { @@ -366,13 +347,15 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> break; } } - if (is_script_constant) + if (is_script_constant) { continue; + } const Variant &var = globals[E->value()]; if (Object *obj = var) { - if (Object::cast_to<GDScriptNativeClass>(obj)) + if (Object::cast_to<GDScriptNativeClass>(obj)) { continue; + } } bool skip = false; @@ -382,8 +365,9 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> break; } } - if (skip) + if (skip) { continue; + } p_globals->push_back(E->key()); p_values->push_back(var); @@ -391,19 +375,15 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> } String GDScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { - return ""; } void GDScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("gd"); } void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const { - for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) { - p_functions->push_back(GDScriptFunctions::get_info(GDScriptFunctions::Function(i))); } @@ -437,7 +417,6 @@ void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const } void GDScriptLanguage::get_public_constants(List<Pair<String, Variant>> *p_constants) const { - Pair<String, Variant> pi; pi.first = "PI"; pi.second = Math_PI; @@ -460,7 +439,6 @@ void GDScriptLanguage::get_public_constants(List<Pair<String, Variant>> *p_const } String GDScriptLanguage::make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const { - #ifdef TOOLS_ENABLED bool th = EditorSettings::get_singleton()->get_setting("text_editor/completion/add_type_hints"); #else @@ -470,8 +448,9 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na String s = "func " + p_name + "("; if (p_args.size()) { for (int i = 0; i < p_args.size(); i++) { - if (i > 0) + if (i > 0) { s += ", "; + } s += p_args[i].get_slice(":", 0); if (th) { String type = p_args[i].get_slice(":", 1); @@ -491,36 +470,27 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na #if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) struct GDScriptCompletionContext { - - const GDScriptParser::ClassNode *_class; - const GDScriptParser::FunctionNode *function; - const GDScriptParser::BlockNode *block; - Object *base; + const GDScriptParser::ClassNode *_class = nullptr; + const GDScriptParser::FunctionNode *function = nullptr; + const GDScriptParser::BlockNode *block = nullptr; + Object *base = nullptr; String base_path; - int line; - uint32_t depth; - - GDScriptCompletionContext() : - _class(nullptr), - function(nullptr), - block(nullptr), - base(nullptr), - line(0), - depth(0) {} + int line = 0; + uint32_t depth = 0; + + GDScriptCompletionContext() {} }; struct GDScriptCompletionIdentifier { GDScriptParser::DataType type; String enumeration; Variant value; - const GDScriptParser::Node *assigned_expression; + const GDScriptParser::Node *assigned_expression = nullptr; - GDScriptCompletionIdentifier() : - assigned_expression(nullptr) {} + GDScriptCompletionIdentifier() {} }; static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String, ScriptCodeCompletionOption> &r_list) { - const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; for (int i = 0; i < p_dir->get_file_count(); i++) { @@ -535,7 +505,6 @@ static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String } static String _get_visual_datatype(const PropertyInfo &p_info, bool p_isarg = true) { - if (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { String enum_name = p_info.class_name; if (enum_name.find(".") == -1) { @@ -835,7 +804,6 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G Object *baseptr = base.value; if (all_is_const && String(id) == "get_node" && ClassDB::is_parent_class(native_type.native_type, "Node") && args.size()) { - String arg1 = args[0]; if (arg1.begins_with("/root/")) { String which = arg1.get_slice("/", 2); @@ -849,7 +817,6 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G ProjectSettings::get_singleton()->get_property_list(&props); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String s = E->get().name; if (!s.begins_with("autoload/")) { continue; @@ -1082,16 +1049,36 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G Variant::Operator vop = Variant::OP_MAX; switch (op->op) { - case GDScriptParser::OperatorNode::OP_ADD: vop = Variant::OP_ADD; break; - case GDScriptParser::OperatorNode::OP_SUB: vop = Variant::OP_SUBTRACT; break; - case GDScriptParser::OperatorNode::OP_MUL: vop = Variant::OP_MULTIPLY; break; - case GDScriptParser::OperatorNode::OP_DIV: vop = Variant::OP_DIVIDE; break; - case GDScriptParser::OperatorNode::OP_MOD: vop = Variant::OP_MODULE; break; - case GDScriptParser::OperatorNode::OP_SHIFT_LEFT: vop = Variant::OP_SHIFT_LEFT; break; - case GDScriptParser::OperatorNode::OP_SHIFT_RIGHT: vop = Variant::OP_SHIFT_RIGHT; break; - case GDScriptParser::OperatorNode::OP_BIT_AND: vop = Variant::OP_BIT_AND; break; - case GDScriptParser::OperatorNode::OP_BIT_OR: vop = Variant::OP_BIT_OR; break; - case GDScriptParser::OperatorNode::OP_BIT_XOR: vop = Variant::OP_BIT_XOR; break; + case GDScriptParser::OperatorNode::OP_ADD: + vop = Variant::OP_ADD; + break; + case GDScriptParser::OperatorNode::OP_SUB: + vop = Variant::OP_SUBTRACT; + break; + case GDScriptParser::OperatorNode::OP_MUL: + vop = Variant::OP_MULTIPLY; + break; + case GDScriptParser::OperatorNode::OP_DIV: + vop = Variant::OP_DIVIDE; + break; + case GDScriptParser::OperatorNode::OP_MOD: + vop = Variant::OP_MODULE; + break; + case GDScriptParser::OperatorNode::OP_SHIFT_LEFT: + vop = Variant::OP_SHIFT_LEFT; + break; + case GDScriptParser::OperatorNode::OP_SHIFT_RIGHT: + vop = Variant::OP_SHIFT_RIGHT; + break; + case GDScriptParser::OperatorNode::OP_BIT_AND: + vop = Variant::OP_BIT_AND; + break; + case GDScriptParser::OperatorNode::OP_BIT_OR: + vop = Variant::OP_BIT_OR; + break; + case GDScriptParser::OperatorNode::OP_BIT_XOR: + vop = Variant::OP_BIT_XOR; + break; default: { } } @@ -1171,7 +1158,6 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G } static bool _guess_identifier_type(GDScriptCompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { - // Look in blocks first const GDScriptParser::BlockNode *blk = p_context.block; int last_assign_line = -1; @@ -1427,6 +1413,7 @@ static bool _guess_identifier_type_from_base(GDScriptCompletionContext &p_contex // Variable used in the same expression return false; } + if (_guess_expression_type(p_context, m.expression, r_type)) { return true; } @@ -1732,7 +1719,6 @@ static bool _guess_method_return_type_from_base(GDScriptCompletionContext &p_con } static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx) { - String arghint = _get_visual_datatype(p_info.return_val, false) + " " + p_info.name + "("; int def_args = p_info.arguments.size() - p_info.default_arguments.size(); @@ -1777,7 +1763,6 @@ static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx) { } static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_function, int p_arg_idx) { - String arghint = p_function->return_type.to_string() + " " + p_function->name.operator String() + "("; int def_args = p_function->arguments.size() - p_function->default_values.size(); @@ -1819,7 +1804,6 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio } static void _find_enumeration_candidates(const String p_enum_hint, Map<String, ScriptCodeCompletionOption> &r_result) { - if (p_enum_hint.find(".") == -1) { // Global constant StringName current_enum = p_enum_hint; @@ -2057,7 +2041,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context List<PropertyInfo> pinfo; ClassDB::get_property_list(type, &pinfo); for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (E->get().usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) { + if (E->get().usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SUBGROUP | PROPERTY_USAGE_CATEGORY)) { continue; } if (E->get().name.find("/") != -1) { @@ -2098,7 +2082,11 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context if (!p_only_functions) { List<PropertyInfo> members; - p_base.value.get_property_list(&members); + if (p_base.value.get_type() != Variant::NIL) { + p_base.value.get_property_list(&members); + } else { + tmp.get_property_list(&members); + } for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { if (String(E->get().name).find("/") == -1) { @@ -2130,11 +2118,9 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context } static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) { - const GDScriptParser::BlockNode *block = p_context.block; if (p_context.function) { - const GDScriptParser::FunctionNode *f = p_context.function; for (int i = 0; i < f->arguments.size(); i++) { @@ -2150,7 +2136,7 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p } const GDScriptParser::ClassNode *clss = p_context._class; - bool _static = !p_context.function || p_context.function->_static; + bool _static = p_context.function && p_context.function->_static; while (clss) { GDScriptCompletionContext c = p_context; @@ -2403,7 +2389,6 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con } static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_node, int p_argidx, Map<String, ScriptCodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) { - const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; if (!p_node || p_node->type != GDScriptParser::Node::TYPE_OPERATOR) { @@ -2459,7 +2444,6 @@ static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDS } return; } else if (op->arguments[0]->type == GDScriptParser::Node::TYPE_SELF) { - if (op->arguments.size() < 2 || op->arguments[1]->type != GDScriptParser::Node::TYPE_IDENTIFIER) { return; } @@ -2533,7 +2517,6 @@ static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDS } Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) { - const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; GDScriptParser parser; @@ -2581,7 +2564,6 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path p_owner->get_argument_options("get_node", 0, &opts); for (List<String>::Element *E = opts.front(); E; E = E->next()) { - String opt = E->get().strip_edges(); if (opt.is_quoted()) { r_forced = true; @@ -2689,7 +2671,6 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path List<MethodInfo> virtual_methods; ClassDB::get_virtual_methods(class_name, &virtual_methods); for (List<MethodInfo>::Element *E = virtual_methods.front(); E; E = E->next()) { - MethodInfo &mi = E->get(); String method_hint = mi.name; if (method_hint.find(":") != -1) { @@ -3013,19 +2994,16 @@ String GDScriptLanguage::_get_indentation() const { } void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const { - String indent = _get_indentation(); Vector<String> lines = p_code.split("\n"); List<int> indent_stack; for (int i = 0; i < lines.size(); i++) { - String l = lines[i]; int tc = 0; for (int j = 0; j < l.length(); j++) { if (l[j] == ' ' || l[j] == '\t') { - tc++; } else { break; @@ -3033,8 +3011,9 @@ void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_t } String st = l.substr(tc, l.length()).strip_edges(); - if (st == "" || st.begins_with("#")) + if (st == "" || st.begins_with("#")) { continue; //ignore! + } int ilevel = 0; if (indent_stack.size()) { @@ -3048,12 +3027,12 @@ void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_t indent_stack.pop_back(); } - if (indent_stack.size() && indent_stack.back()->get() != tc) + if (indent_stack.size() && indent_stack.back()->get() != tc) { indent_stack.push_back(tc); //this is not right but gets the job done + } } if (i >= p_from_line) { - l = ""; for (int j = 0; j < indent_stack.size(); j++) { l += indent; @@ -3069,8 +3048,9 @@ void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_t p_code = ""; for (int i = 0; i < lines.size(); i++) { - if (i > 0) + if (i > 0) { p_code += "\n"; + } p_code += lines[i]; } } @@ -3113,6 +3093,14 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co return OK; } } + + for (int i = 0; i < base_type.class_type->subclasses.size(); i++) { + if (base_type.class_type->subclasses[i]->name == p_symbol) { + r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location = base_type.class_type->subclasses[i]->line; + return OK; + } + } } base_type = base_type.class_type->base_type; } @@ -3257,7 +3245,6 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) { - //before parsing, try the usual stuff if (ClassDB::class_exists(p_symbol)) { r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS; @@ -3338,7 +3325,6 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol [[fallthrough]]; } case GDScriptParser::COMPLETION_IDENTIFIER: { - if (!is_function) { is_function = parser.get_completion_identifier_is_function(); } @@ -3390,13 +3376,12 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol ProjectSettings::get_singleton()->get_property_list(&props); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String s = E->get().name; - if (!s.begins_with("autoload/")) + if (!s.begins_with("autoload/")) { continue; + } String name = s.get_slice("/", 1); if (name == String(p_symbol)) { - String path = ProjectSettings::get_singleton()->get(s); if (path.begins_with("*")) { String script = path.substr(1, path.length()); @@ -3408,7 +3393,6 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol } if (FileAccess::exists(script)) { - r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; r_result.location = 0; r_result.script = ResourceLoader::load(script); @@ -3490,6 +3474,16 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol return OK; } } break; + case GDScriptParser::COMPLETION_TYPE_HINT: { + GDScriptParser::DataType base_type = context._class->base_type; + base_type.has_type = true; + base_type.kind = GDScriptParser::DataType::CLASS; + base_type.class_type = const_cast<GDScriptParser::ClassNode *>(context._class); + + if (_lookup_symbol_from_base(base_type, p_symbol, false, r_result) == OK) { + return OK; + } + } break; default: { } } diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index ca4d6f6de9..1aab71d161 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -35,12 +35,10 @@ #include "gdscript_functions.h" Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const { - int address = p_address & ADDR_MASK; //sequential table (jump table generated by compiler) switch ((p_address & ADDR_TYPE_MASK) >> ADDR_BITS) { - case ADDR_TYPE_SELF: { #ifdef DEBUG_ENABLED if (unlikely(!p_instance)) { @@ -51,7 +49,6 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta return &self; } break; case ADDR_TYPE_CLASS: { - return &static_ref; } break; case ADDR_TYPE_MEMBER: { @@ -65,7 +62,6 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta return &p_instance->members.write[address]; } break; case ADDR_TYPE_CLASS_CONSTANT: { - //todo change to index! GDScript *s = p_script; #ifdef DEBUG_ENABLED @@ -76,7 +72,6 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta while (s) { GDScript *o = s; while (o) { - Map<StringName, Variant>::Element *E = o->constants.find(*sn); if (E) { return &E->get(); @@ -133,7 +128,6 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta #ifdef DEBUG_ENABLED static String _get_var_type(const Variant *p_var) { - String basestr; if (p_var->get_type() == Variant::OBJECT) { @@ -146,10 +140,11 @@ static String _get_var_type(const Variant *p_var) { basestr = "previously freed"; } } else { - if (bobj->get_script_instance()) + if (bobj->get_script_instance()) { basestr = bobj->get_class() + " (" + bobj->get_script_instance()->get_script()->get_path().get_file() + ")"; - else + } else { basestr = bobj->get_class(); + } } } else { @@ -161,7 +156,6 @@ static String _get_var_type(const Variant *p_var) { #endif // DEBUG_ENABLED String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const { - String err_text; if (p_err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) { @@ -259,11 +253,9 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const #endif Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state) { - OPCODES_TABLE; if (!_code_ptr) { - return Variant(); } @@ -294,29 +286,23 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a line = p_state->line; ip = p_state->ip; alloca_size = p_state->stack.size(); - script = p_state->script.ptr(); + script = p_state->script; p_instance = p_state->instance; defarg = p_state->defarg; self = p_state->self; - //stack[p_state->result_pos]=p_state->result; //assign stack with result } else { - if (p_argcount != _argument_count) { - if (p_argcount > _argument_count) { - r_err.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_err.argument = _argument_count; return Variant(); } else if (p_argcount < _argument_count - _default_arg_count) { - r_err.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_err.argument = _argument_count - _default_arg_count; return Variant(); } else { - defarg = _argument_count - p_argcount; } } @@ -324,11 +310,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a alloca_size = sizeof(Variant *) * _call_size + sizeof(Variant) * _stack_size; if (alloca_size) { - uint8_t *aptr = (uint8_t *)alloca(alloca_size); if (_stack_size) { - stack = (Variant *)aptr; for (int i = 0; i < p_argcount; i++) { if (!argument_types[i].has_type) { @@ -337,15 +321,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } if (!argument_types[i].is_type(*p_args[i], true)) { - if (argument_types[i].is_type(Variant(), true)) { - memnew_placement(&stack[i], Variant); - continue; - } else { - r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_err.argument = i; - r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT; - return Variant(); - } + r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_err.argument = i; + r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT; + return Variant(); } if (argument_types[i].kind == GDScriptDataType::BUILTIN) { Variant arg = Variant::construct(argument_types[i].builtin_type, &p_args[i], 1, r_err); @@ -362,10 +341,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } if (_call_size) { - call_args = (Variant **)&aptr[sizeof(Variant) * _stack_size]; } else { - call_args = nullptr; } @@ -376,7 +353,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a if (p_instance) { if (p_instance->base_ref && static_cast<Reference *>(p_instance->owner)->is_referenced()) { - self = REF(static_cast<Reference *>(p_instance->owner)); } else { self = p_instance->owner; @@ -387,12 +363,15 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } } + static_ref = script; + String err_text; #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active()) + if (EngineDebugger::is_active()) { GDScriptLanguage::get_singleton()->enter_function(p_instance, this, stack, &ip, &line); + } #define GD_ERR_BREAK(m_cond) \ { \ @@ -443,9 +422,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #endif OPCODE_SWITCH(_code_ptr[ip]) { - OPCODE(OPCODE_OPERATOR) { - CHECK_SPACE(5); bool valid; @@ -465,7 +442,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #endif #ifdef DEBUG_ENABLED if (!valid) { - if (ret.get_type() == Variant::STRING) { //return a string when invalid with the error err_text = ret; @@ -482,7 +458,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_EXTENDS_TEST) { - CHECK_SPACE(4); GET_VARIANT_PTR(a, 1); @@ -491,7 +466,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED if (b->get_type() != Variant::OBJECT || b->operator Object *() == nullptr) { - err_text = "Right operand of 'is' is not a class."; OPCODE_BREAK; } @@ -499,7 +473,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a bool extends_ok = false; if (a->get_type() == Variant::OBJECT && a->operator Object *() != nullptr) { - #ifdef DEBUG_ENABLED bool was_freed; Object *obj_A = a->get_validated_object_with_check(was_freed); @@ -528,11 +501,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a //in other situation, this shoul return false. if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language() == GDScriptLanguage::get_singleton()) { - GDScript *cmp = static_cast<GDScript *>(obj_A->get_script_instance()->get_script().ptr()); //bool found=false; while (cmp) { - if (cmp == scr_B) { //inherits from script, all ok extends_ok = true; @@ -544,12 +515,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } } else { - GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(obj_B); #ifdef DEBUG_ENABLED if (!nc) { - err_text = "Right operand of 'is' is not a class (type: '" + obj_B->get_class() + "')."; OPCODE_BREAK; } @@ -564,7 +533,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_IS_BUILTIN) { - CHECK_SPACE(4); GET_VARIANT_PTR(value, 1); @@ -579,7 +547,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_SET) { - CHECK_SPACE(3); GET_VARIANT_PTR(dst, 1); @@ -606,7 +573,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_GET) { - CHECK_SPACE(3); GET_VARIANT_PTR(src, 1); @@ -639,7 +605,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_SET_NAMED) { - CHECK_SPACE(3); GET_VARIANT_PTR(dst, 1); @@ -665,7 +630,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_GET_NAMED) { - CHECK_SPACE(4); GET_VARIANT_PTR(src, 1); @@ -700,7 +664,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_SET_MEMBER) { - CHECK_SPACE(3); int indexname = _code_ptr[ip + 1]; GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count); @@ -725,7 +688,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_GET_MEMBER) { - CHECK_SPACE(3); int indexname = _code_ptr[ip + 1]; GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count); @@ -746,7 +708,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_ASSIGN) { - CHECK_SPACE(3); GET_VARIANT_PTR(dst, 1); GET_VARIANT_PTR(src, 2); @@ -758,7 +719,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_ASSIGN_TRUE) { - CHECK_SPACE(2); GET_VARIANT_PTR(dst, 1); @@ -769,7 +729,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_ASSIGN_FALSE) { - CHECK_SPACE(2); GET_VARIANT_PTR(dst, 1); @@ -780,7 +739,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_ASSIGN_TYPED_BUILTIN) { - CHECK_SPACE(4); GET_VARIANT_PTR(dst, 2); GET_VARIANT_PTR(src, 3); @@ -810,7 +768,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_ASSIGN_TYPED_NATIVE) { - CHECK_SPACE(4); GET_VARIANT_PTR(dst, 2); GET_VARIANT_PTR(src, 3); @@ -839,7 +796,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_ASSIGN_TYPED_SCRIPT) { - CHECK_SPACE(4); GET_VARIANT_PTR(dst, 2); GET_VARIANT_PTR(src, 3); @@ -856,7 +812,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } if (src->get_type() != Variant::NIL && src->operator Object *() != nullptr) { - ScriptInstance *scr_inst = src->operator Object *()->get_script_instance(); if (!scr_inst) { err_text = "Trying to assign value of type '" + src->operator Object *()->get_class_name() + @@ -890,7 +845,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_CAST_TO_BUILTIN) { - CHECK_SPACE(4); Variant::Type to_type = (Variant::Type)_code_ptr[ip + 1]; GET_VARIANT_PTR(src, 2); @@ -913,7 +867,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_CAST_TO_NATIVE) { - CHECK_SPACE(4); GET_VARIANT_PTR(to_type, 1); GET_VARIANT_PTR(src, 2); @@ -941,7 +894,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_CAST_TO_SCRIPT) { - CHECK_SPACE(4); GET_VARIANT_PTR(to_type, 1); GET_VARIANT_PTR(src, 2); @@ -961,11 +913,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a bool valid = false; if (src->get_type() != Variant::NIL && src->operator Object *() != nullptr) { - ScriptInstance *scr_inst = src->operator Object *()->get_script_instance(); if (scr_inst) { - Script *src_type = src->operator Object *()->get_script_instance()->get_script().ptr(); while (src_type) { @@ -989,7 +939,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_CONSTRUCT) { - CHECK_SPACE(2); Variant::Type t = Variant::Type(_code_ptr[ip + 1]); int argc = _code_ptr[ip + 2]; @@ -1006,7 +955,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED if (err.error != Callable::CallError::CALL_OK) { - err_text = _get_call_error(err, "'" + Variant::get_type_name(t) + "' constructor", (const Variant **)argptrs); OPCODE_BREAK; } @@ -1018,7 +966,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_CONSTRUCT_ARRAY) { - CHECK_SPACE(1); int argc = _code_ptr[ip + 1]; Array array; //arrays are always shared @@ -1039,7 +986,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_CONSTRUCT_DICTIONARY) { - CHECK_SPACE(1); int argc = _code_ptr[ip + 1]; Dictionary dict; //arrays are always shared @@ -1047,7 +993,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a CHECK_SPACE(argc * 2 + 2); for (int i = 0; i < argc; i++) { - GET_VARIANT_PTR(k, 2 + i * 2 + 0); GET_VARIANT_PTR(v, 2 + i * 2 + 1); dict[*k] = *v; @@ -1063,7 +1008,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_CALL_RETURN) OPCODE(OPCODE_CALL) { - CHECK_SPACE(4); bool call_ret = _code_ptr[ip] == OPCODE_CALL_RETURN; @@ -1094,11 +1038,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #endif Callable::CallError err; if (call_ret) { - GET_VARIANT_PTR(ret, argc); base->call_ptr(*methodname, (const Variant **)argptrs, argc, ret, err); } else { - base->call_ptr(*methodname, (const Variant **)argptrs, argc, nullptr, err); } #ifdef DEBUG_ENABLED @@ -1107,7 +1049,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } if (err.error != Callable::CallError::CALL_OK) { - String methodstr = *methodname; String basestr = _get_var_type(base); @@ -1119,14 +1060,11 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } } } else if (methodstr == "free") { - if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) { - if (base->is_ref()) { err_text = "Attempted to free a reference."; OPCODE_BREAK; } else if (base->get_type() == Variant::OBJECT) { - err_text = "Attempted to free a locked object (calling or emitting)."; OPCODE_BREAK; } @@ -1143,7 +1081,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_CALL_BUILT_IN) { - CHECK_SPACE(4); GDScriptFunctions::Function func = GDScriptFunctions::Function(_code_ptr[ip + 1]); @@ -1167,7 +1104,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED if (err.error != Callable::CallError::CALL_OK) { - String methodstr = GDScriptFunctions::get_func_name(func); if (dst->get_type() == Variant::STRING) { //call provided error string @@ -1183,18 +1119,15 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_CALL_SELF) { - OPCODE_BREAK; } OPCODE(OPCODE_CALL_SELF_BASE) { - CHECK_SPACE(2); int self_fun = _code_ptr[ip + 1]; #ifdef DEBUG_ENABLED if (self_fun < 0 || self_fun >= _global_names_count) { - err_text = "compiler bug, function name not found"; OPCODE_BREAK; } @@ -1220,19 +1153,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a while (gds->base.ptr()) { gds = gds->base.ptr(); E = gds->member_functions.find(*methodname); - if (E) + if (E) { break; + } } Callable::CallError err; if (E) { - *dst = E->get()->call(p_instance, (const Variant **)argptrs, argc, err); } else if (gds->native.ptr()) { - if (*methodname != GDScriptLanguage::get_singleton()->strings._init) { - MethodBind *mb = ClassDB::get_method(gds->native->get_name(), *methodname); if (!mb) { err.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; @@ -1243,7 +1174,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a err.error = Callable::CallError::CALL_OK; } } else { - if (*methodname != GDScriptLanguage::get_singleton()->strings._init) { err.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; } else { @@ -1252,7 +1182,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } if (err.error != Callable::CallError::CALL_OK) { - String methodstr = *methodname; err_text = _get_call_error(err, "function '" + methodstr + "'", (const Variant **)argptrs); @@ -1265,7 +1194,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_YIELD) OPCODE(OPCODE_YIELD_SIGNAL) { - int ipofs = 1; if (_code_ptr[ip] == OPCODE_YIELD_SIGNAL) { CHECK_SPACE(4); @@ -1285,13 +1213,24 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a gdfs->state.stack_size = _stack_size; gdfs->state.self = self; gdfs->state.alloca_size = alloca_size; - gdfs->state.script = Ref<GDScript>(_script); gdfs->state.ip = ip + ipofs; gdfs->state.line = line; - gdfs->state.instance_id = (p_instance && p_instance->get_owner()) ? p_instance->get_owner()->get_instance_id() : ObjectID(); - //gdfs->state.result_pos=ip+ipofs-1; + gdfs->state.script = _script; + { + MutexLock lock(GDScriptLanguage::get_singleton()->lock); + _script->pending_func_states.add(&gdfs->scripts_list); + if (p_instance) { + gdfs->state.instance = p_instance; + p_instance->pending_func_states.add(&gdfs->instances_list); + } else { + gdfs->state.instance = nullptr; + } + } +#ifdef DEBUG_ENABLED + gdfs->state.function_name = name; + gdfs->state.script_path = _script->get_path(); +#endif gdfs->state.defarg = defarg; - gdfs->state.instance = p_instance; gdfs->function = this; retvalue = gdfs; @@ -1327,7 +1266,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_BREAK; } if (signal.length() == 0) { - err_text = "Second argument of yield() is an empty string (for signal name)."; OPCODE_BREAK; } @@ -1353,7 +1291,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } OPCODE(OPCODE_YIELD_RESUME) { - CHECK_SPACE(2); #ifdef DEBUG_ENABLED if (!p_state) { @@ -1368,7 +1305,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_JUMP) { - CHECK_SPACE(2); int to = _code_ptr[ip + 1]; @@ -1378,7 +1314,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_JUMP_IF) { - CHECK_SPACE(3); GET_VARIANT_PTR(test, 1); @@ -1396,7 +1331,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_JUMP_IF_NOT) { - CHECK_SPACE(3); GET_VARIANT_PTR(test, 1); @@ -1414,14 +1348,12 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_JUMP_TO_DEF_ARGUMENT) { - CHECK_SPACE(2); ip = _default_arg_ptr[defarg]; } DISPATCH_OPCODE; OPCODE(OPCODE_RETURN) { - CHECK_SPACE(2); GET_VARIANT_PTR(r, 1); retvalue = *r; @@ -1432,7 +1364,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } OPCODE(OPCODE_ITERATE_BEGIN) { - CHECK_SPACE(8); //space for this a regular iterate GET_VARIANT_PTR(counter, 1); @@ -1465,7 +1396,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a DISPATCH_OPCODE; OPCODE(OPCODE_ITERATE) { - CHECK_SPACE(4); GET_VARIANT_PTR(counter, 1); @@ -1502,11 +1432,14 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED GET_VARIANT_PTR(test, 1); - GET_VARIANT_PTR(message, 2); bool result = test->booleanize(); if (!result) { - const String &message_str = *message; + String message_str; + if (_code_ptr[ip + 2] != 0) { + GET_VARIANT_PTR(message, 2); + message_str = *message; + } if (message_str.empty()) { err_text = "Assertion failed."; } else { @@ -1541,15 +1474,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a bool do_break = false; if (EngineDebugger::get_script_debugger()->get_lines_left() > 0) { - - if (EngineDebugger::get_script_debugger()->get_depth() <= 0) + if (EngineDebugger::get_script_debugger()->get_depth() <= 0) { EngineDebugger::get_script_debugger()->set_lines_left(EngineDebugger::get_script_debugger()->get_lines_left() - 1); - if (EngineDebugger::get_script_debugger()->get_lines_left() <= 0) + } + if (EngineDebugger::get_script_debugger()->get_lines_left() <= 0) { do_break = true; + } } - if (EngineDebugger::get_script_debugger()->is_breakpoint(line, source)) + if (EngineDebugger::get_script_debugger()->is_breakpoint(line, source)) { do_break = true; + } if (do_break) { GDScriptLanguage::get_singleton()->debug_break("Breakpoint", true); @@ -1577,20 +1512,24 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODES_END #ifdef DEBUG_ENABLED - if (exit_ok) + if (exit_ok) { OPCODE_OUT; + } //error // function, file, line, error, explanation String err_file; - if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->path != "") + if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->path != "") { err_file = p_instance->script->path; - else if (script) + } else if (script) { err_file = script->path; - if (err_file == "") + } + if (err_file == "") { err_file = "<built-in>"; + } String err_func = name; - if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->name != "") + if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->name != "") { err_func = p_instance->script->name + "." + err_func; + } int err_line = line; if (err_text == "") { err_text = "Internal Script Error! - opcode #" + itos(last_opcode) + " (report please)."; @@ -1622,14 +1561,16 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a // When it's the last resume it will postpone the exit from stack, // so the debugger knows which function triggered the resume of the next function (if any) if (!p_state || yielded) { - if (EngineDebugger::is_active()) + if (EngineDebugger::is_active()) { GDScriptLanguage::get_singleton()->exit_function(); + } #endif if (_stack_size) { //free stack - for (int i = 0; i < _stack_size; i++) + for (int i = 0; i < _stack_size; i++) { stack[i].~Variant(); + } } #ifdef DEBUG_ENABLED @@ -1640,32 +1581,28 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } const int *GDScriptFunction::get_code() const { - return _code_ptr; } -int GDScriptFunction::get_code_size() const { +int GDScriptFunction::get_code_size() const { return _code_size; } Variant GDScriptFunction::get_constant(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, constants.size(), "<errconst>"); return constants[p_idx]; } StringName GDScriptFunction::get_global_name(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, global_names.size(), "<errgname>"); return global_names[p_idx]; } int GDScriptFunction::get_default_argument_count() const { - return _default_arg_count; } -int GDScriptFunction::get_default_argument_addr(int p_idx) const { +int GDScriptFunction::get_default_argument_addr(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, default_arguments.size(), -1); return default_arguments[p_idx]; } @@ -1680,45 +1617,38 @@ GDScriptDataType GDScriptFunction::get_argument_type(int p_idx) const { } StringName GDScriptFunction::get_name() const { - return name; } int GDScriptFunction::get_max_stack_size() const { - return _stack_size; } struct _GDFKC { - int order; List<int> pos; }; struct _GDFKCS { - int order; StringName id; int pos; bool operator<(const _GDFKCS &p_r) const { - return order < p_r.order; } }; void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const { - int oc = 0; Map<StringName, _GDFKC> sdmap; for (const List<StackDebug>::Element *E = stack_debug.front(); E; E = E->next()) { - const StackDebug &sd = E->get(); - if (sd.line > p_line) + if (sd.line > p_line) { break; + } if (sd.added) { - if (!sdmap.has(sd.identifier)) { _GDFKC d; d.order = oc++; @@ -1729,18 +1659,17 @@ void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<String sdmap[sd.identifier].pos.push_back(sd.pos); } } else { - ERR_CONTINUE(!sdmap.has(sd.identifier)); sdmap[sd.identifier].pos.pop_back(); - if (sdmap[sd.identifier].pos.empty()) + if (sdmap[sd.identifier].pos.empty()) { sdmap.erase(sd.identifier); + } } } List<_GDFKCS> stackpositions; for (Map<StringName, _GDFKC>::Element *E = sdmap.front(); E; E = E->next()) { - _GDFKCS spp; spp.id = E->key(); spp.order = E->get().order; @@ -1751,7 +1680,6 @@ void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<String stackpositions.sort(); for (List<_GDFKCS>::Element *E = stackpositions.front(); E; E = E->next()) { - Pair<StringName, int> p; p.first = E->get().id; p.second = E->get().pos; @@ -1761,7 +1689,6 @@ void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<String GDScriptFunction::GDScriptFunction() : function_list(this) { - _stack_size = 0; _call_size = 0; rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; @@ -1800,7 +1727,6 @@ GDScriptFunction::~GDScriptFunction() { ///////////////////// Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - Variant arg; r_error.error = Callable::CallError::CALL_OK; @@ -1833,28 +1759,48 @@ Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_ar } bool GDScriptFunctionState::is_valid(bool p_extended_check) const { - - if (function == nullptr) + if (function == nullptr) { return false; + } if (p_extended_check) { - //class instance gone? - if (state.instance_id.is_valid() && !ObjectDB::get_instance(state.instance_id)) + MutexLock lock(GDScriptLanguage::get_singleton()->lock); + + // Script gone? + if (!scripts_list.in_list()) { return false; + } + // Class instance gone? (if not static function) + if (state.instance && !instances_list.in_list()) { + return false; + } } return true; } Variant GDScriptFunctionState::resume(const Variant &p_arg) { - ERR_FAIL_COND_V(!function, Variant()); - if (state.instance_id.is_valid() && !ObjectDB::get_instance(state.instance_id)) { + { + MutexLock lock(GDScriptLanguage::singleton->lock); + + if (!scripts_list.in_list()) { #ifdef DEBUG_ENABLED - ERR_FAIL_V_MSG(Variant(), "Resumed function '" + String(function->get_name()) + "()' after yield, but class instance is gone. At script: " + state.script->get_path() + ":" + itos(state.line)); + ERR_FAIL_V_MSG(Variant(), "Resumed function '" + state.function_name + "()' after yield, but script is gone. At script: " + state.script_path + ":" + itos(state.line)); #else - return Variant(); + return Variant(); +#endif + } + if (state.instance && !instances_list.in_list()) { +#ifdef DEBUG_ENABLED + ERR_FAIL_V_MSG(Variant(), "Resumed function '" + state.function_name + "()' after yield, but class instance is gone. At script: " + state.script_path + ":" + itos(state.line)); +#else + return Variant(); #endif + } + // Do these now to avoid locking again after the call + scripts_list.remove_from_list(); + instances_list.remove_from_list(); } state.result = p_arg; @@ -1884,13 +1830,8 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { } #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active()) + if (EngineDebugger::is_active()) { GDScriptLanguage::get_singleton()->exit_function(); - if (state.stack_size) { - //free stack - Variant *stack = (Variant *)state.stack.ptr(); - for (int i = 0; i < state.stack_size; i++) - stack[i].~Variant(); } #endif } @@ -1898,8 +1839,17 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { return ret; } -void GDScriptFunctionState::_bind_methods() { +void GDScriptFunctionState::_clear_stack() { + if (state.stack_size) { + Variant *stack = (Variant *)state.stack.ptr(); + for (int i = 0; i < state.stack_size; i++) { + stack[i].~Variant(); + } + state.stack_size = 0; + } +} +void GDScriptFunctionState::_bind_methods() { ClassDB::bind_method(D_METHOD("resume", "arg"), &GDScriptFunctionState::resume, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("is_valid", "extended_check"), &GDScriptFunctionState::is_valid, DEFVAL(false)); ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &GDScriptFunctionState::_signal_callback, MethodInfo("_signal_callback")); @@ -1907,18 +1857,18 @@ void GDScriptFunctionState::_bind_methods() { ADD_SIGNAL(MethodInfo("completed", PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); } -GDScriptFunctionState::GDScriptFunctionState() { - +GDScriptFunctionState::GDScriptFunctionState() : + scripts_list(this), + instances_list(this) { function = nullptr; } GDScriptFunctionState::~GDScriptFunctionState() { + _clear_stack(); - if (function != nullptr) { - //never called, deinitialize stack - for (int i = 0; i < state.stack_size; i++) { - Variant *v = (Variant *)&state.stack[sizeof(Variant) * i]; - v->~Variant(); - } + { + MutexLock lock(GDScriptLanguage::singleton->lock); + scripts_list.remove_from_list(); + instances_list.remove_from_list(); } } diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index acfc0a95b4..583eab744a 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -43,20 +43,25 @@ class GDScriptInstance; class GDScript; struct GDScriptDataType { - bool has_type; - enum { + enum Kind { UNINITIALIZED, BUILTIN, NATIVE, SCRIPT, GDSCRIPT, - } kind; - Variant::Type builtin_type; + }; + + Kind kind = UNINITIALIZED; + + bool has_type = false; + Variant::Type builtin_type = Variant::NIL; StringName native_type; Ref<Script> script_type; bool is_type(const Variant &p_variant, bool p_allow_implicit_conversion = false) const { - if (!has_type) return true; // Can't type check + if (!has_type) { + return true; // Can't type check + } switch (kind) { case UNINITIALIZED: @@ -146,10 +151,7 @@ struct GDScriptDataType { return info; } - GDScriptDataType() : - has_type(false), - kind(UNINITIALIZED), - builtin_type(Variant::NIL) {} + GDScriptDataType() {} }; class GDScriptFunction { @@ -214,7 +216,6 @@ public: }; struct StackDebug { - int line; int pos; bool added; @@ -292,14 +293,16 @@ private: public: struct CallState { - - ObjectID instance_id; + GDScript *script; GDScriptInstance *instance; +#ifdef DEBUG_ENABLED + StringName function_name; + String script_path; +#endif Vector<uint8_t> stack; int stack_size; Variant self; uint32_t alloca_size; - Ref<GDScript> script; int ip; int line; int defarg; @@ -347,7 +350,6 @@ public: }; class GDScriptFunctionState : public Reference { - GDCLASS(GDScriptFunctionState, Reference); friend class GDScriptFunction; GDScriptFunction *function; @@ -355,12 +357,18 @@ class GDScriptFunctionState : public Reference { Variant _signal_callback(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Ref<GDScriptFunctionState> first_state; + SelfList<GDScriptFunctionState> scripts_list; + SelfList<GDScriptFunctionState> instances_list; + protected: static void _bind_methods(); public: bool is_valid(bool p_extended_check = false) const; Variant resume(const Variant &p_arg = Variant()); + + void _clear_stack(); + GDScriptFunctionState(); ~GDScriptFunctionState(); }; diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp index 9154d6eb89..d4258c385e 100644 --- a/modules/gdscript/gdscript_functions.cpp +++ b/modules/gdscript/gdscript_functions.cpp @@ -41,7 +41,6 @@ #include "gdscript.h" const char *GDScriptFunctions::get_func_name(Function p_func) { - ERR_FAIL_INDEX_V(p_func, FUNC_MAX, ""); static const char *_names[FUNC_MAX] = { @@ -140,7 +139,6 @@ const char *GDScriptFunctions::get_func_name(Function p_func) { } void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_count, Variant &r_ret, Callable::CallError &r_error) { - r_error.error = Callable::CallError::CALL_OK; #ifdef DEBUG_ENABLED @@ -176,7 +174,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ //using a switch, so the compiler generates a jumptable switch (p_func) { - case MATH_SIN: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); @@ -269,15 +266,12 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ case MATH_ABS: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type() == Variant::INT) { - int64_t i = *p_args[0]; r_ret = ABS(i); } else if (p_args[0]->get_type() == Variant::FLOAT) { - double r = *p_args[0]; r_ret = Math::abs(r); } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::FLOAT; @@ -287,15 +281,12 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ case MATH_SIGN: { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type() == Variant::INT) { - int64_t i = *p_args[0]; r_ret = i < 0 ? -1 : (i > 0 ? +1 : 0); } else if (p_args[0]->get_type() == Variant::FLOAT) { - real_t r = *p_args[0]; r_ret = r < 0.0 ? -1.0 : (r > 0.0 ? +1.0 : 0.0); } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::FLOAT; @@ -362,13 +353,13 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ const double t = (double)*p_args[2]; switch (p_args[0]->get_type() == p_args[1]->get_type() ? p_args[0]->get_type() : Variant::FLOAT) { case Variant::VECTOR2: { - r_ret = ((Vector2)*p_args[0]).linear_interpolate((Vector2)*p_args[1], t); + r_ret = ((Vector2)*p_args[0]).lerp((Vector2)*p_args[1], t); } break; case Variant::VECTOR3: { - r_ret = (p_args[0]->operator Vector3()).linear_interpolate(p_args[1]->operator Vector3(), t); + r_ret = (p_args[0]->operator Vector3()).lerp(p_args[1]->operator Vector3(), t); } break; case Variant::COLOR: { - r_ret = ((Color)*p_args[0]).linear_interpolate((Color)*p_args[1], t); + r_ret = ((Color)*p_args[0]).lerp((Color)*p_args[1], t); } break; default: { VALIDATE_ARG_NUM(0); @@ -505,7 +496,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ case LOGIC_MAX: { VALIDATE_ARG_COUNT(2); if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT) { - int64_t a = *p_args[0]; int64_t b = *p_args[1]; r_ret = MAX(a, b); @@ -523,7 +513,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ case LOGIC_MIN: { VALIDATE_ARG_COUNT(2); if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT) { - int64_t a = *p_args[0]; int64_t b = *p_args[1]; r_ret = MIN(a, b); @@ -540,7 +529,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ case LOGIC_CLAMP: { VALIDATE_ARG_COUNT(3); if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT && p_args[2]->get_type() == Variant::INT) { - int64_t a = *p_args[0]; int64_t b = *p_args[1]; int64_t c = *p_args[2]; @@ -595,7 +583,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ case FUNC_FUNCREF: { VALIDATE_ARG_COUNT(2); if (p_args[0]->get_type() != Variant::OBJECT) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::OBJECT; @@ -603,7 +590,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ return; } if (p_args[1]->get_type() != Variant::STRING && p_args[1]->get_type() != Variant::NODE_PATH) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 1; r_error.expected = Variant::STRING; @@ -624,7 +610,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ VALIDATE_ARG_NUM(1); int type = *p_args[1]; if (type < 0 || type >= Variant::VARIANT_MAX) { - r_ret = RTR("Invalid type argument to convert(), use TYPE_* constants."); r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; @@ -632,18 +617,15 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ return; } else { - r_ret = Variant::construct(Variant::Type(type), p_args, 1, r_error); } } break; case TYPE_OF: { - VALIDATE_ARG_COUNT(1); r_ret = p_args[0]->get_type(); } break; case TYPE_EXISTS: { - VALIDATE_ARG_COUNT(1); r_ret = ClassDB::class_exists(*p_args[0]); @@ -655,11 +637,9 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ r_ret = String(result); } break; case TEXT_ORD: { - VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type() != Variant::STRING) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING; @@ -670,7 +650,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ String str = p_args[0]->operator String(); if (str.length() != 1) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING; @@ -691,23 +670,21 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } String str; for (int i = 0; i < p_arg_count; i++) { - String os = p_args[i]->operator String(); - if (i == 0) + if (i == 0) { str = os; - else + } else { str += os; + } } r_ret = str; } break; case TEXT_PRINT: { - String str; for (int i = 0; i < p_arg_count; i++) { - str += p_args[i]->operator String(); } @@ -716,12 +693,11 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; case TEXT_PRINT_TABBED: { - String str; for (int i = 0; i < p_arg_count; i++) { - - if (i) + if (i) { str += "\t"; + } str += p_args[i]->operator String(); } @@ -730,12 +706,11 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; case TEXT_PRINT_SPACED: { - String str; for (int i = 0; i < p_arg_count; i++) { - - if (i) + if (i) { str += " "; + } str += p_args[i]->operator String(); } @@ -745,10 +720,8 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; case TEXT_PRINTERR: { - String str; for (int i = 0; i < p_arg_count; i++) { - str += p_args[i]->operator String(); } @@ -759,7 +732,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ case TEXT_PRINTRAW: { String str; for (int i = 0; i < p_arg_count; i++) { - str += p_args[i]->operator String(); } @@ -770,7 +742,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ case TEXT_PRINT_DEBUG: { String str; for (int i = 0; i < p_arg_count; i++) { - str += p_args[i]->operator String(); } @@ -922,18 +893,14 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; case GEN_RANGE: { - switch (p_arg_count) { - case 0: { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = 1; r_ret = Variant(); } break; case 1: { - VALIDATE_ARG_NUM(0); int count = *p_args[0]; Array arr; @@ -955,7 +922,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ r_ret = arr; } break; case 2: { - VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); @@ -973,12 +939,12 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ r_ret = Variant(); return; } - for (int i = from; i < to; i++) + for (int i = from; i < to; i++) { arr[i - from] = i; + } r_ret = arr; } break; case 3: { - VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); VALIDATE_ARG_NUM(2); @@ -987,7 +953,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ int to = *p_args[1]; int incr = *p_args[2]; if (incr == 0) { - r_ret = RTR("Step argument is zero!"); r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; return; @@ -1006,10 +971,8 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ //calculate how many int count = 0; if (incr > 0) { - count = ((to - from - 1) / incr) + 1; } else { - count = ((from - to - 1) / -incr) + 1; } @@ -1027,7 +990,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ arr[idx++] = i; } } else { - int idx = 0; for (int i = from; i > to; i += incr) { arr[idx++] = i; @@ -1037,7 +999,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ r_ret = arr; } break; default: { - r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; r_error.argument = 3; r_ret = Variant(); @@ -1059,7 +1020,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; case INST2DICT: { - VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type() == Variant::NIL) { @@ -1069,24 +1029,20 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ r_error.argument = 0; r_ret = Variant(); } else { - Object *obj = *p_args[0]; if (!obj) { r_ret = Variant(); } else if (!obj->get_script_instance() || obj->get_script_instance()->get_language() != GDScriptLanguage::get_singleton()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::DICTIONARY; r_ret = RTR("Not a script with an instance"); return; } else { - GDScriptInstance *ins = static_cast<GDScriptInstance *>(obj->get_script_instance()); Ref<GDScript> base = ins->get_script(); if (base.is_null()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::DICTIONARY; @@ -1098,7 +1054,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ Vector<StringName> sname; while (p->_owner) { - sname.push_back(p->name); p = p->_owner; } @@ -1132,11 +1087,9 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; case DICT2INST: { - VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type() != Variant::DICTIONARY) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::DICTIONARY; @@ -1148,7 +1101,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ Dictionary d = *p_args[0]; if (!d.has("@path")) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::OBJECT; @@ -1159,7 +1111,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ Ref<Script> scr = ResourceLoader::load(d["@path"]); if (!scr.is_valid()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::OBJECT; @@ -1170,7 +1121,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ Ref<GDScript> gdscr = scr; if (!gdscr.is_valid()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::OBJECT; @@ -1185,10 +1135,8 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } for (int i = 0; i < sub.get_name_count(); i++) { - gdscr = gdscr->subclasses[sub.get_name(i)]; if (!gdscr.is_valid()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::OBJECT; @@ -1197,8 +1145,12 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ return; } } + r_ret = gdscr->_new(nullptr, -1 /*skip initializer*/, r_error); - r_ret = gdscr->_new(nullptr, 0, r_error); + if (r_error.error != Callable::CallError::CALL_OK) { + r_ret = Variant(); + return; + } GDScriptInstance *ins = static_cast<GDScriptInstance *>(static_cast<Object *>(r_ret)->get_script_instance()); Ref<GDScript> gd_ref = ins->get_script(); @@ -1211,7 +1163,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; case VALIDATE_JSON: { - VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type() != Variant::STRING) { @@ -1235,7 +1186,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; case PARSE_JSON: { - VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type() != Variant::STRING) { @@ -1263,13 +1213,11 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ r_ret = JSON::print(*p_args[0]); } break; case HASH: { - VALIDATE_ARG_COUNT(1); r_ret = p_args[0]->hash(); } break; case COLOR8: { - if (p_arg_count < 3) { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = 3; @@ -1300,7 +1248,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; case COLORN: { - if (p_arg_count < 1) { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = 1; @@ -1335,7 +1282,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ ScriptLanguage *script = GDScriptLanguage::get_singleton(); for (int i = 0; i < script->debug_get_stack_level_count(); i++) { - print_line("Frame " + itos(i) + " - " + script->debug_get_stack_level_source(i) + ":" + itos(script->debug_get_stack_level_line(i)) + " in function '" + script->debug_get_stack_level_function(i) + "'"); }; } break; @@ -1346,7 +1292,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ ScriptLanguage *script = GDScriptLanguage::get_singleton(); Array ret; for (int i = 0; i < script->debug_get_stack_level_count(); i++) { - Dictionary frame; frame["source"] = script->debug_get_stack_level_source(i); frame["function"] = script->debug_get_stack_level_function(i); @@ -1357,7 +1302,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; case INSTANCE_FROM_ID: { - VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type() != Variant::INT && p_args[0]->get_type() != Variant::FLOAT) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; @@ -1372,66 +1316,53 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; case LEN: { - VALIDATE_ARG_COUNT(1); switch (p_args[0]->get_type()) { case Variant::STRING: { - String d = *p_args[0]; r_ret = d.length(); } break; case Variant::DICTIONARY: { - Dictionary d = *p_args[0]; r_ret = d.size(); } break; case Variant::ARRAY: { - Array d = *p_args[0]; r_ret = d.size(); } break; case Variant::PACKED_BYTE_ARRAY: { - Vector<uint8_t> d = *p_args[0]; r_ret = d.size(); } break; case Variant::PACKED_INT32_ARRAY: { - Vector<int32_t> d = *p_args[0]; r_ret = d.size(); } break; case Variant::PACKED_INT64_ARRAY: { - Vector<int64_t> d = *p_args[0]; r_ret = d.size(); } break; case Variant::PACKED_FLOAT32_ARRAY: { - Vector<float> d = *p_args[0]; r_ret = d.size(); } break; case Variant::PACKED_FLOAT64_ARRAY: { - Vector<double> d = *p_args[0]; r_ret = d.size(); } break; case Variant::PACKED_STRING_ARRAY: { - Vector<String> d = *p_args[0]; r_ret = d.size(); } break; case Variant::PACKED_VECTOR2_ARRAY: { - Vector<Vector2> d = *p_args[0]; r_ret = d.size(); } break; case Variant::PACKED_VECTOR3_ARRAY: { - Vector<Vector3> d = *p_args[0]; r_ret = d.size(); } break; case Variant::PACKED_COLOR_ARRAY: { - Vector<Color> d = *p_args[0]; r_ret = d.size(); } break; @@ -1446,7 +1377,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; case IS_INSTANCE_VALID: { - VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type() != Variant::OBJECT) { r_ret = false; @@ -1457,19 +1387,16 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; case FUNC_MAX: { - ERR_FAIL(); } break; } } bool GDScriptFunctions::is_deterministic(Function p_func) { - //man i couldn't have chosen a worse function name, //way too controversial.. switch (p_func) { - case MATH_SIN: case MATH_COS: case MATH_TAN: @@ -1533,12 +1460,10 @@ bool GDScriptFunctions::is_deterministic(Function p_func) { } MethodInfo GDScriptFunctions::get_info(Function p_func) { - #ifdef DEBUG_ENABLED //using a switch, so the compiler generates a jumptable switch (p_func) { - case MATH_SIN: { MethodInfo mi("sin", PropertyInfo(Variant::FLOAT, "s")); mi.return_val.type = Variant::FLOAT; @@ -1813,7 +1738,6 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { return mi; } break; case OBJ_WEAKREF: { - MethodInfo mi("weakref", PropertyInfo(Variant::OBJECT, "obj")); mi.return_val.type = Variant::OBJECT; mi.return_val.class_name = "WeakRef"; @@ -1822,7 +1746,6 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { } break; case FUNC_FUNCREF: { - MethodInfo mi("funcref", PropertyInfo(Variant::OBJECT, "instance"), PropertyInfo(Variant::STRING, "funcname")); mi.return_val.type = Variant::OBJECT; mi.return_val.class_name = "FuncRef"; @@ -1830,42 +1753,36 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { } break; case TYPE_CONVERT: { - MethodInfo mi("convert", PropertyInfo(Variant::NIL, "what", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::INT, "type")); mi.return_val.type = Variant::NIL; mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; return mi; } break; case TYPE_OF: { - MethodInfo mi("typeof", PropertyInfo(Variant::NIL, "what", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); mi.return_val.type = Variant::INT; return mi; } break; case TYPE_EXISTS: { - MethodInfo mi("type_exists", PropertyInfo(Variant::STRING, "type")); mi.return_val.type = Variant::BOOL; return mi; } break; case TEXT_CHAR: { - MethodInfo mi("char", PropertyInfo(Variant::INT, "code")); mi.return_val.type = Variant::STRING; return mi; } break; case TEXT_ORD: { - MethodInfo mi("ord", PropertyInfo(Variant::STRING, "char")); mi.return_val.type = Variant::INT; return mi; } break; case TEXT_STR: { - MethodInfo mi("str"); mi.return_val.type = Variant::STRING; mi.flags |= METHOD_FLAG_VARARG; @@ -1873,7 +1790,6 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { } break; case TEXT_PRINT: { - MethodInfo mi("print"); mi.return_val.type = Variant::NIL; mi.flags |= METHOD_FLAG_VARARG; @@ -1881,7 +1797,6 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { } break; case TEXT_PRINT_TABBED: { - MethodInfo mi("printt"); mi.return_val.type = Variant::NIL; mi.flags |= METHOD_FLAG_VARARG; @@ -1889,7 +1804,6 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { } break; case TEXT_PRINT_SPACED: { - MethodInfo mi("prints"); mi.return_val.type = Variant::NIL; mi.flags |= METHOD_FLAG_VARARG; @@ -1897,7 +1811,6 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { } break; case TEXT_PRINTERR: { - MethodInfo mi("printerr"); mi.return_val.type = Variant::NIL; mi.flags |= METHOD_FLAG_VARARG; @@ -1905,7 +1818,6 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { } break; case TEXT_PRINTRAW: { - MethodInfo mi("printraw"); mi.return_val.type = Variant::NIL; mi.flags |= METHOD_FLAG_VARARG; @@ -1913,7 +1825,6 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { } break; case TEXT_PRINT_DEBUG: { - MethodInfo mi("print_debug"); mi.return_val.type = Variant::NIL; mi.flags |= METHOD_FLAG_VARARG; @@ -1921,41 +1832,35 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { } break; case PUSH_ERROR: { - MethodInfo mi(Variant::NIL, "push_error", PropertyInfo(Variant::STRING, "message")); mi.return_val.type = Variant::NIL; return mi; } break; case PUSH_WARNING: { - MethodInfo mi(Variant::NIL, "push_warning", PropertyInfo(Variant::STRING, "message")); mi.return_val.type = Variant::NIL; return mi; } break; case VAR_TO_STR: { - MethodInfo mi("var2str", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); mi.return_val.type = Variant::STRING; return mi; } break; case STR_TO_VAR: { - MethodInfo mi(Variant::NIL, "str2var", PropertyInfo(Variant::STRING, "string")); mi.return_val.type = Variant::NIL; mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; return mi; } break; case VAR_TO_BYTES: { - MethodInfo mi("var2bytes", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::BOOL, "full_objects")); mi.default_arguments.push_back(false); mi.return_val.type = Variant::PACKED_BYTE_ARRAY; return mi; } break; case BYTES_TO_VAR: { - MethodInfo mi(Variant::NIL, "bytes2var", PropertyInfo(Variant::PACKED_BYTE_ARRAY, "bytes"), PropertyInfo(Variant::BOOL, "allow_objects")); mi.default_arguments.push_back(false); mi.return_val.type = Variant::NIL; @@ -1963,65 +1868,55 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { return mi; } break; case GEN_RANGE: { - MethodInfo mi("range"); mi.return_val.type = Variant::ARRAY; mi.flags |= METHOD_FLAG_VARARG; return mi; } break; case RESOURCE_LOAD: { - MethodInfo mi("load", PropertyInfo(Variant::STRING, "path")); mi.return_val.type = Variant::OBJECT; mi.return_val.class_name = "Resource"; return mi; } break; case INST2DICT: { - MethodInfo mi("inst2dict", PropertyInfo(Variant::OBJECT, "inst")); mi.return_val.type = Variant::DICTIONARY; return mi; } break; case DICT2INST: { - MethodInfo mi("dict2inst", PropertyInfo(Variant::DICTIONARY, "dict")); mi.return_val.type = Variant::OBJECT; return mi; } break; case VALIDATE_JSON: { - MethodInfo mi("validate_json", PropertyInfo(Variant::STRING, "json")); mi.return_val.type = Variant::STRING; return mi; } break; case PARSE_JSON: { - MethodInfo mi(Variant::NIL, "parse_json", PropertyInfo(Variant::STRING, "json")); mi.return_val.type = Variant::NIL; mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; return mi; } break; case TO_JSON: { - MethodInfo mi("to_json", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); mi.return_val.type = Variant::STRING; return mi; } break; case HASH: { - MethodInfo mi("hash", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); mi.return_val.type = Variant::INT; return mi; } break; case COLOR8: { - MethodInfo mi("Color8", PropertyInfo(Variant::INT, "r8"), PropertyInfo(Variant::INT, "g8"), PropertyInfo(Variant::INT, "b8"), PropertyInfo(Variant::INT, "a8")); mi.default_arguments.push_back(255); mi.return_val.type = Variant::COLOR; return mi; } break; case COLORN: { - MethodInfo mi("ColorN", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "alpha")); mi.default_arguments.push_back(1.0f); mi.return_val.type = Variant::COLOR; @@ -2055,7 +1950,6 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { return mi; } break; default: { - ERR_FAIL_V(MethodInfo()); } break; } diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 8d34ce5c70..d2867cb77a 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -42,14 +42,14 @@ template <class T> T *GDScriptParser::alloc_node() { - T *t = memnew(T); t->next = list; list = t; - if (!head) + if (!head) { head = t; + } t->line = tokenizer->get_token_line(); t->column = tokenizer->get_token_column(); @@ -61,7 +61,6 @@ static String _find_function_name(const GDScriptParser::OperatorNode *p_call); #endif // DEBUG_ENABLED bool GDScriptParser::_end_statement() { - if (tokenizer->get_token() == GDScriptTokenizer::TK_SEMICOLON) { tokenizer->advance(); return true; //handle next @@ -72,8 +71,17 @@ bool GDScriptParser::_end_statement() { return false; } -bool GDScriptParser::_enter_indent_block(BlockNode *p_block) { +void GDScriptParser::_set_end_statement_error(String p_name) { + String error_msg; + if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER) { + error_msg = vformat("Expected end of statement (\"%s\"), got %s (\"%s\") instead.", p_name, tokenizer->get_token_name(tokenizer->get_token()), tokenizer->get_token_identifier()); + } else { + error_msg = vformat("Expected end of statement (\"%s\"), got %s instead.", p_name, tokenizer->get_token_name(tokenizer->get_token())); + } + _set_error(error_msg); +} +bool GDScriptParser::_enter_indent_block(BlockNode *p_block) { if (tokenizer->get_token() != GDScriptTokenizer::TK_COLON) { // report location at the previous token (on the previous line) int error_line = tokenizer->get_token_line(-1); @@ -98,12 +106,10 @@ bool GDScriptParser::_enter_indent_block(BlockNode *p_block) { while (true) { if (tokenizer->get_token() != GDScriptTokenizer::TK_NEWLINE) { - return false; //wtf } else if (tokenizer->get_token(1) == GDScriptTokenizer::TK_EOF) { return false; } else if (tokenizer->get_token(1) != GDScriptTokenizer::TK_NEWLINE) { - int indent = tokenizer->get_token_line_indent(); int tabs = tokenizer->get_token_line_tab_indent(); IndentLevel current_level = indent_level.back()->get(); @@ -122,7 +128,6 @@ bool GDScriptParser::_enter_indent_block(BlockNode *p_block) { return true; } else if (p_block) { - NewLineNode *nl = alloc_node<NewLineNode>(); nl->line = tokenizer->get_token_line(); p_block->statements.push_back(nl); @@ -133,16 +138,13 @@ bool GDScriptParser::_enter_indent_block(BlockNode *p_block) { } bool GDScriptParser::_parse_arguments(Node *p_parent, Vector<Node *> &p_args, bool p_static, bool p_can_codecomplete, bool p_parsing_constant) { - if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { tokenizer->advance(); } else { - parenthesis++; int argidx = 0; while (true) { - if (tokenizer->get_token() == GDScriptTokenizer::TK_CURSOR) { _make_completable_call(argidx); completion_node = p_parent; @@ -168,9 +170,7 @@ bool GDScriptParser::_parse_arguments(Node *p_parent, Vector<Node *> &p_args, bo break; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { - if (tokenizer->get_token(1) == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { - _set_error("Expression expected"); return false; } @@ -190,7 +190,6 @@ bool GDScriptParser::_parse_arguments(Node *p_parent, Vector<Node *> &p_args, bo } void GDScriptParser::_make_completable_call(int p_arg) { - completion_cursor = StringName(); completion_type = COMPLETION_CALL_ARGUMENTS; completion_class = current_class; @@ -203,14 +202,12 @@ void GDScriptParser::_make_completable_call(int p_arg) { } bool GDScriptParser::_get_completable_identifier(CompletionType p_type, StringName &identifier) { - identifier = StringName(); if (tokenizer->is_token_literal()) { identifier = tokenizer->get_token_literal(); tokenizer->advance(); } if (tokenizer->get_token() == GDScriptTokenizer::TK_CURSOR) { - completion_cursor = identifier; completion_type = p_type; completion_class = current_class; @@ -236,7 +233,6 @@ bool GDScriptParser::_get_completable_identifier(CompletionType p_type, StringNa } GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_static, bool p_allow_assign, bool p_parsing_constant) { - //Vector<Node*> expressions; //Vector<OperatorNode::Operator> operators; @@ -247,7 +243,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s int op_line = tokenizer->get_token_line(); // when operators are created at the bottom, the line might have been changed (\n found) while (true) { - /*****************/ /* Parse Operand */ /*****************/ @@ -275,11 +270,11 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s parenthesis++; Node *subexpr = _parse_expression(p_parent, p_static, p_allow_assign, p_parsing_constant); parenthesis--; - if (!subexpr) + if (!subexpr) { return nullptr; + } if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')' in expression"); return nullptr; } @@ -296,7 +291,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s int line = tokenizer->get_token_line(); while (!done) { - switch (tokenizer->get_token()) { case GDScriptTokenizer::TK_CURSOR: { completion_type = COMPLETION_GET_NODE; @@ -310,7 +304,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(); } break; case GDScriptTokenizer::TK_CONSTANT: { - if (!need_identifier) { done = true; break; @@ -327,7 +320,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } break; case GDScriptTokenizer::TK_OP_DIV: { - if (need_identifier) { done = true; break; @@ -382,7 +374,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s continue; //no point in cursor in the middle of expression } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CONSTANT) { - //constant defined by tokenizer ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = tokenizer->get_token_constant(); @@ -390,7 +381,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(); expr = constant; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CONST_PI) { - //constant defined by tokenizer ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = Math_PI; @@ -398,7 +388,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(); expr = constant; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CONST_TAU) { - //constant defined by tokenizer ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = Math_TAU; @@ -406,7 +395,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(); expr = constant; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CONST_INF) { - //constant defined by tokenizer ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = Math_INF; @@ -414,7 +402,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(); expr = constant; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CONST_NAN) { - //constant defined by tokenizer ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = Math_NAN; @@ -422,7 +409,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(); expr = constant; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_PRELOAD) { - //constant defined by tokenizer tokenizer->advance(); if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) { @@ -479,11 +465,11 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s return nullptr; } - if (!path.is_abs_path() && base_path != "") + if (!path.is_abs_path() && base_path != "") { path = base_path.plus_file(path); + } path = path.replace("///", "//").simplify_path(); if (path == self_path) { - _set_error("Can't preload itself (use 'get_script()')."); return nullptr; } @@ -492,7 +478,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s dependencies.push_back(path); if (!dependencies_only) { if (!validating) { - //this can be too slow for just validating code if (for_completion && ScriptCodeCompletionCache::get_singleton() && FileAccess::exists(path)) { res = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(path); @@ -500,7 +485,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s res = ResourceLoader::load(path); } } else { - if (!FileAccess::exists(path)) { _set_error("Can't preload resource at path: " + path); return nullptr; @@ -533,7 +517,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s expr = constant; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_YIELD) { - if (!current_function) { _set_error("\"yield()\" can only be used inside function blocks."); return nullptr; @@ -560,12 +543,12 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s expr = yield; tokenizer->advance(); } else { - parenthesis++; Node *object = _parse_and_reduce_expression(p_parent, p_static); - if (!object) + if (!object) { return nullptr; + } yield->arguments.push_back(object); if (tokenizer->get_token() != GDScriptTokenizer::TK_COMMA) { @@ -576,7 +559,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(); if (tokenizer->get_token() == GDScriptTokenizer::TK_CURSOR) { - completion_cursor = StringName(); completion_node = object; completion_type = COMPLETION_YIELD; @@ -590,8 +572,9 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } Node *signal = _parse_and_reduce_expression(p_parent, p_static); - if (!signal) + if (!signal) { return nullptr; + } yield->arguments.push_back(signal); if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { @@ -607,7 +590,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } } else if (tokenizer->get_token() == GDScriptTokenizer::TK_SELF) { - if (p_static) { _set_error("\"self\" isn't allowed in a static function or constant expression."); return nullptr; @@ -617,28 +599,23 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(); expr = self; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_BUILT_IN_TYPE && tokenizer->get_token(1) == GDScriptTokenizer::TK_PERIOD) { - Variant::Type bi_type = tokenizer->get_token_type(); tokenizer->advance(2); StringName identifier; if (_get_completable_identifier(COMPLETION_BUILT_IN_TYPE_CONSTANT, identifier)) { - completion_built_in_constant = bi_type; } if (identifier == StringName()) { - _set_error("Built-in type constant or static function expected after \".\"."); return nullptr; } if (!Variant::has_constant(bi_type, identifier)) { - if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN && Variant::is_method_const(bi_type, identifier) && Variant::get_method_return_type(bi_type, identifier) == bi_type) { - tokenizer->advance(); OperatorNode *construct = alloc_node<OperatorNode>(); @@ -656,8 +633,9 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s id->name = identifier; op->arguments.push_back(id); - if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant)) + if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant)) { return nullptr; + } expr = op; } else { @@ -678,7 +656,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } } } else { - ConstantNode *cn = alloc_node<ConstantNode>(); cn->value = Variant::get_constant_value(bi_type, identifier); cn->datatype = _type_from_variant(cn->value); @@ -723,13 +700,11 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(2); } } else if (tokenizer->get_token() == GDScriptTokenizer::TK_BUILT_IN_FUNC) { - BuiltInFunctionNode *bn = alloc_node<BuiltInFunctionNode>(); bn->function = tokenizer->get_token_built_in_func(); op->arguments.push_back(bn); tokenizer->advance(2); } else { - SelfNode *self = alloc_node<SelfNode>(); op->arguments.push_back(self); @@ -746,10 +721,18 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (tokenizer->get_token() == GDScriptTokenizer::TK_CURSOR) { _make_completable_call(0); completion_node = op; + + if (op->arguments[0]->type == GDScriptParser::Node::Type::TYPE_BUILT_IN_FUNCTION) { + BuiltInFunctionNode *bn = static_cast<BuiltInFunctionNode *>(op->arguments[0]); + if (bn->function == GDScriptFunctions::Function::RESOURCE_LOAD) { + completion_type = COMPLETION_RESOURCE_PATH; + } + } } if (!replaced) { - if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant)) + if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant)) { return nullptr; + } expr = op; } } else if (tokenizer->is_token_literal(0, true)) { @@ -827,6 +810,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s //check from singletons ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = GDScriptLanguage::get_singleton()->get_named_globals_map()[identifier]; + constant->datatype = _type_from_variant(constant->value); expr = constant; bfn = true; } @@ -837,6 +821,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (scr.is_valid() && scr->is_valid()) { ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = scr; + constant->datatype = _type_from_variant(constant->value); expr = constant; bfn = true; } @@ -852,6 +837,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (parent_constants.has(identifier)) { ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = parent_constants[identifier]; + constant->datatype = _type_from_variant(constant->value); expr = constant; bfn = true; } @@ -893,17 +879,24 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } } else if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ADD || tokenizer->get_token() == GDScriptTokenizer::TK_OP_SUB || tokenizer->get_token() == GDScriptTokenizer::TK_OP_NOT || tokenizer->get_token() == GDScriptTokenizer::TK_OP_BIT_INVERT) { - //single prefix operators like !expr +expr -expr ++expr --expr alloc_node<OperatorNode>(); Expression e; e.is_op = true; switch (tokenizer->get_token()) { - case GDScriptTokenizer::TK_OP_ADD: e.op = OperatorNode::OP_POS; break; - case GDScriptTokenizer::TK_OP_SUB: e.op = OperatorNode::OP_NEG; break; - case GDScriptTokenizer::TK_OP_NOT: e.op = OperatorNode::OP_NOT; break; - case GDScriptTokenizer::TK_OP_BIT_INVERT: e.op = OperatorNode::OP_BIT_INVERT; break; + case GDScriptTokenizer::TK_OP_ADD: + e.op = OperatorNode::OP_POS; + break; + case GDScriptTokenizer::TK_OP_SUB: + e.op = OperatorNode::OP_NEG; + break; + case GDScriptTokenizer::TK_OP_NOT: + e.op = OperatorNode::OP_NOT; + break; + case GDScriptTokenizer::TK_OP_BIT_INVERT: + e.op = OperatorNode::OP_BIT_INVERT; + break; default: { } } @@ -951,9 +944,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s bool expecting_comma = false; while (true) { - if (tokenizer->get_token() == GDScriptTokenizer::TK_EOF) { - _set_error("Unterminated array"); return nullptr; @@ -961,7 +952,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(); break; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE) { - tokenizer->advance(); //ignore newline } else if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { if (!expecting_comma) { @@ -978,8 +968,9 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s return nullptr; } Node *n = _parse_expression(arr, p_static, p_allow_assign, p_parsing_constant); - if (!n) + if (!n) { return nullptr; + } arr->elements.push_back(n); expecting_comma = true; } @@ -1007,14 +998,11 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s DictExpect expecting = DICT_EXPECT_KEY; while (true) { - if (tokenizer->get_token() == GDScriptTokenizer::TK_EOF) { - _set_error("Unterminated dictionary"); return nullptr; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CURLY_BRACKET_CLOSE) { - if (expecting == DICT_EXPECT_COLON) { _set_error("':' expected"); return nullptr; @@ -1026,10 +1014,8 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(); break; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE) { - tokenizer->advance(); //ignore newline } else if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { - if (expecting == DICT_EXPECT_KEY) { _set_error("key or '}' expected"); return nullptr; @@ -1047,7 +1033,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(); //ignore newline } else if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { - if (expecting == DICT_EXPECT_KEY) { _set_error("key or '}' expected"); return nullptr; @@ -1064,7 +1049,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s expecting = DICT_EXPECT_VALUE; tokenizer->advance(); //ignore newline } else { - if (expecting == DICT_EXPECT_COMMA) { _set_error("',' or '}' expected"); return nullptr; @@ -1075,7 +1059,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } if (expecting == DICT_EXPECT_KEY) { - if (tokenizer->is_token_literal() && tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) { // We check with is_token_literal, as this allows us to use match/sync/etc. as a name //lua style identifier, easier to write @@ -1088,16 +1071,18 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } else { //python/js style more flexible key = _parse_expression(dict, p_static, p_allow_assign, p_parsing_constant); - if (!key) + if (!key) { return nullptr; + } expecting = DICT_EXPECT_COLON; } } if (expecting == DICT_EXPECT_VALUE) { Node *value = _parse_expression(dict, p_static, p_allow_assign, p_parsing_constant); - if (!value) + if (!value) { return nullptr; + } expecting = DICT_EXPECT_COMMA; if (key->type == GDScriptParser::Node::TYPE_CONSTANT) { @@ -1163,7 +1148,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s expr = tn; tokenizer->advance(); } else { - //find list [ or find dictionary { _set_error("Error parsing expression, misplaced: " + String(tokenizer->get_token_name(tokenizer->get_token()))); return nullptr; //nothing @@ -1176,11 +1160,9 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s /******************/ while (true) { - //expressions can be indexed any number of times if (tokenizer->get_token() == GDScriptTokenizer::TK_PERIOD) { - //indexing using "." if (tokenizer->get_token(1) != GDScriptTokenizer::TK_CURSOR && !tokenizer->is_token_literal(1)) { @@ -1211,8 +1193,9 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s _make_completable_call(0); completion_node = op; } - if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant)) + if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant)) { return nullptr; + } expr = op; } else { @@ -1224,7 +1207,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s StringName identifier; if (_get_completable_identifier(COMPLETION_INDEX, identifier)) { - if (identifier == StringName()) { identifier = "@temp"; //so it parses alright } @@ -1264,8 +1246,9 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(1); expr = op; - } else + } else { break; + } } /*****************/ @@ -1319,25 +1302,55 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s switch (tokenizer->get_token()) { //see operator - case GDScriptTokenizer::TK_OP_IN: op = OperatorNode::OP_IN; break; - case GDScriptTokenizer::TK_OP_EQUAL: op = OperatorNode::OP_EQUAL; break; - case GDScriptTokenizer::TK_OP_NOT_EQUAL: op = OperatorNode::OP_NOT_EQUAL; break; - case GDScriptTokenizer::TK_OP_LESS: op = OperatorNode::OP_LESS; break; - case GDScriptTokenizer::TK_OP_LESS_EQUAL: op = OperatorNode::OP_LESS_EQUAL; break; - case GDScriptTokenizer::TK_OP_GREATER: op = OperatorNode::OP_GREATER; break; - case GDScriptTokenizer::TK_OP_GREATER_EQUAL: op = OperatorNode::OP_GREATER_EQUAL; break; - case GDScriptTokenizer::TK_OP_AND: op = OperatorNode::OP_AND; break; - case GDScriptTokenizer::TK_OP_OR: op = OperatorNode::OP_OR; break; - case GDScriptTokenizer::TK_OP_ADD: op = OperatorNode::OP_ADD; break; - case GDScriptTokenizer::TK_OP_SUB: op = OperatorNode::OP_SUB; break; - case GDScriptTokenizer::TK_OP_MUL: op = OperatorNode::OP_MUL; break; - case GDScriptTokenizer::TK_OP_DIV: op = OperatorNode::OP_DIV; break; + case GDScriptTokenizer::TK_OP_IN: + op = OperatorNode::OP_IN; + break; + case GDScriptTokenizer::TK_OP_EQUAL: + op = OperatorNode::OP_EQUAL; + break; + case GDScriptTokenizer::TK_OP_NOT_EQUAL: + op = OperatorNode::OP_NOT_EQUAL; + break; + case GDScriptTokenizer::TK_OP_LESS: + op = OperatorNode::OP_LESS; + break; + case GDScriptTokenizer::TK_OP_LESS_EQUAL: + op = OperatorNode::OP_LESS_EQUAL; + break; + case GDScriptTokenizer::TK_OP_GREATER: + op = OperatorNode::OP_GREATER; + break; + case GDScriptTokenizer::TK_OP_GREATER_EQUAL: + op = OperatorNode::OP_GREATER_EQUAL; + break; + case GDScriptTokenizer::TK_OP_AND: + op = OperatorNode::OP_AND; + break; + case GDScriptTokenizer::TK_OP_OR: + op = OperatorNode::OP_OR; + break; + case GDScriptTokenizer::TK_OP_ADD: + op = OperatorNode::OP_ADD; + break; + case GDScriptTokenizer::TK_OP_SUB: + op = OperatorNode::OP_SUB; + break; + case GDScriptTokenizer::TK_OP_MUL: + op = OperatorNode::OP_MUL; + break; + case GDScriptTokenizer::TK_OP_DIV: + op = OperatorNode::OP_DIV; + break; case GDScriptTokenizer::TK_OP_MOD: op = OperatorNode::OP_MOD; break; //case GDScriptTokenizer::TK_OP_NEG: op=OperatorNode::OP_NEG ; break; - case GDScriptTokenizer::TK_OP_SHIFT_LEFT: op = OperatorNode::OP_SHIFT_LEFT; break; - case GDScriptTokenizer::TK_OP_SHIFT_RIGHT: op = OperatorNode::OP_SHIFT_RIGHT; break; + case GDScriptTokenizer::TK_OP_SHIFT_LEFT: + op = OperatorNode::OP_SHIFT_LEFT; + break; + case GDScriptTokenizer::TK_OP_SHIFT_RIGHT: + op = OperatorNode::OP_SHIFT_RIGHT; + break; case GDScriptTokenizer::TK_OP_ASSIGN: { _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN; @@ -1354,23 +1367,57 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } } break; - case GDScriptTokenizer::TK_OP_ASSIGN_ADD: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_ADD; break; - case GDScriptTokenizer::TK_OP_ASSIGN_SUB: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_SUB; break; - case GDScriptTokenizer::TK_OP_ASSIGN_MUL: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_MUL; break; - case GDScriptTokenizer::TK_OP_ASSIGN_DIV: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_DIV; break; - case GDScriptTokenizer::TK_OP_ASSIGN_MOD: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_MOD; break; - case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_LEFT: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_SHIFT_LEFT; break; - case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_SHIFT_RIGHT; break; - case GDScriptTokenizer::TK_OP_ASSIGN_BIT_AND: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_BIT_AND; break; - case GDScriptTokenizer::TK_OP_ASSIGN_BIT_OR: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_BIT_OR; break; - case GDScriptTokenizer::TK_OP_ASSIGN_BIT_XOR: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_BIT_XOR; break; - case GDScriptTokenizer::TK_OP_BIT_AND: op = OperatorNode::OP_BIT_AND; break; - case GDScriptTokenizer::TK_OP_BIT_OR: op = OperatorNode::OP_BIT_OR; break; - case GDScriptTokenizer::TK_OP_BIT_XOR: op = OperatorNode::OP_BIT_XOR; break; - case GDScriptTokenizer::TK_PR_IS: op = OperatorNode::OP_IS; break; - case GDScriptTokenizer::TK_CF_IF: op = OperatorNode::OP_TERNARY_IF; break; - case GDScriptTokenizer::TK_CF_ELSE: op = OperatorNode::OP_TERNARY_ELSE; break; - default: valid = false; break; + case GDScriptTokenizer::TK_OP_ASSIGN_ADD: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_ADD; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_SUB: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_SUB; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_MUL: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_MUL; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_DIV: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_DIV; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_MOD: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_MOD; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_LEFT: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_SHIFT_LEFT; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_SHIFT_RIGHT; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_BIT_AND: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_BIT_AND; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_BIT_OR: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_BIT_OR; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_BIT_XOR: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_BIT_XOR; + break; + case GDScriptTokenizer::TK_OP_BIT_AND: + op = OperatorNode::OP_BIT_AND; + break; + case GDScriptTokenizer::TK_OP_BIT_OR: + op = OperatorNode::OP_BIT_OR; + break; + case GDScriptTokenizer::TK_OP_BIT_XOR: + op = OperatorNode::OP_BIT_XOR; + break; + case GDScriptTokenizer::TK_PR_IS: + op = OperatorNode::OP_IS; + break; + case GDScriptTokenizer::TK_CF_IF: + op = OperatorNode::OP_TERNARY_IF; + break; + case GDScriptTokenizer::TK_CF_ELSE: + op = OperatorNode::OP_TERNARY_ELSE; + break; + default: + valid = false; + break; } if (valid) { @@ -1386,16 +1433,13 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */ while (expression.size() > 1) { - int next_op = -1; int min_priority = 0xFFFFF; bool is_unary = false; bool is_ternary = false; for (int i = 0; i < expression.size(); i++) { - if (!expression[i].is_op) { - continue; } @@ -1407,7 +1451,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s bool right_to_left = false; switch (expression[i].op) { - case OperatorNode::OP_IS: case OperatorNode::OP_IS_BUILTIN: priority = -1; @@ -1423,36 +1466,74 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s unary = true; break; - case OperatorNode::OP_MUL: priority = 2; break; - case OperatorNode::OP_DIV: priority = 2; break; - case OperatorNode::OP_MOD: priority = 2; break; + case OperatorNode::OP_MUL: + priority = 2; + break; + case OperatorNode::OP_DIV: + priority = 2; + break; + case OperatorNode::OP_MOD: + priority = 2; + break; - case OperatorNode::OP_ADD: priority = 3; break; - case OperatorNode::OP_SUB: priority = 3; break; + case OperatorNode::OP_ADD: + priority = 3; + break; + case OperatorNode::OP_SUB: + priority = 3; + break; - case OperatorNode::OP_SHIFT_LEFT: priority = 4; break; - case OperatorNode::OP_SHIFT_RIGHT: priority = 4; break; + case OperatorNode::OP_SHIFT_LEFT: + priority = 4; + break; + case OperatorNode::OP_SHIFT_RIGHT: + priority = 4; + break; - case OperatorNode::OP_BIT_AND: priority = 5; break; - case OperatorNode::OP_BIT_XOR: priority = 6; break; - case OperatorNode::OP_BIT_OR: priority = 7; break; + case OperatorNode::OP_BIT_AND: + priority = 5; + break; + case OperatorNode::OP_BIT_XOR: + priority = 6; + break; + case OperatorNode::OP_BIT_OR: + priority = 7; + break; - case OperatorNode::OP_LESS: priority = 8; break; - case OperatorNode::OP_LESS_EQUAL: priority = 8; break; - case OperatorNode::OP_GREATER: priority = 8; break; - case OperatorNode::OP_GREATER_EQUAL: priority = 8; break; + case OperatorNode::OP_LESS: + priority = 8; + break; + case OperatorNode::OP_LESS_EQUAL: + priority = 8; + break; + case OperatorNode::OP_GREATER: + priority = 8; + break; + case OperatorNode::OP_GREATER_EQUAL: + priority = 8; + break; - case OperatorNode::OP_EQUAL: priority = 8; break; - case OperatorNode::OP_NOT_EQUAL: priority = 8; break; + case OperatorNode::OP_EQUAL: + priority = 8; + break; + case OperatorNode::OP_NOT_EQUAL: + priority = 8; + break; - case OperatorNode::OP_IN: priority = 10; break; + case OperatorNode::OP_IN: + priority = 10; + break; case OperatorNode::OP_NOT: priority = 11; unary = true; break; - case OperatorNode::OP_AND: priority = 12; break; - case OperatorNode::OP_OR: priority = 13; break; + case OperatorNode::OP_AND: + priority = 12; + break; + case OperatorNode::OP_OR: + priority = 13; + break; case OperatorNode::OP_TERNARY_IF: priority = 14; @@ -1465,17 +1546,39 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s // Rigth-to-left should be false in this case, otherwise it would always error. break; - case OperatorNode::OP_ASSIGN: priority = 15; break; - case OperatorNode::OP_ASSIGN_ADD: priority = 15; break; - case OperatorNode::OP_ASSIGN_SUB: priority = 15; break; - case OperatorNode::OP_ASSIGN_MUL: priority = 15; break; - case OperatorNode::OP_ASSIGN_DIV: priority = 15; break; - case OperatorNode::OP_ASSIGN_MOD: priority = 15; break; - case OperatorNode::OP_ASSIGN_SHIFT_LEFT: priority = 15; break; - case OperatorNode::OP_ASSIGN_SHIFT_RIGHT: priority = 15; break; - case OperatorNode::OP_ASSIGN_BIT_AND: priority = 15; break; - case OperatorNode::OP_ASSIGN_BIT_OR: priority = 15; break; - case OperatorNode::OP_ASSIGN_BIT_XOR: priority = 15; break; + case OperatorNode::OP_ASSIGN: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_ADD: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_SUB: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_MUL: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_DIV: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_MOD: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_SHIFT_LEFT: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_SHIFT_RIGHT: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_BIT_AND: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_BIT_OR: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_BIT_XOR: + priority = 15; + break; default: { _set_error("GDScriptParser bug, invalid operator in expression: " + itos(expression[i].op)); @@ -1498,17 +1601,14 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } if (next_op == -1) { - _set_error("Yet another parser bug...."); ERR_FAIL_V(nullptr); } // OK! create operator.. if (is_unary) { - int expr_pos = next_op; while (expression[expr_pos].is_op) { - expr_pos++; if (expr_pos == expression.size()) { //can happen.. @@ -1519,7 +1619,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s //consecutively do unary operators for (int i = expr_pos - 1; i >= next_op; i--) { - OperatorNode *op = alloc_node<OperatorNode>(); op->op = expression[i].op; op->arguments.push_back(expression[i + 1].node); @@ -1549,7 +1648,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s op->line = op_line; //line might have been changed from a \n if (expression[next_op - 1].is_op) { - _set_error("Parser bug..."); ERR_FAIL_V(nullptr); } @@ -1585,7 +1683,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s expression.remove(next_op); expression.remove(next_op); } else { - if (next_op < 1 || next_op >= (expression.size() - 1)) { _set_error("Parser bug..."); ERR_FAIL_V(nullptr); @@ -1596,7 +1693,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s op->line = op_line; //line might have been changed from a \n if (expression[next_op - 1].is_op) { - _set_error("Parser bug..."); ERR_FAIL_V(nullptr); } @@ -1625,23 +1721,20 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to_const) { - switch (p_node->type) { - case Node::TYPE_BUILT_IN_FUNCTION: { //many may probably be optimizable return p_node; } break; case Node::TYPE_ARRAY: { - ArrayNode *an = static_cast<ArrayNode *>(p_node); bool all_constants = true; for (int i = 0; i < an->elements.size(); i++) { - an->elements.write[i] = _reduce_expression(an->elements[i], p_to_const); - if (an->elements[i]->type != Node::TYPE_CONSTANT) + if (an->elements[i]->type != Node::TYPE_CONSTANT) { all_constants = false; + } } if (all_constants && p_to_const) { @@ -1663,18 +1756,18 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to } break; case Node::TYPE_DICTIONARY: { - DictionaryNode *dn = static_cast<DictionaryNode *>(p_node); bool all_constants = true; for (int i = 0; i < dn->elements.size(); i++) { - dn->elements.write[i].key = _reduce_expression(dn->elements[i].key, p_to_const); - if (dn->elements[i].key->type != Node::TYPE_CONSTANT) + if (dn->elements[i].key->type != Node::TYPE_CONSTANT) { all_constants = false; + } dn->elements.write[i].value = _reduce_expression(dn->elements[i].value, p_to_const); - if (dn->elements[i].value->type != Node::TYPE_CONSTANT) + if (dn->elements[i].value->type != Node::TYPE_CONSTANT) { all_constants = false; + } } if (all_constants && p_to_const) { @@ -1697,14 +1790,12 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to } break; case Node::TYPE_OPERATOR: { - OperatorNode *op = static_cast<OperatorNode *>(p_node); bool all_constants = true; int last_not_constant = -1; for (int i = 0; i < op->arguments.size(); i++) { - op->arguments.write[i] = _reduce_expression(op->arguments[i], p_to_const); if (op->arguments[i]->type != Node::TYPE_CONSTANT) { all_constants = false; @@ -1723,15 +1814,12 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to } else if (op->op == OperatorNode::OP_CALL) { //can reduce base type constructors if ((op->arguments[0]->type == Node::TYPE_TYPE || (op->arguments[0]->type == Node::TYPE_BUILT_IN_FUNCTION && GDScriptFunctions::is_deterministic(static_cast<BuiltInFunctionNode *>(op->arguments[0])->function))) && last_not_constant == 0) { - //native type constructor or intrinsic function const Variant **vptr = nullptr; Vector<Variant *> ptrs; if (op->arguments.size() > 1) { - ptrs.resize(op->arguments.size() - 1); for (int i = 0; i < ptrs.size(); i++) { - ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[i + 1]); ptrs.write[i] = &cn->value; } @@ -1752,7 +1840,6 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to } if (ce.error != Callable::CallError::CALL_OK) { - String errwhere; if (op->arguments[0]->type == Node::TYPE_TYPE) { TypeNode *tn = static_cast<TypeNode *>(op->arguments[0]); @@ -1764,18 +1851,14 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to } switch (ce.error) { - case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: { - _set_error("Invalid argument (#" + itos(ce.argument + 1) + ") for " + errwhere + "."); } break; case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { - _set_error("Too many arguments for " + errwhere + "."); } break; case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: { - _set_error("Too few arguments for " + errwhere + "."); } break; default: { @@ -1804,7 +1887,6 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to //can reduce indices into constant arrays or dictionaries if (all_constants) { - ConstantNode *ca = static_cast<ConstantNode *>(op->arguments[0]); ConstantNode *cb = static_cast<ConstantNode *>(op->arguments[1]); @@ -1826,9 +1908,7 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to return op; } else if (op->op == OperatorNode::OP_INDEX_NAMED) { - if (op->arguments[0]->type == Node::TYPE_CONSTANT && op->arguments[1]->type == Node::TYPE_IDENTIFIER) { - ConstantNode *ca = static_cast<ConstantNode *>(op->arguments[0]); IdentifierNode *ib = static_cast<IdentifierNode *>(op->arguments[1]); @@ -1851,7 +1931,6 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to //validate assignment (don't assign to constant expression switch (op->op) { - case OperatorNode::OP_ASSIGN: case OperatorNode::OP_ASSIGN_ADD: case OperatorNode::OP_ASSIGN_SUB: @@ -1863,7 +1942,6 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to case OperatorNode::OP_ASSIGN_BIT_AND: case OperatorNode::OP_ASSIGN_BIT_OR: case OperatorNode::OP_ASSIGN_BIT_XOR: { - if (op->arguments[0]->type == Node::TYPE_CONSTANT) { _set_error("Can't assign to constant", tokenizer->get_token_line() - 1); error_line = op->line; @@ -1889,8 +1967,9 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to } } //now se if all are constants - if (!all_constants) + if (!all_constants) { return op; //nothing to reduce from here on + } #define _REDUCE_UNARY(m_vop) \ bool valid = false; \ Variant res; \ @@ -1920,7 +1999,6 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to return cn; switch (op->op) { - //unary operators case OperatorNode::OP_NEG: { _REDUCE_UNARY(Variant::OP_NEGATE); @@ -2012,18 +2090,53 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to } GDScriptParser::Node *GDScriptParser::_parse_and_reduce_expression(Node *p_parent, bool p_static, bool p_reduce_const, bool p_allow_assign) { - Node *expr = _parse_expression(p_parent, p_static, p_allow_assign, p_reduce_const); - if (!expr || error_set) + if (!expr || error_set) { return nullptr; + } expr = _reduce_expression(expr, p_reduce_const); - if (!expr || error_set) + if (!expr || error_set) { return nullptr; + } return expr; } -bool GDScriptParser::_recover_from_completion() { +bool GDScriptParser::_reduce_export_var_type(Variant &p_value, int p_line) { + if (p_value.get_type() == Variant::ARRAY) { + Array arr = p_value; + for (int i = 0; i < arr.size(); i++) { + if (!_reduce_export_var_type(arr[i], p_line)) { + return false; + } + } + return true; + } + + if (p_value.get_type() == Variant::DICTIONARY) { + Dictionary dict = p_value; + for (int i = 0; i < dict.size(); i++) { + Variant value = dict.get_value_at_index(i); + if (!_reduce_export_var_type(value, p_line)) { + return false; + } + } + return true; + } + + // validate type + DataType type = _type_from_variant(p_value); + if (type.kind == DataType::BUILTIN) { + return true; + } else if (type.kind == DataType::NATIVE) { + if (ClassDB::is_parent_class(type.native_type, "Resource")) { + return true; + } + } + _set_error("Invalid export type. Only built-in and native resource types can be exported.", p_line); + return false; +} +bool GDScriptParser::_recover_from_completion() { if (!completion_found) { return false; //can't recover if no completion } @@ -2041,12 +2154,12 @@ bool GDScriptParser::_recover_from_completion() { } GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { - PatternNode *pattern = alloc_node<PatternNode>(); GDScriptTokenizer::Token token = tokenizer->get_token(); - if (error_set) + if (error_set) { return nullptr; + } if (token == GDScriptTokenizer::TK_EOF) { return nullptr; @@ -2058,7 +2171,6 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { tokenizer->advance(); pattern->pt_type = GDScriptParser::PatternNode::PT_ARRAY; while (true) { - if (tokenizer->get_token() == GDScriptTokenizer::TK_BRACKET_CLOSE) { tokenizer->advance(); break; @@ -2130,7 +2242,6 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { tokenizer->advance(); pattern->pt_type = GDScriptParser::PatternNode::PT_DICTIONARY; while (true) { - if (tokenizer->get_token() == GDScriptTokenizer::TK_CURLY_BRACKET_CLOSE) { tokenizer->advance(); break; @@ -2243,13 +2354,14 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran bool catch_all_appeared = false; while (true) { - - while (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE && _parse_newline()) + while (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE && _parse_newline()) { ; + } // GDScriptTokenizer::Token token = tokenizer->get_token(); - if (error_set) + if (error_set) { return; + } if (current_level.indent > indent_level.back()->get().indent) { break; // go back a level @@ -2321,12 +2433,10 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran } void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_match, Node *&p_resulting_node, Map<StringName, Node *> &p_bindings) { - const DataType &to_match_type = p_node_to_match->get_datatype(); switch (p_pattern->pt_type) { case PatternNode::PT_CONSTANT: { - DataType pattern_type = _reduce_node_type(p_pattern->constant); if (error_set) { return; @@ -2386,10 +2496,10 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m // a bind always matches ConstantNode *true_value = alloc_node<ConstantNode>(); true_value->value = Variant(true); + true_value->datatype = _type_from_variant(true_value->value); p_resulting_node = true_value; } break; case PatternNode::PT_ARRAY: { - bool open_ended = false; if (p_pattern->array.size() > 0) { @@ -2432,6 +2542,7 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m // size ConstantNode *length = alloc_node<ConstantNode>(); length->value = Variant(open_ended ? p_pattern->array.size() - 1 : p_pattern->array.size()); + length->datatype = _type_from_variant(length->value); OperatorNode *call = alloc_node<OperatorNode>(); call->op = OperatorNode::OP_CALL; @@ -2465,6 +2576,7 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m ConstantNode *index = alloc_node<ConstantNode>(); index->value = Variant(i); + index->datatype = _type_from_variant(index->value); OperatorNode *indexed_value = alloc_node<OperatorNode>(); indexed_value->op = OperatorNode::OP_INDEX; @@ -2484,7 +2596,6 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m } break; case PatternNode::PT_DICTIONARY: { - bool open_ended = false; if (p_pattern->array.size() > 0) { @@ -2525,6 +2636,7 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m // size ConstantNode *length = alloc_node<ConstantNode>(); length->value = Variant(open_ended ? p_pattern->dictionary.size() - 1 : p_pattern->dictionary.size()); + length->datatype = _type_from_variant(length->value); OperatorNode *call = alloc_node<OperatorNode>(); call->op = OperatorNode::OP_CALL; @@ -2552,7 +2664,6 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m } for (Map<ConstantNode *, PatternNode *>::Element *e = p_pattern->dictionary.front(); e; e = e->next()) { - Node *condition = nullptr; // check for has, then for pattern @@ -2567,7 +2678,6 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m has_call->arguments.push_back(e->key()); if (e->value()) { - OperatorNode *indexed_value = alloc_node<OperatorNode>(); indexed_value->op = OperatorNode::OP_INDEX; indexed_value->arguments.push_back(p_node_to_match); @@ -2601,10 +2711,10 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m // simply generate a `true` ConstantNode *true_value = alloc_node<ConstantNode>(); true_value->value = Variant(true); + true_value->datatype = _type_from_variant(true_value->value); p_resulting_node = true_value; } break; default: { - } break; } } @@ -2625,7 +2735,6 @@ void GDScriptParser::_transform_match_statment(MatchNode *p_match_statement) { } for (int i = 0; i < p_match_statement->branches.size(); i++) { - PatternBranchNode *branch = p_match_statement->branches[i]; MatchNode::CompiledPatternBranch compiled_branch; @@ -2683,9 +2792,11 @@ void GDScriptParser::_transform_match_statment(MatchNode *p_match_statement) { LocalVarNode *local_var = branch->body->variables[e->key()]; local_var->assign = e->value(); local_var->set_datatype(local_var->assign->get_datatype()); + local_var->assignments++; IdentifierNode *id2 = alloc_node<IdentifierNode>(); id2->name = local_var->name; + id2->datatype = local_var->datatype; id2->declared_block = branch->body; id2->set_datatype(local_var->assign->get_datatype()); @@ -2706,11 +2817,12 @@ void GDScriptParser::_transform_match_statment(MatchNode *p_match_statement) { } void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { - IndentLevel current_level = indent_level.back()->get(); #ifdef DEBUG_ENABLED + pending_newline = -1; // reset for the new block + NewLineNode *nl = alloc_node<NewLineNode>(); nl->line = tokenizer->get_token_line(); @@ -2733,8 +2845,9 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { is_first_line = false; GDScriptTokenizer::Token token = tokenizer->get_token(); - if (error_set) + if (error_set) { return; + } if (current_level.indent > indent_level.back()->get().indent) { p_block->end_line = tokenizer->get_token_line(); @@ -2742,7 +2855,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } if (pending_newline != -1) { - NewLineNode *nl2 = alloc_node<NewLineNode>(); nl2->line = pending_newline; p_block->statements.push_back(nl2); @@ -2774,7 +2886,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { return; } break; case GDScriptTokenizer::TK_NEWLINE: { - int line = tokenizer->get_token_line(); if (!_parse_newline()) { @@ -2785,6 +2896,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { return; } + _mark_line_as_safe(line); NewLineNode *nl2 = alloc_node<NewLineNode>(); nl2->line = line; p_block->statements.push_back(nl2); @@ -2792,7 +2904,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } break; case GDScriptTokenizer::TK_CF_PASS: { if (tokenizer->get_token(1) != GDScriptTokenizer::TK_SEMICOLON && tokenizer->get_token(1) != GDScriptTokenizer::TK_NEWLINE && tokenizer->get_token(1) != GDScriptTokenizer::TK_EOF) { - _set_error("Expected \";\" or a line break."); return; } @@ -2809,7 +2920,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { tokenizer->advance(); int var_line = tokenizer->get_token_line(); if (!tokenizer->is_token_literal(0, true)) { - _set_error("Expected an identifier for the local variable name."); return; } @@ -2854,7 +2964,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) { - tokenizer->advance(); Node *subexpr = _parse_and_reduce_expression(p_block, p_static); if (!subexpr) { @@ -2867,7 +2976,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { lv->assignments++; assigned = subexpr; } else { - assigned = _get_default_value_for_type(lv->datatype, var_line); } //must be added later, to avoid self-referencing. @@ -2888,13 +2996,12 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { lv->assign = assigned; if (!_end_statement()) { - _set_error("Expected end of statement (\"var\")."); + _set_end_statement_error("var"); return; } } break; case GDScriptTokenizer::TK_CF_IF: { - tokenizer->advance(); Node *condition = _parse_and_reduce_expression(p_block, p_static); @@ -2926,17 +3033,18 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { _parse_block(cf_if->body, p_static); current_block = p_block; - if (error_set) + if (error_set) { return; + } p_block->statements.push_back(cf_if); bool all_have_return = cf_if->body->has_return; bool have_else = false; while (true) { - - while (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE && _parse_newline()) + while (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE && _parse_newline()) { ; + } if (indent_level.back()->get().indent < current_level.indent) { //not at current indent level p_block->end_line = tokenizer->get_token_line(); @@ -2944,9 +3052,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } if (tokenizer->get_token() == GDScriptTokenizer::TK_CF_ELIF) { - if (indent_level.back()->get().indent > current_level.indent) { - _set_error("Invalid indentation."); return; } @@ -2986,13 +3092,13 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { current_block = cf_else->body; _parse_block(cf_else->body, p_static); current_block = p_block; - if (error_set) + if (error_set) { return; + } all_have_return = all_have_return && cf_else->body->has_return; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CF_ELSE) { - if (indent_level.back()->get().indent > current_level.indent) { _set_error("Invalid indentation."); return; @@ -3011,16 +3117,18 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { current_block = cf_if->body_else; _parse_block(cf_if->body_else, p_static); current_block = p_block; - if (error_set) + if (error_set) { return; + } all_have_return = all_have_return && cf_if->body_else->has_return; have_else = true; break; //after else, exit - } else + } else { break; + } } cf_if->body->has_return = all_have_return; @@ -3029,7 +3137,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } break; case GDScriptTokenizer::TK_CF_WHILE: { - tokenizer->advance(); Node *condition2 = _parse_and_reduce_expression(p_block, p_static); if (!condition2) { @@ -3046,6 +3153,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { cf_while->body = alloc_node<BlockNode>(); cf_while->body->parent_block = p_block; + cf_while->body->can_break = true; + cf_while->body->can_continue = true; p_block->sub_blocks.push_back(cf_while->body); if (!_enter_indent_block(cf_while->body)) { @@ -3057,23 +3166,30 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { current_block = cf_while->body; _parse_block(cf_while->body, p_static); current_block = p_block; - if (error_set) + if (error_set) { return; - p_block->has_return = cf_while->body->has_return; + } p_block->statements.push_back(cf_while); } break; case GDScriptTokenizer::TK_CF_FOR: { - tokenizer->advance(); if (!tokenizer->is_token_literal(0, true)) { - _set_error("Identifier expected after \"for\"."); } IdentifierNode *id = alloc_node<IdentifierNode>(); id->name = tokenizer->get_token_identifier(); + BlockNode *check_block = p_block; + while (check_block) { + if (check_block->variables.has(id->name)) { + _set_error("Variable \"" + String(id->name) + "\" already defined in the scope (at line " + itos(check_block->variables[id->name]->line) + ")."); + return; + } + check_block = check_block->parent_block; + } + tokenizer->advance(); if (tokenizer->get_token() != GDScriptTokenizer::TK_OP_IN) { @@ -3094,7 +3210,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { DataType iter_type; if (container->type == Node::TYPE_OPERATOR) { - OperatorNode *op = static_cast<OperatorNode *>(container); if (op->op == OperatorNode::OP_CALL && op->arguments[0]->type == Node::TYPE_BUILT_IN_FUNCTION && static_cast<BuiltInFunctionNode *>(op->arguments[0])->function == GDScriptFunctions::GEN_RANGE) { //iterating a range, so see if range() can be optimized without allocating memory, by replacing it by vectors (which can work as iterable too!) @@ -3110,6 +3225,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { ConstantNode *c = static_cast<ConstantNode *>(op->arguments[i]); if (c->value.get_type() == Variant::FLOAT || c->value.get_type() == Variant::INT) { constants.push_back(c->value); + } else { + constant = false; } } else { constant = false; @@ -3117,14 +3234,18 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } if (args.size() > 0 && args.size() < 4) { - if (constant) { - ConstantNode *cn = alloc_node<ConstantNode>(); switch (args.size()) { - case 1: cn->value = (int)constants[0]; break; - case 2: cn->value = Vector2(constants[0], constants[1]); break; - case 3: cn->value = Vector3(constants[0], constants[1], constants[2]); break; + case 1: + cn->value = (int64_t)constants[0]; + break; + case 2: + cn->value = Vector2i(constants[0], constants[1]); + break; + case 3: + cn->value = Vector3i(constants[0], constants[1], constants[2]); + break; } cn->datatype = _type_from_variant(cn->value); container = cn; @@ -3136,9 +3257,15 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { on->arguments.push_back(tn); switch (args.size()) { - case 1: tn->vtype = Variant::INT; break; - case 2: tn->vtype = Variant::VECTOR2; break; - case 3: tn->vtype = Variant::VECTOR3; break; + case 1: + tn->vtype = Variant::INT; + break; + case 2: + tn->vtype = Variant::VECTOR2I; + break; + case 3: + tn->vtype = Variant::VECTOR3I; + break; } for (int i = 0; i < args.size(); i++) { @@ -3163,6 +3290,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { cf_for->body = alloc_node<BlockNode>(); cf_for->body->parent_block = p_block; + cf_for->body->can_break = true; + cf_for->body->can_continue = true; p_block->sub_blocks.push_back(cf_for->body); if (!_enter_indent_block(cf_for->body)) { @@ -3186,12 +3315,26 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { _parse_block(cf_for->body, p_static); current_block = p_block; - if (error_set) + if (error_set) { return; - p_block->has_return = cf_for->body->has_return; + } p_block->statements.push_back(cf_for); } break; case GDScriptTokenizer::TK_CF_CONTINUE: { + BlockNode *upper_block = p_block; + bool is_continue_valid = false; + while (upper_block) { + if (upper_block->can_continue) { + is_continue_valid = true; + break; + } + upper_block = upper_block->parent_block; + } + + if (!is_continue_valid) { + _set_error("Unexpected keyword \"continue\" outside a loop."); + return; + } _mark_line_as_safe(tokenizer->get_token_line()); tokenizer->advance(); @@ -3199,11 +3342,25 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { cf_continue->cf_type = ControlFlowNode::CF_CONTINUE; p_block->statements.push_back(cf_continue); if (!_end_statement()) { - _set_error("Expected end of statement (\"continue\")."); + _set_end_statement_error("continue"); return; } } break; case GDScriptTokenizer::TK_CF_BREAK: { + BlockNode *upper_block = p_block; + bool is_break_valid = false; + while (upper_block) { + if (upper_block->can_break) { + is_break_valid = true; + break; + } + upper_block = upper_block->parent_block; + } + + if (!is_break_valid) { + _set_error("Unexpected keyword \"break\" outside a loop."); + return; + } _mark_line_as_safe(tokenizer->get_token_line()); tokenizer->advance(); @@ -3211,12 +3368,11 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { cf_break->cf_type = ControlFlowNode::CF_BREAK; p_block->statements.push_back(cf_break); if (!_end_statement()) { - _set_error("Expected end of statement (\"break\")."); + _set_end_statement_error("break"); return; } } break; case GDScriptTokenizer::TK_CF_RETURN: { - tokenizer->advance(); ControlFlowNode *cf_return = alloc_node<ControlFlowNode>(); cf_return->cf_type = ControlFlowNode::CF_RETURN; @@ -3240,7 +3396,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { cf_return->arguments.push_back(retexpr); p_block->statements.push_back(cf_return); if (!_end_statement()) { - _set_error("Expected end of statement after return expression."); + _set_end_statement_error("return"); return; } } @@ -3248,7 +3404,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } break; case GDScriptTokenizer::TK_CF_MATCH: { - tokenizer->advance(); MatchNode *match_node = alloc_node<MatchNode>(); @@ -3272,12 +3427,15 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { BlockNode *compiled_branches = alloc_node<BlockNode>(); compiled_branches->parent_block = p_block; compiled_branches->parent_class = p_block->parent_class; + compiled_branches->can_continue = true; p_block->sub_blocks.push_back(compiled_branches); _parse_pattern_block(compiled_branches, match_node->branches, p_static); - if (error_set) return; + if (error_set) { + return; + } ControlFlowNode *match_cf_node = alloc_node<ControlFlowNode>(); match_cf_node->cf_type = ControlFlowNode::CF_MATCH; @@ -3290,7 +3448,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { _end_statement(); } break; case GDScriptTokenizer::TK_PR_ASSERT: { - tokenizer->advance(); if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) { @@ -3298,6 +3455,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { return; } + int assert_line = tokenizer->get_token_line(); + tokenizer->advance(); Vector<Node *> args; @@ -3307,41 +3466,41 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } if (args.empty() || args.size() > 2) { - _set_error("Wrong number of arguments, expected 1 or 2"); + _set_error("Wrong number of arguments, expected 1 or 2", assert_line); return; } AssertNode *an = alloc_node<AssertNode>(); an->condition = _reduce_expression(args[0], p_static); + an->line = assert_line; if (args.size() == 2) { an->message = _reduce_expression(args[1], p_static); } else { ConstantNode *message_node = alloc_node<ConstantNode>(); message_node->value = String(); + message_node->datatype = _type_from_variant(message_node->value); an->message = message_node; } p_block->statements.push_back(an); if (!_end_statement()) { - _set_error("Expected end of statement after \"assert\"."); + _set_end_statement_error("assert"); return; } } break; case GDScriptTokenizer::TK_PR_BREAKPOINT: { - tokenizer->advance(); BreakpointNode *bn = alloc_node<BreakpointNode>(); p_block->statements.push_back(bn); if (!_end_statement()) { - _set_error("Expected end of statement after \"breakpoint\"."); + _set_end_statement_error("breakpoint"); return; } } break; default: { - Node *expression = _parse_and_reduce_expression(p_block, p_static, false, true); if (!expression) { if (_recover_from_completion()) { @@ -3355,7 +3514,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON && tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) { _set_error("Unexpected ':=', use '=' instead. Expected end of statement after expression."); } else { - _set_error(String() + "Expected end of statement after expression, got " + tokenizer->get_token_name(tokenizer->get_token()) + " instead"); + _set_error(vformat("Expected end of statement after expression, got %s instead.", tokenizer->get_token_name(tokenizer->get_token()))); } return; } @@ -3366,9 +3525,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } bool GDScriptParser::_parse_newline() { - if (tokenizer->get_token(1) != GDScriptTokenizer::TK_EOF && tokenizer->get_token(1) != GDScriptTokenizer::TK_NEWLINE) { - IndentLevel current_level = indent_level.back()->get(); int indent = tokenizer->get_token_line_indent(); int tabs = tokenizer->get_token_line_tab_indent(); @@ -3385,9 +3542,7 @@ bool GDScriptParser::_parse_newline() { } if (indent < current_level.indent) { - while (indent < current_level.indent) { - //exit block if (indent_level.size() == 1) { _set_error("Invalid indentation. Bug?"); @@ -3397,7 +3552,6 @@ bool GDScriptParser::_parse_newline() { indent_level.pop_back(); if (indent_level.back()->get().indent < indent) { - _set_error("Unindent does not match any outer indentation level."); return false; } @@ -3420,15 +3574,12 @@ bool GDScriptParser::_parse_newline() { } void GDScriptParser::_parse_extends(ClassNode *p_class) { - if (p_class->extends_used) { - _set_error("\"extends\" can only be present once per script."); return; } if (!p_class->constant_expressions.empty() || !p_class->subclasses.empty() || !p_class->functions.empty() || !p_class->variables.empty()) { - _set_error("\"extends\" must be used before anything else."); return; } @@ -3445,10 +3596,8 @@ void GDScriptParser::_parse_extends(ClassNode *p_class) { // see if inheritance happens from a file if (tokenizer->get_token() == GDScriptTokenizer::TK_CONSTANT) { - Variant constant = tokenizer->get_token_constant(); if (constant.get_type() != Variant::STRING) { - _set_error("\"extends\" constant must be a string."); return; } @@ -3465,16 +3614,14 @@ void GDScriptParser::_parse_extends(ClassNode *p_class) { if (tokenizer->get_token() != GDScriptTokenizer::TK_PERIOD) { return; - } else + } else { tokenizer->advance(); + } } while (true) { - switch (tokenizer->get_token()) { - case GDScriptTokenizer::TK_IDENTIFIER: { - StringName identifier = tokenizer->get_token_identifier(); p_class->extends_class.push_back(identifier); } break; @@ -3483,7 +3630,6 @@ void GDScriptParser::_parse_extends(ClassNode *p_class) { break; default: { - _set_error("Invalid \"extends\" syntax, expected string constant (path) and/or identifier (parent class)."); return; } @@ -3492,7 +3638,6 @@ void GDScriptParser::_parse_extends(ClassNode *p_class) { tokenizer->advance(1); switch (tokenizer->get_token()) { - case GDScriptTokenizer::TK_IDENTIFIER: case GDScriptTokenizer::TK_PERIOD: continue; @@ -3504,14 +3649,13 @@ void GDScriptParser::_parse_extends(ClassNode *p_class) { } void GDScriptParser::_parse_class(ClassNode *p_class) { - IndentLevel current_level = indent_level.back()->get(); while (true) { - GDScriptTokenizer::Token token = tokenizer->get_token(); - if (error_set) + if (error_set) { return; + } if (current_level.indent > indent_level.back()->get().indent) { p_class->end_line = tokenizer->get_token_line(); @@ -3519,7 +3663,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } switch (token) { - case GDScriptTokenizer::TK_CURSOR: { tokenizer->advance(); } break; @@ -3539,19 +3682,18 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } break; case GDScriptTokenizer::TK_PR_EXTENDS: { - _mark_line_as_safe(tokenizer->get_token_line()); _parse_extends(p_class); - if (error_set) + if (error_set) { return; + } if (!_end_statement()) { - _set_error("Expected end of statement after \"extends\"."); + _set_end_statement_error("extends"); return; } } break; case GDScriptTokenizer::TK_PR_CLASS_NAME: { - _mark_line_as_safe(tokenizer->get_token_line()); if (p_class->owner) { _set_error("\"class_name\" is only valid for the main class namespace."); @@ -3562,7 +3704,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } if (tokenizer->get_token(1) != GDScriptTokenizer::TK_IDENTIFIER) { - _set_error("\"class_name\" syntax: \"class_name <UniqueName>\""); return; } @@ -3628,9 +3769,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } break; case GDScriptTokenizer::TK_PR_TOOL: { - if (p_class->tool) { - _set_error("The \"tool\" keyword can only be present once per script."); return; } @@ -3645,7 +3784,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { StringName name; if (tokenizer->get_token(1) != GDScriptTokenizer::TK_IDENTIFIER) { - _set_error("\"class\" syntax: \"class <Name>:\" or \"class <Name> extends <BaseClass>:\""); return; } @@ -3673,6 +3811,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { _set_error("A constant named \"" + String(name) + "\" already exists in the outer class scope (at line" + itos(outer_class->constant_expressions[name].expression->line) + ")."); return; } + for (int i = 0; i < outer_class->variables.size(); i++) { + if (outer_class->variables[i].identifier == name) { + _set_error("A variable named \"" + String(name) + "\" already exists in the outer class scope (at line " + itos(outer_class->variables[i].line) + ")."); + return; + } + } outer_class = outer_class->owner; } @@ -3688,14 +3832,13 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { p_class->subclasses.push_back(newclass); if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_EXTENDS) { - _parse_extends(newclass); - if (error_set) + if (error_set) { return; + } } if (!_enter_indent_block()) { - _set_error("Indented block expected."); return; } @@ -3713,7 +3856,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { case GDScriptTokenizer::TK_PR_STATIC: { tokenizer->advance(); if (tokenizer->get_token() != GDScriptTokenizer::TK_PR_FUNCTION) { - _set_error("Expected \"func\"."); return; } @@ -3721,12 +3863,10 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { [[fallthrough]]; } case GDScriptTokenizer::TK_PR_FUNCTION: { - bool _static = false; pending_newline = -1; if (tokenizer->get_token(-1) == GDScriptTokenizer::TK_PR_STATIC) { - _static = true; } @@ -3737,7 +3877,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (name == StringName()) { - _set_error("Expected an identifier after \"func\" (syntax: \"func <identifier>([arguments]):\")."); return; } @@ -3770,7 +3909,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { #endif // DEBUG_ENABLED if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) { - _set_error("Expected \"(\" after the identifier (syntax: \"func <identifier>([arguments]):\" )."); return; } @@ -3790,19 +3928,16 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { //has arguments bool defaulting = false; while (true) { - if (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE) { tokenizer->advance(); continue; } if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_VAR) { - tokenizer->advance(); //var before the identifier is allowed } if (!tokenizer->is_token_literal(0, true)) { - _set_error("Expected an identifier for an argument."); return; } @@ -3834,7 +3969,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { argument_types.push_back(argtype); if (defaulting && tokenizer->get_token() != GDScriptTokenizer::TK_OP_ASSIGN) { - _set_error("Default parameter expected."); return; } @@ -3845,8 +3979,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { defaulting = true; tokenizer->advance(1); Node *defval = _parse_and_reduce_expression(p_class, _static); - if (!defval || error_set) + if (!defval || error_set) { return; + } OperatorNode *on = alloc_node<OperatorNode>(); on->op = OperatorNode::OP_ASSIGN; @@ -3875,7 +4010,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); continue; } else if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { - _set_error("Expected \",\" or \")\"."); return; } @@ -3903,14 +4037,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; if (name == "_init") { - if (_static) { _set_error("The constructor cannot be static."); return; } if (p_class->extends_used) { - OperatorNode *cparent = alloc_node<OperatorNode>(); cparent->op = OperatorNode::OP_PARENT_CALL; block->statements.push_back(cparent); @@ -3931,7 +4063,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { //has arguments parenthesis++; while (true) { - current_function = function; Node *arg = _parse_and_reduce_expression(p_class, _static); current_function = nullptr; @@ -3941,7 +4072,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); continue; } else if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { - _set_error("Expected \",\" or \")\"."); return; } @@ -3954,9 +4084,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); } } else { - if (tokenizer->get_token() == GDScriptTokenizer::TK_PERIOD) { - _set_error("Parent constructor call found for a class without inheritance."); return; } @@ -3965,7 +4093,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { DataType return_type; if (tokenizer->get_token() == GDScriptTokenizer::TK_FORWARD_ARROW) { - if (!_parse_type(return_type, true)) { _set_error("Expected a return type for the function."); return; @@ -3973,17 +4100,17 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (!_enter_indent_block(block)) { - - _set_error("Indented block expected."); + _set_error(vformat("Indented block expected after declaration of \"%s\" function.", function->name)); return; } function->return_type = return_type; - if (_static) + if (_static) { p_class->static_functions.push_back(function); - else + } else { p_class->functions.push_back(function); + } current_function = function; function->body = block; @@ -4005,6 +4132,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { sig.name = tokenizer->get_token_identifier(); sig.emissions = 0; sig.line = tokenizer->get_token_line(); + + for (int i = 0; i < current_class->_signals.size(); i++) { + if (current_class->_signals[i].name == sig.name) { + _set_error("The signal \"" + sig.name + "\" already exists in this class (at line: " + itos(current_class->_signals[i].line) + ")."); + return; + } + } + tokenizer->advance(); if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN) { @@ -4044,16 +4179,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { p_class->_signals.push_back(sig); if (!_end_statement()) { - _set_error("Expected end of statement (\"signal\")."); + _set_end_statement_error("signal"); return; } } break; case GDScriptTokenizer::TK_PR_EXPORT: { - tokenizer->advance(); if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN) { - #define _ADVANCE_AND_CONSUME_NEWLINES \ do { \ tokenizer->advance(); \ @@ -4078,7 +4211,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() == GDScriptTokenizer::TK_BUILT_IN_TYPE) { - Variant::Type type = tokenizer->get_token_type(); if (type == Variant::NIL) { _set_error("Can't export null type."); @@ -4097,11 +4229,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { _ADVANCE_AND_CONSUME_NEWLINES; switch (type) { - case Variant::INT: { - if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "FLAGS") { - _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_COMMA) { @@ -4114,7 +4243,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { bool first = true; while (true) { - if (tokenizer->get_token() != GDScriptTokenizer::TK_CONSTANT || tokenizer->get_token_constant().get_type() != Variant::STRING) { current_export = PropertyInfo(); _set_error("Expected a string constant in the named bit flags hint."); @@ -4122,16 +4250,18 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } String c = tokenizer->get_token_constant(); - if (!first) + if (!first) { current_export.hint_string += ","; - else + } else { first = false; + } current_export.hint_string += c.xml_escape(); _ADVANCE_AND_CONSUME_NEWLINES; - if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) + if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { break; + } if (tokenizer->get_token() != GDScriptTokenizer::TK_COMMA) { current_export = PropertyInfo(); @@ -4145,7 +4275,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "LAYERS_2D_RENDER") { - _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected \")\" in the layers 2D render hint."); @@ -4156,7 +4285,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "LAYERS_2D_PHYSICS") { - _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected \")\" in the layers 2D physics hint."); @@ -4167,7 +4295,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "LAYERS_3D_RENDER") { - _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected \")\" in the layers 3D render hint."); @@ -4178,7 +4305,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "LAYERS_3D_PHYSICS") { - _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected \")\" in the layers 3D physics hint."); @@ -4193,25 +4319,25 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { current_export.hint = PROPERTY_HINT_ENUM; bool first = true; while (true) { - if (tokenizer->get_token() != GDScriptTokenizer::TK_CONSTANT || tokenizer->get_token_constant().get_type() != Variant::STRING) { - current_export = PropertyInfo(); _set_error("Expected a string constant in the enumeration hint."); return; } String c = tokenizer->get_token_constant(); - if (!first) + if (!first) { current_export.hint_string += ","; - else + } else { first = false; + } current_export.hint_string += c.xml_escape(); _ADVANCE_AND_CONSUME_NEWLINES; - if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) + if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { break; + } if (tokenizer->get_token() != GDScriptTokenizer::TK_COMMA) { current_export = PropertyInfo(); @@ -4228,7 +4354,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { [[fallthrough]]; } case Variant::FLOAT: { - if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "EASE") { current_export.hint = PROPERTY_HINT_EXP_EASING; _ADVANCE_AND_CONSUME_NEWLINES; @@ -4241,19 +4366,19 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { // range if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "EXP") { - current_export.hint = PROPERTY_HINT_EXP_RANGE; _ADVANCE_AND_CONSUME_NEWLINES; - if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) + if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { break; - else if (tokenizer->get_token() != GDScriptTokenizer::TK_COMMA) { + } else if (tokenizer->get_token() != GDScriptTokenizer::TK_COMMA) { _set_error("Expected \")\" or \",\" in the exponential range hint."); return; } _ADVANCE_AND_CONSUME_NEWLINES; - } else + } else { current_export.hint = PROPERTY_HINT_RANGE; + } float sign = 1.0; @@ -4262,7 +4387,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { _ADVANCE_AND_CONSUME_NEWLINES; } if (tokenizer->get_token() != GDScriptTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) { - current_export = PropertyInfo(); _set_error("Expected a range in the numeric hint."); return; @@ -4277,7 +4401,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() != GDScriptTokenizer::TK_COMMA) { - current_export = PropertyInfo(); _set_error("Expected \",\" or \")\" in the numeric range hint."); return; @@ -4292,7 +4415,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() != GDScriptTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) { - current_export = PropertyInfo(); _set_error("Expected a number as upper bound in the numeric range hint."); return; @@ -4301,11 +4423,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { current_export.hint_string += "," + rtos(sign * double(tokenizer->get_token_constant())); _ADVANCE_AND_CONSUME_NEWLINES; - if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) + if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { break; + } if (tokenizer->get_token() != GDScriptTokenizer::TK_COMMA) { - current_export = PropertyInfo(); _set_error("Expected \",\" or \")\" in the numeric range hint."); return; @@ -4319,7 +4441,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() != GDScriptTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) { - current_export = PropertyInfo(); _set_error("Expected a number as step in the numeric range hint."); return; @@ -4330,30 +4451,29 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } break; case Variant::STRING: { - if (tokenizer->get_token() == GDScriptTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type() == Variant::STRING) { //enumeration current_export.hint = PROPERTY_HINT_ENUM; bool first = true; while (true) { - if (tokenizer->get_token() != GDScriptTokenizer::TK_CONSTANT || tokenizer->get_token_constant().get_type() != Variant::STRING) { - current_export = PropertyInfo(); _set_error("Expected a string constant in the enumeration hint."); return; } String c = tokenizer->get_token_constant(); - if (!first) + if (!first) { current_export.hint_string += ","; - else + } else { first = false; + } current_export.hint_string += c.xml_escape(); _ADVANCE_AND_CONSUME_NEWLINES; - if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) + if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { break; + } if (tokenizer->get_token() != GDScriptTokenizer::TK_COMMA) { current_export = PropertyInfo(); @@ -4367,13 +4487,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "DIR") { - _ADVANCE_AND_CONSUME_NEWLINES; - if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) + if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { current_export.hint = PROPERTY_HINT_DIR; - else if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { - + } else if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_IDENTIFIER || !(tokenizer->get_token_identifier() == "GLOBAL")) { @@ -4399,16 +4517,13 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "FILE") { - current_export.hint = PROPERTY_HINT_FILE; _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { - _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "GLOBAL") { - if (!p_class->tool) { _set_error("Global filesystem hints may only be used in tool scripts."); return; @@ -4416,22 +4531,22 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { current_export.hint = PROPERTY_HINT_GLOBAL_FILE; _ADVANCE_AND_CONSUME_NEWLINES; - if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) + if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { break; - else if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) + } else if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { _ADVANCE_AND_CONSUME_NEWLINES; - else { + } else { _set_error("Expected \")\" or \",\" in the hint."); return; } } if (tokenizer->get_token() != GDScriptTokenizer::TK_CONSTANT || tokenizer->get_token_constant().get_type() != Variant::STRING) { - - if (current_export.hint == PROPERTY_HINT_GLOBAL_FILE) + if (current_export.hint == PROPERTY_HINT_GLOBAL_FILE) { _set_error("Expected string constant with filter."); - else + } else { _set_error("Expected \"GLOBAL\" or string constant with filter."); + } return; } current_export.hint_string = tokenizer->get_token_constant(); @@ -4446,7 +4561,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "MULTILINE") { - current_export.hint = PROPERTY_HINT_MULTILINE_TEXT; _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { @@ -4457,9 +4571,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } break; case Variant::COLOR: { - if (tokenizer->get_token() != GDScriptTokenizer::TK_IDENTIFIER) { - current_export = PropertyInfo(); _set_error("Color type hint expects RGB or RGBA as hints."); return; @@ -4479,7 +4591,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } break; default: { - current_export = PropertyInfo(); _set_error("Type \"" + Variant::get_type_name(type) + "\" can't take hints."); return; @@ -4488,7 +4599,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } else { - parenthesis++; Node *subexpr = _parse_and_reduce_expression(p_class, true, true); if (!subexpr) { @@ -4548,10 +4658,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { bool first = true; for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { if (enum_values[E->get()].get_type() == Variant::INT) { - if (!first) + if (!first) { current_export.hint_string += ","; - else + } else { first = false; + } current_export.hint_string += E->get().operator String().camelcase_to_underscore(true).capitalize().xml_escape(); if (!is_flags) { @@ -4568,7 +4679,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { - current_export = PropertyInfo(); _set_error("Expected \")\" or \",\" after the export hint."); return; @@ -4590,7 +4700,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() != GDScriptTokenizer::TK_PR_VAR && tokenizer->get_token() != GDScriptTokenizer::TK_PR_ONREADY && tokenizer->get_token() != GDScriptTokenizer::TK_PR_REMOTE && tokenizer->get_token() != GDScriptTokenizer::TK_PR_MASTER && tokenizer->get_token() != GDScriptTokenizer::TK_PR_PUPPET && tokenizer->get_token() != GDScriptTokenizer::TK_PR_REMOTESYNC && tokenizer->get_token() != GDScriptTokenizer::TK_PR_MASTERSYNC && tokenizer->get_token() != GDScriptTokenizer::TK_PR_PUPPETSYNC) { - current_export = PropertyInfo(); _set_error("Expected \"var\", \"onready\", \"remote\", \"master\", \"puppet\", \"remotesync\", \"mastersync\", \"puppetsync\"."); return; @@ -4599,7 +4708,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { continue; } break; case GDScriptTokenizer::TK_PR_ONREADY: { - //may be fallthrough from export, ignore if so tokenizer->advance(); if (tokenizer->get_token() != GDScriptTokenizer::TK_PR_VAR) { @@ -4610,7 +4718,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { continue; } break; case GDScriptTokenizer::TK_PR_REMOTE: { - //may be fallthrough from export, ignore if so tokenizer->advance(); if (current_export.type) { @@ -4630,7 +4737,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { continue; } break; case GDScriptTokenizer::TK_PR_MASTER: { - //may be fallthrough from export, ignore if so tokenizer->advance(); if (current_export.type) { @@ -4650,7 +4756,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { continue; } break; case GDScriptTokenizer::TK_PR_PUPPET: { - //may be fallthrough from export, ignore if so tokenizer->advance(); if (current_export.type) { @@ -4670,14 +4775,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { continue; } break; case GDScriptTokenizer::TK_PR_REMOTESYNC: { - //may be fallthrough from export, ignore if so tokenizer->advance(); if (tokenizer->get_token() != GDScriptTokenizer::TK_PR_VAR && tokenizer->get_token() != GDScriptTokenizer::TK_PR_FUNCTION) { - if (current_export.type) + if (current_export.type) { _set_error("Expected \"var\"."); - else + } else { _set_error("Expected \"var\" or \"func\"."); + } return; } @@ -4685,14 +4790,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { continue; } break; case GDScriptTokenizer::TK_PR_MASTERSYNC: { - //may be fallthrough from export, ignore if so tokenizer->advance(); if (tokenizer->get_token() != GDScriptTokenizer::TK_PR_VAR && tokenizer->get_token() != GDScriptTokenizer::TK_PR_FUNCTION) { - if (current_export.type) + if (current_export.type) { _set_error("Expected \"var\"."); - else + } else { _set_error("Expected \"var\" or \"func\"."); + } return; } @@ -4700,14 +4805,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { continue; } break; case GDScriptTokenizer::TK_PR_PUPPETSYNC: { - //may be fallthrough from export, ignore if so tokenizer->advance(); if (tokenizer->get_token() != GDScriptTokenizer::TK_PR_VAR && tokenizer->get_token() != GDScriptTokenizer::TK_PR_FUNCTION) { - if (current_export.type) + if (current_export.type) { _set_error("Expected \"var\"."); - else + } else { _set_error("Expected \"var\" or \"func\"."); + } return; } @@ -4729,7 +4834,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); if (!tokenizer->is_token_literal(0, true)) { - _set_error("Expected an identifier for the member variable name."); return; } @@ -4819,7 +4923,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { #endif if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) { - #ifdef DEBUG_ENABLED int line = tokenizer->get_token_line(); #endif @@ -4835,12 +4938,10 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { //discourage common error if (!onready && subexpr->type == Node::TYPE_OPERATOR) { - OperatorNode *op = static_cast<OperatorNode *>(subexpr); if (op->op == OperatorNode::OP_CALL && op->arguments[0]->type == Node::TYPE_SELF && op->arguments[1]->type == Node::TYPE_IDENTIFIER) { IdentifierNode *id = static_cast<IdentifierNode *>(op->arguments[1]); if (id->name == "get_node") { - _set_error("Use \"onready var " + String(member.identifier) + " = get_node(...)\" instead."); return; } @@ -4850,19 +4951,21 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { member.expression = subexpr; if (autoexport && !member.data_type.has_type) { - if (subexpr->type != Node::TYPE_CONSTANT) { - _set_error("Type-less export needs a constant expression assigned to infer type."); return; } ConstantNode *cn = static_cast<ConstantNode *>(subexpr); if (cn->value.get_type() == Variant::NIL) { - _set_error("Can't accept a null constant expression for inferring export type."); return; } + + if (!_reduce_export_var_type(cn->value, member.line)) { + return; + } + member._export.type = cn->value.get_type(); member._export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; if (cn->value.get_type() == Variant::OBJECT) { @@ -4878,7 +4981,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } #ifdef TOOLS_ENABLED if (subexpr->type == Node::TYPE_CONSTANT && (member._export.type != Variant::NIL || member.data_type.has_type)) { - ConstantNode *cn = static_cast<ConstantNode *>(subexpr); if (cn->value.get_type() != Variant::NIL) { if (member._export.type != Variant::NIL && cn->value.get_type() != member._export.type) { @@ -4898,6 +5000,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { IdentifierNode *id = alloc_node<IdentifierNode>(); id->name = member.identifier; + id->datatype = member.data_type; OperatorNode *op = alloc_node<OperatorNode>(); op->op = OperatorNode::OP_INIT_ASSIGN; @@ -4907,20 +5010,21 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { #ifdef DEBUG_ENABLED NewLineNode *nl2 = alloc_node<NewLineNode>(); nl2->line = line; - if (onready) + if (onready) { p_class->ready->statements.push_back(nl2); - else + } else { p_class->initializer->statements.push_back(nl2); + } #endif - if (onready) + if (onready) { p_class->ready->statements.push_back(op); - else + } else { p_class->initializer->statements.push_back(op); + } member.initial_assignment = op; } else { - if (autoexport && !member.data_type.has_type) { _set_error("Type-less export needs a constant expression assigned to infer type."); return; @@ -4940,6 +5044,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { IdentifierNode *id = alloc_node<IdentifierNode>(); id->name = member.identifier; + id->datatype = member.data_type; OperatorNode *op = alloc_node<OperatorNode>(); op->op = OperatorNode::OP_INIT_ASSIGN; @@ -4952,7 +5057,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_SETGET) { - tokenizer->advance(); if (tokenizer->get_token() != GDScriptTokenizer::TK_COMMA) { @@ -4982,7 +5086,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { p_class->variables.push_back(member); if (!_end_statement()) { - _set_error("Expected end of statement (\"continue\")."); + _set_end_statement_error("var"); return; } } break; @@ -4993,7 +5097,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); if (!tokenizer->is_token_literal(0, true)) { - _set_error("Expected an identifier for the constant."); return; } @@ -5062,7 +5165,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { p_class->constant_expressions.insert(const_id, constant); if (!_end_statement()) { - _set_error("Expected end of statement (constant).", line); + _set_end_statement_error("const"); return; } @@ -5109,14 +5212,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { while (true) { if (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE) { - tokenizer->advance(); // Ignore newlines } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CURLY_BRACKET_CLOSE) { - tokenizer->advance(); break; // End of enum } else if (!tokenizer->is_token_literal(0, true)) { - if (tokenizer->get_token() == GDScriptTokenizer::TK_EOF) { _set_error("Unexpected end of file."); } else { @@ -5216,7 +5316,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (!_end_statement()) { - _set_error("Expected end of statement (\"enum\")."); + _set_end_statement_error("enum"); return; } @@ -5237,7 +5337,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } break; default: { - _set_error(String() + "Unexpected token: " + tokenizer->get_token_name(tokenizer->get_token()) + ":" + tokenizer->get_token_identifier()); return; @@ -5247,7 +5346,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive) { - if (p_class->base_type.has_type) { // Already determined } else if (p_class->extends_used) { @@ -5262,7 +5360,6 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive //path (and optionally subclasses) if (path.is_rel_path()) { - String base = base_path; if (base == "" || base.is_rel_path()) { @@ -5277,22 +5374,17 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive return; } if (!script->is_valid()) { - _set_error("Script isn't 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("Couldn't find the subclass: " + sub, p_class->line); return; } @@ -5300,7 +5392,6 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive } } else { - if (p_class->extends_class.size() == 0) { _set_error("Parser bug: undecidable inheritance.", p_class->line); ERR_FAIL(); @@ -5347,7 +5438,6 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive } while (p) { - bool found = false; for (int i = 0; i < p->subclasses.size(); i++) { @@ -5376,8 +5466,12 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive } } - if (base_class) break; - if (found) continue; + if (base_class) { + break; + } + if (found) { + continue; + } if (p->constant_expressions.has(base)) { if (p->constant_expressions[base].expression->type != Node::TYPE_CONSTANT) { @@ -5397,21 +5491,17 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive } if (base_script.is_valid()) { - String ident = base; Ref<GDScript> find_subclass = base_script; for (int i = extend_iter; i < p_class->extends_class.size(); i++) { - String subclass = p_class->extends_class[i]; ident += ("." + subclass); if (find_subclass->get_subclasses().has(subclass)) { - find_subclass = find_subclass->get_subclasses()[subclass]; } else if (find_subclass->get_constants().has(subclass)) { - Ref<GDScript> new_base_class = find_subclass->get_constants()[subclass]; if (new_base_class.is_null()) { _set_error("Constant isn't a class: " + ident, p_class->line); @@ -5419,7 +5509,6 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive } find_subclass = new_base_class; } else { - _set_error("Couldn't find the subclass: " + ident, p_class->line); return; } @@ -5428,15 +5517,12 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive script = find_subclass; } 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; } @@ -5479,10 +5565,14 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive } String GDScriptParser::DataType::to_string() const { - if (!has_type) return "var"; + if (!has_type) { + return "var"; + } switch (kind) { case BUILTIN: { - if (builtin_type == Variant::NIL) return "null"; + if (builtin_type == Variant::NIL) { + return "null"; + } return Variant::get_type_name(builtin_type); } break; case NATIVE: { @@ -5646,8 +5736,12 @@ bool GDScriptParser::_parse_type(DataType &r_type, bool p_can_be_void) { } GDScriptParser::DataType GDScriptParser::_resolve_type(const DataType &p_source, int p_line) { - if (!p_source.has_type) return p_source; - if (p_source.kind != DataType::UNRESOLVED) return p_source; + if (!p_source.has_type) { + return p_source; + } + if (p_source.kind != DataType::UNRESOLVED) { + return p_source; + } Vector<String> full_name = p_source.native_type.operator String().split(".", false); int name_part = 0; @@ -5656,7 +5750,6 @@ GDScriptParser::DataType GDScriptParser::_resolve_type(const DataType &p_source, result.has_type = true; while (name_part < full_name.size()) { - bool found = false; StringName id = full_name[name_part]; DataType base_type = result; @@ -6229,11 +6322,13 @@ GDScriptParser::Node *GDScriptParser::_get_default_value_for_type(const DataType ConstantNode *c = alloc_node<ConstantNode>(); Callable::CallError err; c->value = Variant::construct(p_type.builtin_type, nullptr, 0, err); + c->datatype = _type_from_variant(c->value); result = c; } } else { ConstantNode *c = alloc_node<ConstantNode>(); c->value = Variant(); + c->datatype = _type_from_variant(c->value); result = c; } @@ -6316,7 +6411,6 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { DataType source_type = _reduce_node_type(cn->source_node); cn->cast_type = _resolve_type(cn->cast_type, cn->line); if (source_type.has_type) { - bool valid = false; if (check_types) { if (cn->cast_type.kind == DataType::BUILTIN && source_type.kind == DataType::BUILTIN) { @@ -6370,7 +6464,6 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { } break; case OperatorNode::OP_IS: case OperatorNode::OP_IS_BUILTIN: { - if (op->arguments.size() != 2) { _set_error("Parser bug: binary operation without 2 arguments.", op->line); ERR_FAIL_V(DataType()); @@ -6406,7 +6499,6 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { case OperatorNode::OP_POS: case OperatorNode::OP_NOT: case OperatorNode::OP_BIT_INVERT: { - DataType argument_type = _reduce_node_type(op->arguments[0]); if (!argument_type.has_type) { break; @@ -6444,7 +6536,6 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { case OperatorNode::OP_BIT_AND: case OperatorNode::OP_BIT_OR: case OperatorNode::OP_BIT_XOR: { - if (op->arguments.size() != 2) { _set_error("Parser bug: binary operation without 2 arguments.", op->line); ERR_FAIL_V(DataType()); @@ -6512,7 +6603,6 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { case OperatorNode::OP_ASSIGN_BIT_OR: case OperatorNode::OP_ASSIGN_BIT_XOR: case OperatorNode::OP_INIT_ASSIGN: { - _set_error("Assignment inside an expression isn't allowed (parser bug?).", op->line); return DataType(); @@ -6562,6 +6652,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { node_type = _reduce_identifier_type(&base_type, member_id->name, op->line, true); #ifdef DEBUG_ENABLED if (!node_type.has_type) { + _mark_line_as_unsafe(op->line); _add_warning(GDScriptWarning::UNSAFE_PROPERTY_ACCESS, op->line, member_id->name.operator String(), base_type.to_string()); } #endif // DEBUG_ENABLED @@ -6574,7 +6665,6 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { } } break; case OperatorNode::OP_INDEX: { - if (op->arguments[1]->type == Node::TYPE_CONSTANT) { ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[1]); if (cn->value.get_type() == Variant::STRING) { @@ -6582,6 +6672,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { IdentifierNode *id = alloc_node<IdentifierNode>(); id->name = cn->value.operator StringName(); + id->datatype = cn->datatype; op->op = OperatorNode::OP_INDEX_NAMED; op->arguments.write[1] = id; @@ -6772,7 +6863,6 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { } bool GDScriptParser::_get_function_signature(DataType &p_base_type, const StringName &p_function, DataType &r_return_type, List<DataType> &r_arg_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) const { - r_static = false; r_default_arg_count = 0; @@ -6883,7 +6973,9 @@ bool GDScriptParser::_get_function_signature(DataType &p_base_type, const String native = "_" + native.operator String(); } if (!ClassDB::class_exists(native)) { - if (!check_types) return false; + if (!check_types) { + return false; + } ERR_FAIL_V_MSG(false, "Parser bug: Class '" + String(native) + "' not found."); } @@ -6974,7 +7066,9 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat par_types.write[i - 1] = _reduce_node_type(p_call->arguments[i]); } - if (error_set) return DataType(); + if (error_set) { + return DataType(); + } // Special case: check copy constructor. Those are defined implicitly in Variant. if (par_types.size() == 1) { @@ -7042,7 +7136,9 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat err += "' matches the signature '"; err += Variant::get_type_name(tn->vtype) + "("; for (int i = 0; i < par_types.size(); i++) { - if (i > 0) err += ", "; + if (i > 0) { + err += ", "; + } err += par_types[i].to_string(); } err += ")'."; @@ -7251,8 +7347,8 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat } else if (!_is_type_compatible(arg_types[i - arg_diff], par_type, true)) { // Supertypes are acceptable for dynamic compliance if (!_is_type_compatible(par_type, arg_types[i - arg_diff])) { - _set_error("At \"" + callee_name + "()\" call, argument " + itos(i - arg_diff + 1) + ". Assigned type (" + - par_type.to_string() + ") doesn't match the function argument's type (" + + _set_error("At \"" + callee_name + "()\" call, argument " + itos(i - arg_diff + 1) + ". The passed argument's type (" + + par_type.to_string() + ") doesn't match the function's expected argument type (" + arg_types[i - arg_diff].to_string() + ").", p_call->line); return DataType(); @@ -7271,7 +7367,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat return return_type; } -bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringName &p_member, DataType &r_member_type) const { +bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringName &p_member, DataType &r_member_type, bool *r_is_const) const { DataType base_type = p_base_type; // Check classes in current file @@ -7282,6 +7378,9 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN while (base) { if (base->constant_expressions.has(p_member)) { + if (r_is_const) { + *r_is_const = true; + } r_member_type = base->constant_expressions[p_member].expression->get_datatype(); return true; } @@ -7364,7 +7463,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN } } -#define IS_USAGE_MEMBER(m_usage) (!(m_usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY))) +#define IS_USAGE_MEMBER(m_usage) (!(m_usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SUBGROUP | PROPERTY_USAGE_CATEGORY))) // Check other script types while (scr.is_valid()) { @@ -7400,7 +7499,9 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN native = "_" + native.operator String(); } if (!ClassDB::class_exists(native)) { - if (!check_types) return false; + if (!check_types) { + return false; + } ERR_FAIL_V_MSG(false, "Parser bug: Class \"" + String(native) + "\" not found."); } @@ -7488,7 +7589,6 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN } GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType *p_base_type, const StringName &p_identifier, int p_line, bool p_is_indexing) { - if (p_base_type && !p_base_type->has_type) { return DataType(); } @@ -7505,7 +7605,12 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType base_type = DataType(*p_base_type); } - if (_get_member_type(base_type, p_identifier, member_type)) { + bool is_const = false; + if (_get_member_type(base_type, p_identifier, member_type, &is_const)) { + if (!p_base_type && current_function && current_function->_static && !is_const) { + _set_error("Can't access member variable (\"" + p_identifier.operator String() + "\") from a static function.", p_line); + return DataType(); + } return member_type; } @@ -7657,7 +7762,6 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType } void GDScriptParser::_check_class_level_types(ClassNode *p_class) { - // Names of internal object properties that we check to avoid overriding them. // "__meta__" could also be in here, but since it doesn't really affect object metadata, // it is okay to override it on script. @@ -7693,12 +7797,16 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { // Function declarations for (int i = 0; i < p_class->static_functions.size(); i++) { _check_function_types(p_class->static_functions[i]); - if (error_set) return; + if (error_set) { + return; + } } for (int i = 0; i < p_class->functions.size(); i++) { _check_function_types(p_class->functions[i]); - if (error_set) return; + if (error_set) { + return; + } } // Class variables @@ -7713,6 +7821,7 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { _mark_line_as_safe(v.line); v.data_type = _resolve_type(v.data_type, v.line); + v.initial_assignment->arguments[0]->set_datatype(v.data_type); if (v.expression) { DataType expr_type = _reduce_node_type(v.expression); @@ -7737,7 +7846,7 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { ConstantNode *tgt_type = alloc_node<ConstantNode>(); tgt_type->line = v.line; - tgt_type->value = (int)v.data_type.builtin_type; + tgt_type->value = (int64_t)v.data_type.builtin_type; OperatorNode *convert_call = alloc_node<OperatorNode>(); convert_call->line = v.line; @@ -7756,6 +7865,10 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { _set_error("The assigned value doesn't have a set type; the variable type can't be inferred.", v.line); return; } + if (expr_type.kind == DataType::BUILTIN && expr_type.builtin_type == Variant::NIL) { + _set_error("The variable type cannot be inferred because its value is \"null\".", v.line); + return; + } v.data_type = expr_type; v.data_type.is_constant = false; } @@ -7773,7 +7886,9 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { } // Setter and getter - if (v.setter == StringName() && v.getter == StringName()) continue; + if (v.setter == StringName() && v.getter == StringName()) { + continue; + } bool found_getter = false; bool found_setter = false; @@ -7816,10 +7931,14 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { return; } } - if (found_getter && found_setter) break; + if (found_getter && found_setter) { + break; + } } - if ((found_getter || v.getter == StringName()) && (found_setter || v.setter == StringName())) continue; + if ((found_getter || v.getter == StringName()) && (found_setter || v.setter == StringName())) { + continue; + } // Check for static functions for (int j = 0; j < p_class->static_functions.size(); j++) { @@ -7846,17 +7965,59 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { } } + // Signals + DataType base = p_class->base_type; + + while (base.kind == DataType::CLASS) { + ClassNode *base_class = base.class_type; + for (int i = 0; i < p_class->_signals.size(); i++) { + for (int j = 0; j < base_class->_signals.size(); j++) { + if (p_class->_signals[i].name == base_class->_signals[j].name) { + _set_error("The signal \"" + p_class->_signals[i].name + "\" already exists in a parent class.", p_class->_signals[i].line); + return; + } + } + } + base = base_class->base_type; + } + + StringName native; + if (base.kind == DataType::GDSCRIPT || base.kind == DataType::SCRIPT) { + Ref<Script> scr = base.script_type; + if (scr.is_valid() && scr->is_valid()) { + native = scr->get_instance_base_type(); + for (int i = 0; i < p_class->_signals.size(); i++) { + if (scr->has_script_signal(p_class->_signals[i].name)) { + _set_error("The signal \"" + p_class->_signals[i].name + "\" already exists in a parent class.", p_class->_signals[i].line); + return; + } + } + } + } else if (base.kind == DataType::NATIVE) { + native = base.native_type; + } + + if (native != StringName()) { + for (int i = 0; i < p_class->_signals.size(); i++) { + if (ClassDB::has_signal(native, p_class->_signals[i].name)) { + _set_error("The signal \"" + p_class->_signals[i].name + "\" already exists in a parent class.", p_class->_signals[i].line); + return; + } + } + } + // Inner classes for (int i = 0; i < p_class->subclasses.size(); i++) { current_class = p_class->subclasses[i]; _check_class_level_types(current_class); - if (error_set) return; + if (error_set) { + return; + } current_class = p_class; } } void GDScriptParser::_check_function_types(FunctionNode *p_function) { - p_function->return_type = _resolve_type(p_function->return_type, p_function->line); // Arguments @@ -7975,21 +8136,9 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) { p_function->return_type.has_type = false; p_function->return_type.may_yield = true; } - -#ifdef DEBUG_ENABLED - for (Map<StringName, LocalVarNode *>::Element *E = p_function->body->variables.front(); E; E = E->next()) { - LocalVarNode *lv = E->get(); - for (int i = 0; i < current_class->variables.size(); i++) { - if (current_class->variables[i].identifier == lv->name) { - _add_warning(GDScriptWarning::SHADOWED_VARIABLE, lv->line, lv->name, itos(current_class->variables[i].line)); - } - } - } -#endif // DEBUG_ENABLED } void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) { - // Function blocks for (int i = 0; i < p_class->static_functions.size(); i++) { current_function = p_class->static_functions[i]; @@ -7998,7 +8147,9 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) { _check_block_types(current_block); current_block = nullptr; current_function = nullptr; - if (error_set) return; + if (error_set) { + return; + } } for (int i = 0; i < p_class->functions.size(); i++) { @@ -8008,7 +8159,9 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) { _check_block_types(current_block); current_block = nullptr; current_function = nullptr; - if (error_set) return; + if (error_set) { + return; + } } #ifdef DEBUG_ENABLED @@ -8029,7 +8182,9 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) { for (int i = 0; i < p_class->subclasses.size(); i++) { current_class = p_class->subclasses[i]; _check_class_blocks_types(current_class); - if (error_set) return; + if (error_set) { + return; + } current_class = p_class; } } @@ -8055,7 +8210,6 @@ static String _find_function_name(const GDScriptParser::OperatorNode *p_call) { #endif // DEBUG_ENABLED void GDScriptParser::_check_block_types(BlockNode *p_block) { - Node *last_var_assign = nullptr; // Check each statement @@ -8063,10 +8217,15 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { Node *statement = E->get(); switch (statement->type) { case Node::TYPE_NEWLINE: - case Node::TYPE_BREAKPOINT: - case Node::TYPE_ASSERT: { + case Node::TYPE_BREAKPOINT: { // Nothing to do } break; + case Node::TYPE_ASSERT: { + AssertNode *an = static_cast<AssertNode *>(statement); + _mark_line_as_safe(an->line); + _reduce_node_type(an->condition); + _reduce_node_type(an->message); + } break; case Node::TYPE_LOCAL_VAR: { LocalVarNode *lv = static_cast<LocalVarNode *>(statement); lv->datatype = _resolve_type(lv->datatype, lv->line); @@ -8088,6 +8247,11 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { if (lv->datatype.has_type && assign_type.may_yield && lv->assign->type == Node::TYPE_OPERATOR) { _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, lv->line, _find_function_name(static_cast<OperatorNode *>(lv->assign))); } + for (int i = 0; i < current_class->variables.size(); i++) { + if (current_class->variables[i].identifier == lv->name) { + _add_warning(GDScriptWarning::SHADOWED_VARIABLE, lv->line, lv->name, itos(current_class->variables[i].line)); + } + } #endif // DEBUG_ENABLED if (!_is_type_compatible(lv->datatype, assign_type)) { @@ -8109,7 +8273,8 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { ConstantNode *tgt_type = alloc_node<ConstantNode>(); tgt_type->line = lv->line; - tgt_type->value = (int)lv->datatype.builtin_type; + tgt_type->value = (int64_t)lv->datatype.builtin_type; + tgt_type->datatype = _type_from_variant(tgt_type->value); OperatorNode *convert_call = alloc_node<OperatorNode>(); convert_call->line = lv->line; @@ -8132,6 +8297,10 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { _set_error("The assigned value doesn't have a set type; the variable type can't be inferred.", lv->line); return; } + if (assign_type.kind == DataType::BUILTIN && assign_type.builtin_type == Variant::NIL) { + _set_error("The variable type cannot be inferred because its value is \"null\".", lv->line); + return; + } lv->datatype = assign_type; lv->datatype.is_constant = false; } @@ -8245,6 +8414,7 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { ConstantNode *tgt_type = alloc_node<ConstantNode>(); tgt_type->line = op->line; tgt_type->value = (int)lh_type.builtin_type; + tgt_type->datatype = _type_from_variant(tgt_type->value); OperatorNode *convert_call = alloc_node<OperatorNode>(); convert_call->line = op->line; @@ -8285,7 +8455,9 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { _add_warning(GDScriptWarning::RETURN_VALUE_DISCARDED, op->line, func_name); } #endif // DEBUG_ENABLED - if (error_set) return; + if (error_set) { + return; + } } break; case OperatorNode::OP_YIELD: { _mark_line_as_safe(op->line); @@ -8320,7 +8492,9 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { } } - if (!function_type.has_type) break; + if (!function_type.has_type) { + break; + } if (function_type.kind == DataType::BUILTIN && function_type.builtin_type == Variant::NIL) { // Return void, should not have arguments @@ -8380,7 +8554,9 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { current_block = p_block->sub_blocks[i]; _check_block_types(current_block); current_block = p_block; - if (error_set) return; + if (error_set) { + return; + } } #ifdef DEBUG_ENABLED @@ -8399,9 +8575,9 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { } void GDScriptParser::_set_error(const String &p_error, int p_line, int p_column) { - - if (error_set) + if (error_set) { return; //allow no further errors + } error = p_error; error_line = p_line < 0 ? tokenizer->get_token_line() : p_line; @@ -8463,16 +8639,14 @@ void GDScriptParser::_add_warning(int p_code, int p_line, const Vector<String> & #endif // DEBUG_ENABLED String GDScriptParser::get_error() const { - return error; } int GDScriptParser::get_error_line() const { - return error_line; } -int GDScriptParser::get_error_column() const { +int GDScriptParser::get_error_column() const { return error_column; } @@ -8481,7 +8655,6 @@ bool GDScriptParser::has_error() const { } Error GDScriptParser::_parse(const String &p_base_path) { - base_path = p_base_path; //assume class @@ -8499,7 +8672,13 @@ Error GDScriptParser::_parse(const String &p_base_path) { _set_error("Parse error: " + tokenizer->get_token_error()); } - if (error_set && !for_completion) { + bool for_completion_error_set = false; + if (error_set && for_completion) { + for_completion_error_set = true; + error_set = false; + } + + if (error_set) { return ERR_PARSE_ERROR; } @@ -8517,7 +8696,9 @@ Error GDScriptParser::_parse(const String &p_base_path) { current_function = nullptr; current_block = nullptr; - if (for_completion) check_types = false; + if (for_completion) { + check_types = false; + } // Resolve all class-level stuff before getting into function blocks _check_class_level_types(main_class); @@ -8529,6 +8710,10 @@ Error GDScriptParser::_parse(const String &p_base_path) { // Resolve the function blocks _check_class_blocks_types(main_class); + if (for_completion_error_set) { + error_set = true; + } + if (error_set) { return ERR_PARSE_ERROR; } @@ -8569,7 +8754,6 @@ Error GDScriptParser::_parse(const String &p_base_path) { } Error GDScriptParser::parse_bytecode(const Vector<uint8_t> &p_bytecode, const String &p_base_path, const String &p_self_path) { - clear(); self_path = p_self_path; @@ -8583,7 +8767,6 @@ Error GDScriptParser::parse_bytecode(const Vector<uint8_t> &p_bytecode, const St } 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(); self_path = p_self_path; @@ -8604,19 +8787,15 @@ Error GDScriptParser::parse(const String &p_code, const String &p_base_path, boo } bool GDScriptParser::is_tool_script() const { - return (head && head->type == Node::TYPE_CLASS && static_cast<const ClassNode *>(head)->tool); } const GDScriptParser::Node *GDScriptParser::get_parse_tree() const { - return head; } void GDScriptParser::clear() { - while (list) { - Node *l = list; list = list->next; memdelete(l); @@ -8658,57 +8837,46 @@ void GDScriptParser::clear() { } GDScriptParser::CompletionType GDScriptParser::get_completion_type() { - return completion_type; } StringName GDScriptParser::get_completion_cursor() { - return completion_cursor; } int GDScriptParser::get_completion_line() { - return completion_line; } Variant::Type GDScriptParser::get_completion_built_in_constant() { - return completion_built_in_constant; } GDScriptParser::Node *GDScriptParser::get_completion_node() { - return completion_node; } GDScriptParser::BlockNode *GDScriptParser::get_completion_block() { - return completion_block; } GDScriptParser::ClassNode *GDScriptParser::get_completion_class() { - return completion_class; } GDScriptParser::FunctionNode *GDScriptParser::get_completion_function() { - return completion_function; } int GDScriptParser::get_completion_argument_index() { - return completion_argument; } -int GDScriptParser::get_completion_identifier_is_function() { - +bool GDScriptParser::get_completion_identifier_is_function() { return completion_ident_is_call; } GDScriptParser::GDScriptParser() { - head = nullptr; list = nullptr; tokenizer = nullptr; @@ -8717,6 +8885,5 @@ GDScriptParser::GDScriptParser() { } GDScriptParser::~GDScriptParser() { - clear(); } diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index eca5f83f7a..7dedb6d6f9 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -45,25 +45,27 @@ public: struct ClassNode; struct DataType { - enum { + enum Kind { BUILTIN, NATIVE, SCRIPT, GDSCRIPT, CLASS, UNRESOLVED - } kind; + }; + + Kind kind = UNRESOLVED; - bool has_type; - bool is_constant; - bool is_meta_type; // Whether the value can be used as a type - bool infer_type; - bool may_yield; // For function calls + bool has_type = false; + bool is_constant = false; + bool is_meta_type = false; // Whether the value can be used as a type + bool infer_type = false; + bool may_yield = false; // For function calls - Variant::Type builtin_type; + Variant::Type builtin_type = Variant::NIL; StringName native_type; Ref<Script> script_type; - ClassNode *class_type; + ClassNode *class_type = nullptr; String to_string() const; @@ -94,19 +96,10 @@ public: return false; } - DataType() : - kind(UNRESOLVED), - has_type(false), - is_constant(false), - is_meta_type(false), - infer_type(false), - may_yield(false), - builtin_type(Variant::NIL), - class_type(nullptr) {} + DataType() {} }; struct Node { - enum Type { TYPE_CLASS, TYPE_FUNCTION, @@ -145,7 +138,6 @@ public: struct OperatorNode; struct ClassNode : public Node { - bool tool; StringName name; bool extends_used; @@ -206,7 +198,6 @@ public: }; struct FunctionNode : public Node { - bool _static; MultiplayerAPI::RPCMode rpc_mode; bool has_yield; @@ -235,67 +226,65 @@ public: }; struct BlockNode : public Node { - - ClassNode *parent_class; - BlockNode *parent_block; + ClassNode *parent_class = nullptr; + BlockNode *parent_block = nullptr; List<Node *> statements; Map<StringName, LocalVarNode *> variables; - bool has_return; + bool has_return = false; + bool can_break = false; + bool can_continue = false; - Node *if_condition; //tiny hack to improve code completion on if () blocks + Node *if_condition = nullptr; //tiny hack to improve code completion on if () blocks //the following is useful for code completion List<BlockNode *> sub_blocks; - int end_line; + int end_line = -1; + BlockNode() { - if_condition = nullptr; type = TYPE_BLOCK; - end_line = -1; - parent_block = nullptr; - parent_class = nullptr; - has_return = false; } }; struct TypeNode : public Node { - Variant::Type vtype; - TypeNode() { type = TYPE_TYPE; } + + TypeNode() { + type = TYPE_TYPE; + } }; + struct BuiltInFunctionNode : public Node { GDScriptFunctions::Function function; - BuiltInFunctionNode() { type = TYPE_BUILT_IN_FUNCTION; } + + BuiltInFunctionNode() { + type = TYPE_BUILT_IN_FUNCTION; + } }; struct IdentifierNode : public Node { - StringName name; - BlockNode *declared_block; // Simplify lookup by checking if it is declared locally + BlockNode *declared_block = nullptr; // Simplify lookup by checking if it is declared locally DataType datatype; virtual DataType get_datatype() const { return datatype; } virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; } + IdentifierNode() { type = TYPE_IDENTIFIER; - declared_block = nullptr; } }; struct LocalVarNode : public Node { - StringName name; - Node *assign; - OperatorNode *assign_op; - int assignments; - int usages; + Node *assign = nullptr; + OperatorNode *assign_op = nullptr; + int assignments = 0; + int usages = 0; DataType datatype; virtual DataType get_datatype() const { return datatype; } virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; } + LocalVarNode() { type = TYPE_LOCAL_VAR; - assign = nullptr; - assign_op = nullptr; - assignments = 0; - usages = 0; } }; @@ -304,15 +293,18 @@ public: DataType datatype; virtual DataType get_datatype() const { return datatype; } virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; } - ConstantNode() { type = TYPE_CONSTANT; } + + ConstantNode() { + type = TYPE_CONSTANT; + } }; struct ArrayNode : public Node { - Vector<Node *> elements; DataType datatype; virtual DataType get_datatype() const { return datatype; } virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; } + ArrayNode() { type = TYPE_ARRAY; datatype.has_type = true; @@ -322,9 +314,7 @@ public: }; struct DictionaryNode : public Node { - struct Pair { - Node *key; Node *value; }; @@ -333,6 +323,7 @@ public: DataType datatype; virtual DataType get_datatype() const { return datatype; } virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; } + DictionaryNode() { type = TYPE_DICTIONARY; datatype.has_type = true; @@ -342,7 +333,9 @@ public: }; struct SelfNode : public Node { - SelfNode() { type = TYPE_SELF; } + SelfNode() { + type = TYPE_SELF; + } }; struct OperatorNode : public Node { @@ -404,11 +397,12 @@ public: DataType datatype; virtual DataType get_datatype() const { return datatype; } virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; } - OperatorNode() { type = TYPE_OPERATOR; } + OperatorNode() { + type = TYPE_OPERATOR; + } }; struct PatternNode : public Node { - enum PatternType { PT_CONSTANT, PT_BIND, @@ -454,19 +448,17 @@ public: CF_MATCH }; - CFType cf_type; + CFType cf_type = CF_IF; Vector<Node *> arguments; - BlockNode *body; - BlockNode *body_else; + BlockNode *body = nullptr; + BlockNode *body_else = nullptr; MatchNode *match; ControlFlowNode *_else; //used for if + ControlFlowNode() { type = TYPE_CONTROL_FLOW; - cf_type = CF_IF; - body = nullptr; - body_else = nullptr; } }; @@ -476,29 +468,34 @@ public: DataType return_type; virtual DataType get_datatype() const { return return_type; } virtual void set_datatype(const DataType &p_datatype) { return_type = p_datatype; } - CastNode() { type = TYPE_CAST; } + + CastNode() { + type = TYPE_CAST; + } }; struct AssertNode : public Node { - Node *condition; - Node *message; - AssertNode() : - condition(0), - message(0) { + Node *condition = nullptr; + Node *message = nullptr; + + AssertNode() { type = TYPE_ASSERT; } }; struct BreakpointNode : public Node { - BreakpointNode() { type = TYPE_BREAKPOINT; } + BreakpointNode() { + type = TYPE_BREAKPOINT; + } }; struct NewLineNode : public Node { - NewLineNode() { type = TYPE_NEWLINE; } + NewLineNode() { + type = TYPE_NEWLINE; + } }; struct Expression { - bool is_op; union { OperatorNode::Operator op; @@ -553,8 +550,8 @@ private: int pending_newline; struct IndentLevel { - int indent; - int tabs; + int indent = 0; + int tabs = 0; bool is_mixed(IndentLevel other) { return ( @@ -563,9 +560,7 @@ private: (indent < other.indent && tabs > other.tabs)); } - IndentLevel() : - indent(0), - tabs(0) {} + IndentLevel() {} IndentLevel(int p_indent, int p_tabs) : indent(p_indent), @@ -613,6 +608,7 @@ private: Node *_parse_expression(Node *p_parent, bool p_static, bool p_allow_assign = false, bool p_parsing_constant = false); Node *_reduce_expression(Node *p_node, bool p_to_const = false); Node *_parse_and_reduce_expression(Node *p_parent, bool p_static, bool p_reduce_const = false, bool p_allow_assign = false); + bool _reduce_export_var_type(Variant &p_value, int p_line = 0); PatternNode *_parse_pattern(bool p_static); void _parse_pattern_block(BlockNode *p_block, Vector<PatternBranchNode *> &p_branches, bool p_static); @@ -623,6 +619,7 @@ private: void _parse_extends(ClassNode *p_class); void _parse_class(ClassNode *p_class); bool _end_statement(); + void _set_end_statement_error(String p_name); void _determine_inheritance(ClassNode *p_class, bool p_recursive = true); bool _parse_type(DataType &r_type, bool p_can_be_void = false); @@ -633,7 +630,7 @@ private: DataType _get_operation_type(const Variant::Operator p_op, const DataType &p_a, const DataType &p_b, bool &r_valid) const; Variant::Operator _get_variant_operation(const OperatorNode::Operator &p_op) const; bool _get_function_signature(DataType &p_base_type, const StringName &p_function, DataType &r_return_type, List<DataType> &r_arg_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) const; - bool _get_member_type(const DataType &p_base_type, const StringName &p_member, DataType &r_member_type) const; + bool _get_member_type(const DataType &p_base_type, const StringName &p_member, DataType &r_member_type, bool *r_is_const = nullptr) const; bool _is_type_compatible(const DataType &p_container, const DataType &p_expression, bool p_allow_implicit_conversion = false) const; Node *_get_default_value_for_type(const DataType &p_type, int p_line = -1); @@ -646,12 +643,16 @@ private: void _check_block_types(BlockNode *p_block); _FORCE_INLINE_ void _mark_line_as_safe(int p_line) const { #ifdef DEBUG_ENABLED - if (safe_lines) safe_lines->insert(p_line); + if (safe_lines) { + safe_lines->insert(p_line); + } #endif // DEBUG_ENABLED } _FORCE_INLINE_ void _mark_line_as_unsafe(int p_line) const { #ifdef DEBUG_ENABLED - if (safe_lines) safe_lines->erase(p_line); + if (safe_lines) { + safe_lines->erase(p_line); + } #endif // DEBUG_ENABLED } @@ -682,7 +683,7 @@ public: BlockNode *get_completion_block(); FunctionNode *get_completion_function(); int get_completion_argument_index(); - int get_completion_identifier_is_function(); + bool get_completion_identifier_is_function(); const List<String> &get_dependencies() const { return dependencies; } diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index d42ca52731..2db42601c6 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -240,7 +240,6 @@ static const _kws _keyword_list[] = { }; const char *GDScriptTokenizer::get_token_name(Token p_token) { - ERR_FAIL_INDEX_V(p_token, TK_MAX, "<error>"); return token_names[p_token]; } @@ -364,27 +363,22 @@ StringName GDScriptTokenizer::get_token_literal(int p_offset) const { } static bool _is_text_char(CharType c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; } static bool _is_number(CharType c) { - return (c >= '0' && c <= '9'); } static bool _is_hex(CharType c) { - return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } static bool _is_bin(CharType c) { - return (c == '0' || c == '1'); } void GDScriptTokenizerText::_make_token(Token p_type) { - TokenData &tk = tk_rb[tk_rb_pos]; tk.type = p_type; @@ -393,8 +387,8 @@ void GDScriptTokenizerText::_make_token(Token p_type) { tk_rb_pos = (tk_rb_pos + 1) % TK_RB_SIZE; } -void GDScriptTokenizerText::_make_identifier(const StringName &p_identifier) { +void GDScriptTokenizerText::_make_identifier(const StringName &p_identifier) { TokenData &tk = tk_rb[tk_rb_pos]; tk.type = TK_IDENTIFIER; @@ -406,7 +400,6 @@ void GDScriptTokenizerText::_make_identifier(const StringName &p_identifier) { } void GDScriptTokenizerText::_make_built_in_func(GDScriptFunctions::Function p_func) { - TokenData &tk = tk_rb[tk_rb_pos]; tk.type = TK_BUILT_IN_FUNC; @@ -416,8 +409,8 @@ void GDScriptTokenizerText::_make_built_in_func(GDScriptFunctions::Function p_fu tk_rb_pos = (tk_rb_pos + 1) % TK_RB_SIZE; } -void GDScriptTokenizerText::_make_constant(const Variant &p_constant) { +void GDScriptTokenizerText::_make_constant(const Variant &p_constant) { TokenData &tk = tk_rb[tk_rb_pos]; tk.type = TK_CONSTANT; @@ -429,7 +422,6 @@ void GDScriptTokenizerText::_make_constant(const Variant &p_constant) { } void GDScriptTokenizerText::_make_type(const Variant::Type &p_type) { - TokenData &tk = tk_rb[tk_rb_pos]; tk.type = TK_BUILT_IN_TYPE; @@ -441,7 +433,6 @@ void GDScriptTokenizerText::_make_type(const Variant::Type &p_type) { } void GDScriptTokenizerText::_make_error(const String &p_error) { - error_flag = true; last_error = p_error; @@ -454,7 +445,6 @@ void GDScriptTokenizerText::_make_error(const String &p_error) { } void GDScriptTokenizerText::_make_newline(int p_indentation, int p_tabs) { - TokenData &tk = tk_rb[tk_rb_pos]; tk.type = TK_NEWLINE; tk.constant = Vector2(p_indentation, p_tabs); @@ -464,7 +454,6 @@ void GDScriptTokenizerText::_make_newline(int p_indentation, int p_tabs) { } void GDScriptTokenizerText::_advance() { - if (error_flag) { //parser broke _make_error(last_error); @@ -482,7 +471,6 @@ void GDScriptTokenizerText::_advance() { column += m_amount; \ } while (true) { - bool is_string_name = false; StringMode string_mode = STRING_DOUBLE_QUOTE; @@ -570,7 +558,6 @@ void GDScriptTokenizerText::_advance() { return; } case '/': { - switch (GETCHAR(1)) { case '=': { // diveq @@ -587,13 +574,13 @@ void GDScriptTokenizerText::_advance() { _make_token(TK_OP_EQUAL); INCPOS(1); - } else + } else { _make_token(TK_OP_ASSIGN); + } } break; case '<': { if (GETCHAR(1) == '=') { - _make_token(TK_OP_LESS_EQUAL); INCPOS(1); } else if (GETCHAR(1) == '<') { @@ -604,8 +591,9 @@ void GDScriptTokenizerText::_advance() { _make_token(TK_OP_SHIFT_LEFT); } INCPOS(1); - } else + } else { _make_token(TK_OP_LESS); + } } break; case '>': { @@ -684,7 +672,6 @@ void GDScriptTokenizerText::_advance() { break; case '&': { if (GETCHAR(1) == '&') { - _make_token(TK_OP_AND); INCPOS(1); } else if (GETCHAR(1) == '=') { @@ -696,7 +683,6 @@ void GDScriptTokenizerText::_advance() { } break; case '|': { if (GETCHAR(1) == '|') { - _make_token(TK_OP_OR); INCPOS(1); } else if (GETCHAR(1) == '=') { @@ -707,7 +693,6 @@ void GDScriptTokenizerText::_advance() { } } break; case '*': { - if (GETCHAR(1) == '=') { _make_token(TK_OP_ASSIGN_MUL); INCPOS(1); @@ -716,7 +701,6 @@ void GDScriptTokenizerText::_advance() { } } break; case '+': { - if (GETCHAR(1) == '=') { _make_token(TK_OP_ASSIGN_ADD); INCPOS(1); @@ -731,7 +715,6 @@ void GDScriptTokenizerText::_advance() { } break; case '-': { - if (GETCHAR(1) == '=') { _make_token(TK_OP_ASSIGN_SUB); INCPOS(1); @@ -743,7 +726,6 @@ void GDScriptTokenizerText::_advance() { } } break; case '%': { - if (GETCHAR(1) == '=') { _make_token(TK_OP_ASSIGN_MOD); INCPOS(1); @@ -761,9 +743,9 @@ void GDScriptTokenizerText::_advance() { [[fallthrough]]; case '\'': case '"': { - - if (GETCHAR(0) == '\'') + if (GETCHAR(0) == '\'') { string_mode = STRING_SINGLE_QUOTE; + } int i = 1; if (string_mode == STRING_DOUBLE_QUOTE && GETCHAR(i) == '"' && GETCHAR(i + 1) == '"') { @@ -774,7 +756,6 @@ void GDScriptTokenizerText::_advance() { String str; while (true) { if (CharType(GETCHAR(i)) == 0) { - _make_error("Unterminated String"); return; } else if (string_mode == STRING_DOUBLE_QUOTE && CharType(GETCHAR(i)) == '"') { @@ -802,20 +783,36 @@ void GDScriptTokenizerText::_advance() { CharType res = 0; switch (next) { - - case 'a': res = 7; break; - case 'b': res = 8; break; - case 't': res = 9; break; - case 'n': res = 10; break; - case 'v': res = 11; break; - case 'f': res = 12; break; - case 'r': res = 13; break; - case '\'': res = '\''; break; - case '\"': res = '\"'; break; - case '\\': res = '\\'; break; - case '/': - res = '/'; - break; //wtf + case 'a': + res = '\a'; + break; + case 'b': + res = '\b'; + break; + case 't': + res = '\t'; + break; + case 'n': + res = '\n'; + break; + case 'v': + res = '\v'; + break; + case 'f': + res = '\f'; + break; + case 'r': + res = '\r'; + break; + case '\'': + res = '\''; + break; + case '\"': + res = '\"'; + break; + case '\\': + res = '\\'; + break; case 'u': { // hex number @@ -847,14 +844,19 @@ void GDScriptTokenizerText::_advance() { i += 3; } break; + case '\n': { + line++; + column = 1; + } break; default: { - _make_error("Invalid escape sequence"); return; } break; } - str += res; + if (next != '\n') { + str += res; + } } else { if (CharType(GETCHAR(i)) == '\n') { @@ -879,7 +881,6 @@ void GDScriptTokenizerText::_advance() { _make_token(TK_CURSOR); } break; default: { - if (_is_number(GETCHAR(0)) || (GETCHAR(0) == '.' && _is_number(GETCHAR(1)))) { // parse number bool period_found = false; @@ -911,7 +912,6 @@ void GDScriptTokenizerText::_advance() { } hexa_found = true; } else if (hexa_found && _is_hex(GETCHAR(i))) { - } else if (!hexa_found && GETCHAR(i) == 'b') { if (bin_found || str.length() != 1 || !((i == 1 && str[0] == '0') || (i == 2 && str[1] == '0' && str[0] == '-'))) { _make_error("Invalid numeric constant at 'b'"); @@ -928,7 +928,6 @@ void GDScriptTokenizerText::_advance() { //all ok } else if (bin_found && _is_bin(GETCHAR(i))) { - } else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) { if (sign_found) { _make_error("Invalid numeric constant at '-'"); @@ -938,8 +937,9 @@ void GDScriptTokenizerText::_advance() { } else if (GETCHAR(i) == '_') { i++; continue; // Included for readability, shouldn't be a part of the string - } else + } else { break; + } str += CharType(GETCHAR(i)); i++; @@ -996,15 +996,12 @@ void GDScriptTokenizerText::_advance() { } else if (str == "false") { _make_constant(false); } else { - bool found = false; { - int idx = 0; while (_type_list[idx].text) { - if (str == _type_list[idx].text) { _make_type(_type_list[idx].type); found = true; @@ -1015,13 +1012,10 @@ void GDScriptTokenizerText::_advance() { } if (!found) { - //built in func? for (int j = 0; j < GDScriptFunctions::FUNC_MAX; j++) { - if (str == GDScriptFunctions::get_func_name(GDScriptFunctions::Function(j))) { - _make_built_in_func(GDScriptFunctions::Function(j)); found = true; break; @@ -1036,7 +1030,6 @@ void GDScriptTokenizerText::_advance() { found = false; while (_keyword_list[idx].text) { - if (str == _keyword_list[idx].text) { _make_token(_keyword_list[idx].token); found = true; @@ -1046,8 +1039,9 @@ void GDScriptTokenizerText::_advance() { } } - if (!found) + if (!found) { identifier = true; + } } if (identifier) { @@ -1069,7 +1063,6 @@ void GDScriptTokenizerText::_advance() { } void GDScriptTokenizerText::set_code(const String &p_code) { - code = p_code; len = p_code.length(); if (len) { @@ -1086,8 +1079,9 @@ void GDScriptTokenizerText::set_code(const String &p_code) { ignore_warnings = false; #endif // DEBUG_ENABLED last_error = ""; - for (int i = 0; i < MAX_LOOKAHEAD + 1; i++) + for (int i = 0; i < MAX_LOOKAHEAD + 1; i++) { _advance(); + } } GDScriptTokenizerText::Token GDScriptTokenizerText::get_token(int p_offset) const { @@ -1124,7 +1118,6 @@ const Variant &GDScriptTokenizerText::get_token_constant(int p_offset) const { } StringName GDScriptTokenizerText::get_token_identifier(int p_offset) const { - ERR_FAIL_COND_V(p_offset <= -MAX_LOOKAHEAD, StringName()); ERR_FAIL_COND_V(p_offset >= MAX_LOOKAHEAD, StringName()); @@ -1134,7 +1127,6 @@ StringName GDScriptTokenizerText::get_token_identifier(int p_offset) const { } GDScriptFunctions::Function GDScriptTokenizerText::get_token_built_in_func(int p_offset) const { - ERR_FAIL_COND_V(p_offset <= -MAX_LOOKAHEAD, GDScriptFunctions::FUNC_MAX); ERR_FAIL_COND_V(p_offset >= MAX_LOOKAHEAD, GDScriptFunctions::FUNC_MAX); @@ -1144,7 +1136,6 @@ GDScriptFunctions::Function GDScriptTokenizerText::get_token_built_in_func(int p } Variant::Type GDScriptTokenizerText::get_token_type(int p_offset) const { - ERR_FAIL_COND_V(p_offset <= -MAX_LOOKAHEAD, Variant::NIL); ERR_FAIL_COND_V(p_offset >= MAX_LOOKAHEAD, Variant::NIL); @@ -1154,7 +1145,6 @@ Variant::Type GDScriptTokenizerText::get_token_type(int p_offset) const { } int GDScriptTokenizerText::get_token_line_indent(int p_offset) const { - ERR_FAIL_COND_V(p_offset <= -MAX_LOOKAHEAD, 0); ERR_FAIL_COND_V(p_offset >= MAX_LOOKAHEAD, 0); @@ -1164,7 +1154,6 @@ int GDScriptTokenizerText::get_token_line_indent(int p_offset) const { } int GDScriptTokenizerText::get_token_line_tab_indent(int p_offset) const { - ERR_FAIL_COND_V(p_offset <= -MAX_LOOKAHEAD, 0); ERR_FAIL_COND_V(p_offset >= MAX_LOOKAHEAD, 0); @@ -1174,7 +1163,6 @@ int GDScriptTokenizerText::get_token_line_tab_indent(int p_offset) const { } String GDScriptTokenizerText::get_token_error(int p_offset) const { - ERR_FAIL_COND_V(p_offset <= -MAX_LOOKAHEAD, String()); ERR_FAIL_COND_V(p_offset >= MAX_LOOKAHEAD, String()); @@ -1184,10 +1172,10 @@ String GDScriptTokenizerText::get_token_error(int p_offset) const { } void GDScriptTokenizerText::advance(int p_amount) { - ERR_FAIL_COND(p_amount <= 0); - for (int i = 0; i < p_amount; i++) + for (int i = 0; i < p_amount; i++) { _advance(); + } } ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1195,7 +1183,6 @@ void GDScriptTokenizerText::advance(int p_amount) { #define BYTECODE_VERSION 13 Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer) { - const uint8_t *buf = p_buffer.ptr(); int total_len = p_buffer.size(); ERR_FAIL_COND_V(p_buffer.size() < 24 || p_buffer[0] != 'G' || p_buffer[1] != 'D' || p_buffer[2] != 'S' || p_buffer[3] != 'C', ERR_INVALID_DATA); @@ -1213,7 +1200,6 @@ Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer) identifiers.resize(identifier_count); for (int i = 0; i < identifier_count; i++) { - int len = decode_uint32(b); ERR_FAIL_COND_V(len > total_len, ERR_INVALID_DATA); b += 4; @@ -1233,13 +1219,13 @@ Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer) constants.resize(constant_count); for (int i = 0; i < constant_count; i++) { - Variant v; int len; // An object cannot be constant, never decode objects Error err = decode_variant(v, b, total_len, &len, false); - if (err) + if (err) { return err; + } b += len; total_len -= len; constants.write[i] = v; @@ -1248,7 +1234,6 @@ Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer) ERR_FAIL_COND_V(line_count * 8 > total_len, ERR_INVALID_DATA); for (int i = 0; i < line_count; i++) { - uint32_t token = decode_uint32(b); b += 4; uint32_t linecol = decode_uint32(b); @@ -1261,7 +1246,6 @@ Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer) tokens.resize(token_count); for (int i = 0; i < token_count; i++) { - ERR_FAIL_COND_V(total_len < 1, ERR_INVALID_DATA); if ((*b) & TOKEN_BYTE_MASK) { //little endian always @@ -1282,7 +1266,6 @@ Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer) } Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code) { - Vector<uint8_t> buf; Map<StringName, int> identifier_map; @@ -1295,16 +1278,13 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code) int line = -1; while (true) { - if (tt.get_token_line() != line) { - line = tt.get_token_line(); line_map[line] = token_array.size(); } uint32_t token = tt.get_token(); switch (tt.get_token()) { - case TK_IDENTIFIER: { StringName id = tt.get_token_identifier(); if (!identifier_map.has(id)) { @@ -1314,7 +1294,6 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code) token |= identifier_map[id] << TOKEN_BITS; } break; case TK_CONSTANT: { - const Variant &c = tt.get_token_constant(); if (!constant_map.has(c)) { int idx = constant_map.size(); @@ -1323,20 +1302,16 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code) token |= constant_map[c] << TOKEN_BITS; } break; case TK_BUILT_IN_TYPE: { - token |= tt.get_token_type() << TOKEN_BITS; } break; case TK_BUILT_IN_FUNC: { - token |= tt.get_token_built_in_func() << TOKEN_BITS; } break; case TK_NEWLINE: { - token |= tt.get_token_line_indent() << TOKEN_BITS; } break; case TK_ERROR: { - ERR_FAIL_V(Vector<uint8_t>()); } break; default: { @@ -1345,8 +1320,9 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code) token_array.push_back(token); - if (tt.get_token() == TK_EOF) + if (tt.get_token() == TK_EOF) { break; + } tt.advance(); } @@ -1383,12 +1359,12 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code) //save identifiers for (Map<int, StringName>::Element *E = rev_identifier_map.front(); E; E = E->next()) { - CharString cs = String(E->get()).utf8(); int len = cs.length() + 1; int extra = 4 - (len % 4); - if (extra == 4) + if (extra == 4) { extra = 0; + } uint8_t ibuf[4]; encode_uint32(len + extra, ibuf); @@ -1404,7 +1380,6 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code) } for (Map<int, Variant>::Element *E = rev_constant_map.front(); E; E = E->next()) { - int len; // Objects cannot be constant, never encode objects Error err = encode_variant(E->get(), nullptr, len, false); @@ -1415,16 +1390,15 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code) } for (Map<int, uint32_t>::Element *E = rev_line_map.front(); E; E = E->next()) { - uint8_t ibuf[8]; encode_uint32(E->key(), &ibuf[0]); encode_uint32(E->get(), &ibuf[4]); - for (int i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) { buf.push_back(ibuf[i]); + } } for (int i = 0; i < token_array.size(); i++) { - uint32_t token = token_array[i]; if (token & ~TOKEN_MASK) { @@ -1442,17 +1416,16 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code) } GDScriptTokenizerBuffer::Token GDScriptTokenizerBuffer::get_token(int p_offset) const { - int offset = token + p_offset; - if (offset < 0 || offset >= tokens.size()) + if (offset < 0 || offset >= tokens.size()) { return TK_EOF; + } return GDScriptTokenizerBuffer::Token(tokens[offset] & TOKEN_MASK); } StringName GDScriptTokenizerBuffer::get_token_identifier(int p_offset) const { - int offset = token + p_offset; ERR_FAIL_INDEX_V(offset, tokens.size(), StringName()); @@ -1463,14 +1436,12 @@ StringName GDScriptTokenizerBuffer::get_token_identifier(int p_offset) const { } GDScriptFunctions::Function GDScriptTokenizerBuffer::get_token_built_in_func(int p_offset) const { - int offset = token + p_offset; ERR_FAIL_INDEX_V(offset, tokens.size(), GDScriptFunctions::FUNC_MAX); return GDScriptFunctions::Function(tokens[offset] >> TOKEN_BITS); } Variant::Type GDScriptTokenizerBuffer::get_token_type(int p_offset) const { - int offset = token + p_offset; ERR_FAIL_INDEX_V(offset, tokens.size(), Variant::NIL); @@ -1478,55 +1449,57 @@ Variant::Type GDScriptTokenizerBuffer::get_token_type(int p_offset) const { } int GDScriptTokenizerBuffer::get_token_line(int p_offset) const { - int offset = token + p_offset; int pos = lines.find_nearest(offset); - if (pos < 0) + if (pos < 0) { return -1; - if (pos >= lines.size()) + } + if (pos >= lines.size()) { pos = lines.size() - 1; + } uint32_t l = lines.getv(pos); return l & TOKEN_LINE_MASK; } -int GDScriptTokenizerBuffer::get_token_column(int p_offset) const { +int GDScriptTokenizerBuffer::get_token_column(int p_offset) const { int offset = token + p_offset; int pos = lines.find_nearest(offset); - if (pos < 0) + if (pos < 0) { return -1; - if (pos >= lines.size()) + } + if (pos >= lines.size()) { pos = lines.size() - 1; + } uint32_t l = lines.getv(pos); return l >> TOKEN_LINE_BITS; } -int GDScriptTokenizerBuffer::get_token_line_indent(int p_offset) const { +int GDScriptTokenizerBuffer::get_token_line_indent(int p_offset) const { int offset = token + p_offset; ERR_FAIL_INDEX_V(offset, tokens.size(), 0); return tokens[offset] >> TOKEN_BITS; } -const Variant &GDScriptTokenizerBuffer::get_token_constant(int p_offset) const { +const Variant &GDScriptTokenizerBuffer::get_token_constant(int p_offset) const { int offset = token + p_offset; ERR_FAIL_INDEX_V(offset, tokens.size(), nil); uint32_t constant = tokens[offset] >> TOKEN_BITS; ERR_FAIL_UNSIGNED_INDEX_V(constant, (uint32_t)constants.size(), nil); return constants[constant]; } -String GDScriptTokenizerBuffer::get_token_error(int p_offset) const { +String GDScriptTokenizerBuffer::get_token_error(int p_offset) const { ERR_FAIL_V(String()); } void GDScriptTokenizerBuffer::advance(int p_amount) { - ERR_FAIL_INDEX(p_amount + token, tokens.size()); token += p_amount; } -GDScriptTokenizerBuffer::GDScriptTokenizerBuffer() { +GDScriptTokenizerBuffer::GDScriptTokenizerBuffer() { token = 0; } diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index 180ec3c77e..32603c010f 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -176,11 +176,10 @@ public: virtual bool is_ignoring_warnings() const = 0; #endif // DEBUG_ENABLED - virtual ~GDScriptTokenizer(){}; + virtual ~GDScriptTokenizer() {} }; class GDScriptTokenizerText : public GDScriptTokenizer { - enum { MAX_LOOKAHEAD = 4, TK_RB_SIZE = MAX_LOOKAHEAD * 2 + 1 @@ -252,7 +251,6 @@ public: }; class GDScriptTokenizerBuffer : public GDScriptTokenizer { - enum { TOKEN_BYTE_MASK = 0x80, diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index b2c6b0e1ab..330530be80 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -29,13 +29,13 @@ /*************************************************************************/ #include "gdscript_extend_parser.h" + #include "../gdscript.h" #include "core/io/json.h" #include "gdscript_language_protocol.h" #include "gdscript_workspace.h" void ExtendGDScriptParser::update_diagnostics() { - diagnostics.clear(); if (has_error()) { @@ -80,12 +80,10 @@ void ExtendGDScriptParser::update_diagnostics() { } void ExtendGDScriptParser::update_symbols() { - members.clear(); const GDScriptParser::Node *head = get_parse_tree(); if (const GDScriptParser::ClassNode *gdclass = dynamic_cast<const GDScriptParser::ClassNode *>(head)) { - parse_class_symbol(gdclass, class_symbol); for (int i = 0; i < class_symbol.children.size(); i++) { @@ -141,15 +139,15 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) { } void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p_class, lsp::DocumentSymbol &r_symbol) { - const String uri = get_uri(); r_symbol.uri = uri; r_symbol.script_path = path; r_symbol.children.clear(); r_symbol.name = p_class->name; - if (r_symbol.name.empty()) + if (r_symbol.name.empty()) { r_symbol.name = path.get_file(); + } r_symbol.kind = lsp::SymbolKind::Class; r_symbol.deprecated = false; r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_class->line); @@ -161,7 +159,6 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p r_symbol.documentation = parse_documentation(is_root_class ? 0 : LINE_NUMBER_TO_INDEX(p_class->line), is_root_class); for (int i = 0; i < p_class->variables.size(); ++i) { - const GDScriptParser::ClassNode::Member &m = p_class->variables[i]; lsp::DocumentSymbol symbol; @@ -289,7 +286,6 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p } void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionNode *p_func, lsp::DocumentSymbol &r_symbol) { - const String uri = get_uri(); r_symbol.name = p_func->name; @@ -384,8 +380,9 @@ String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) { int step = p_docs_down ? 1 : -1; int start_line = p_docs_down ? p_line : p_line - 1; for (int i = start_line; true; i += step) { - - if (i < 0 || i >= lines.size()) break; + if (i < 0 || i >= lines.size()) { + break; + } String line_comment = lines[i].strip_edges(true, false); if (line_comment.begins_with("#")) { @@ -408,22 +405,20 @@ String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) { } String ExtendGDScriptParser::get_text_for_completion(const lsp::Position &p_cursor) const { - String longthing; int len = lines.size(); for (int i = 0; i < len; i++) { - if (i == p_cursor.line) { longthing += lines[i].substr(0, p_cursor.character); longthing += String::chr(0xFFFF); //not unicode, represents the cursor longthing += lines[i].substr(p_cursor.character, lines[i].size()); } else { - longthing += lines[i]; } - if (i != len - 1) + if (i != len - 1) { longthing += "\n"; + } } return longthing; @@ -433,7 +428,6 @@ String ExtendGDScriptParser::get_text_for_lookup_symbol(const lsp::Position &p_c String longthing; int len = lines.size(); for (int i = 0; i < len; i++) { - if (i == p_cursor.line) { String line = lines[i]; String first_part = line.substr(0, p_cursor.character); @@ -457,19 +451,18 @@ String ExtendGDScriptParser::get_text_for_lookup_symbol(const lsp::Position &p_c } longthing += last_part; } else { - longthing += lines[i]; } - if (i != len - 1) + if (i != len - 1) { longthing += "\n"; + } } return longthing; } String ExtendGDScriptParser::get_identifier_under_position(const lsp::Position &p_position, Vector2i &p_offset) const { - ERR_FAIL_INDEX_V(p_position.line, lines.size(), ""); String line = lines[p_position.line]; ERR_FAIL_INDEX_V(p_position.character, line.size(), ""); @@ -524,7 +517,6 @@ const lsp::DocumentSymbol *ExtendGDScriptParser::search_symbol_defined_at_line(i } Error ExtendGDScriptParser::get_left_function_call(const lsp::Position &p_position, lsp::Position &r_func_pos, int &r_arg_index) const { - ERR_FAIL_INDEX_V(p_position.line, lines.size(), ERR_INVALID_PARAMETER); int bracket_stack = 0; @@ -576,7 +568,6 @@ const lsp::DocumentSymbol *ExtendGDScriptParser::get_symbol_defined_at_line(int } const lsp::DocumentSymbol *ExtendGDScriptParser::get_member_symbol(const String &p_name, const String &p_subclass) const { - if (p_subclass.empty()) { const lsp::DocumentSymbol *const *ptr = members.getptr(p_name); if (ptr) { @@ -599,12 +590,9 @@ const List<lsp::DocumentLink> &ExtendGDScriptParser::get_document_links() const } const Array &ExtendGDScriptParser::get_member_completions() { - if (member_completions.empty()) { - const String *name = members.next(nullptr); while (name) { - const lsp::DocumentSymbol *symbol = members.get(*name); lsp::CompletionItem item = symbol->make_completion_item(); item.data = JOIN_SYMBOLS(path, *name); @@ -615,7 +603,6 @@ const Array &ExtendGDScriptParser::get_member_completions() { const String *_class = inner_classes.next(nullptr); while (_class) { - const ClassMembers *inner_class = inner_classes.getptr(*_class); const String *member_name = inner_class->next(nullptr); while (member_name) { @@ -696,7 +683,6 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode Array constants; for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_class->constant_expressions.front(); E; E = E->next()) { - const GDScriptParser::ClassNode::Constant &c = E->value(); const GDScriptParser::ConstantNode *node = dynamic_cast<const GDScriptParser::ConstantNode *>(c.expression); ERR_FAIL_COND_V(!node, class_api); @@ -765,7 +751,6 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode } Dictionary ExtendGDScriptParser::generate_api() const { - Dictionary api; const GDScriptParser::Node *head = get_parse_tree(); if (const GDScriptParser::ClassNode *gdclass = dynamic_cast<const GDScriptParser::ClassNode *>(head)) { diff --git a/modules/gdscript/language_server/gdscript_extend_parser.h b/modules/gdscript/language_server/gdscript_extend_parser.h index 43dfce994b..0c031d7883 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.h +++ b/modules/gdscript/language_server/gdscript_extend_parser.h @@ -50,7 +50,6 @@ typedef HashMap<String, const lsp::DocumentSymbol *> ClassMembers; class ExtendGDScriptParser : public GDScriptParser { - String path; Vector<String> lines; diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index 69662e96f7..2a67d2ff4f 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "gdscript_language_protocol.h" + #include "core/io/json.h" #include "core/os/copymem.h" #include "core/project_settings.h" @@ -47,10 +48,11 @@ Error GDScriptLanguageProtocol::LSPeer::handle_data() { ERR_FAIL_COND_V_MSG(true, ERR_OUT_OF_MEMORY, "Response header too big"); } Error err = connection->get_partial_data(&req_buf[req_pos], 1, read); - if (err != OK) + if (err != OK) { return FAILED; - else if (read != 1) // Busy, wait until next poll + } else if (read != 1) { // Busy, wait until next poll return ERR_BUSY; + } char *r = (char *)req_buf; int l = req_pos; @@ -75,10 +77,11 @@ Error GDScriptLanguageProtocol::LSPeer::handle_data() { ERR_FAIL_COND_V_MSG(req_pos >= LSP_MAX_BUFFER_SIZE, ERR_OUT_OF_MEMORY, "Response content too big"); } Error err = connection->get_partial_data(&req_buf[req_pos], 1, read); - if (err != OK) + if (err != OK) { return FAILED; - else if (read != 1) + } else if (read != 1) { return ERR_BUSY; + } req_pos++; } @@ -145,7 +148,6 @@ String GDScriptLanguageProtocol::process_message(const String &p_text) { } String GDScriptLanguageProtocol::format_output(const String &p_text) { - String header = "Content-Length: "; CharString charstr = p_text.utf8(); size_t len = charstr.length(); @@ -160,7 +162,7 @@ void GDScriptLanguageProtocol::_bind_methods() { ClassDB::bind_method(D_METHOD("initialized", "params"), &GDScriptLanguageProtocol::initialized); ClassDB::bind_method(D_METHOD("on_client_connected"), &GDScriptLanguageProtocol::on_client_connected); ClassDB::bind_method(D_METHOD("on_client_disconnected"), &GDScriptLanguageProtocol::on_client_disconnected); - ClassDB::bind_method(D_METHOD("notify_client", "p_method", "p_params"), &GDScriptLanguageProtocol::notify_client, DEFVAL(Variant()), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("notify_client", "method", "params"), &GDScriptLanguageProtocol::notify_client, DEFVAL(Variant()), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("is_smart_resolve_enabled"), &GDScriptLanguageProtocol::is_smart_resolve_enabled); ClassDB::bind_method(D_METHOD("get_text_document"), &GDScriptLanguageProtocol::get_text_document); ClassDB::bind_method(D_METHOD("get_workspace"), &GDScriptLanguageProtocol::get_workspace); @@ -168,7 +170,6 @@ void GDScriptLanguageProtocol::_bind_methods() { } Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) { - lsp::InitializeResult ret; String root_uri = p_params["rootUri"]; @@ -183,13 +184,14 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) { if (root_uri.length() && is_same_workspace) { workspace->root_uri = root_uri; } else { - workspace->root_uri = "file://" + workspace->root; Dictionary params; params["path"] = workspace->root; - Dictionary request = make_notification("gdscrip_client/changeWorkspace", params); + Dictionary request = make_notification("gdscript_client/changeWorkspace", params); + ERR_FAIL_COND_V_MSG(!clients.has(latest_client_id), ret.to_json(), + vformat("GDScriptLanguageProtocol: Can't initialize invalid peer '%d'.", latest_client_id)); Ref<LSPeer> peer = clients.get(latest_client_id); if (peer != nullptr) { String msg = JSON::print(request); @@ -208,12 +210,10 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) { } void GDScriptLanguageProtocol::initialized(const Variant &p_params) { - lsp::GodotCapabilities capabilities; DocData *doc = EditorHelp::get_doc_data(); for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) { - lsp::GodotNativeClassInfo gdclass; gdclass.name = E->get().name; gdclass.class_doc = &(E->get()); @@ -271,8 +271,11 @@ void GDScriptLanguageProtocol::stop() { void GDScriptLanguageProtocol::notify_client(const String &p_method, const Variant &p_params, int p_client_id) { if (p_client_id == -1) { + ERR_FAIL_COND_MSG(latest_client_id == -1, + "GDScript LSP: Can't notify client as none was connected."); p_client_id = latest_client_id; } + ERR_FAIL_COND(!clients.has(p_client_id)); Ref<LSPeer> peer = clients.get(p_client_id); ERR_FAIL_COND(peer == nullptr); @@ -293,13 +296,10 @@ bool GDScriptLanguageProtocol::is_goto_native_symbols_enabled() const { GDScriptLanguageProtocol::GDScriptLanguageProtocol() { server.instance(); singleton = this; - _initialized = false; workspace.instance(); text_document.instance(); set_scope("textDocument", text_document.ptr()); set_scope("completionItem", text_document.ptr()); set_scope("workspace", workspace.ptr()); workspace->root = ProjectSettings::get_singleton()->get_resource_path(); - latest_client_id = 0; - next_client_id = 0; } diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h index d929fd255d..cf5242e8c5 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.h +++ b/modules/gdscript/language_server/gdscript_language_protocol.h @@ -70,8 +70,8 @@ private: HashMap<int, Ref<LSPeer>> clients; Ref<TCP_Server> server; - int latest_client_id; - int next_client_id; + int latest_client_id = 0; + int next_client_id = 0; Ref<GDScriptTextDocument> text_document; Ref<GDScriptWorkspace> workspace; @@ -82,7 +82,7 @@ private: String process_message(const String &p_text); String format_output(const String &p_text); - bool _initialized; + bool _initialized = false; protected: static void _bind_methods(); diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp index e1d86ecdd4..3387d262f8 100644 --- a/modules/gdscript/language_server/gdscript_language_server.cpp +++ b/modules/gdscript/language_server/gdscript_language_server.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "gdscript_language_server.h" + #include "core/os/file_access.h" #include "core/os/os.h" #include "editor/editor_log.h" @@ -48,7 +49,6 @@ GDScriptLanguageServer::GDScriptLanguageServer() { } void GDScriptLanguageServer::_notification(int p_what) { - switch (p_what) { case NOTIFICATION_ENTER_TREE: start(); diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index f065b33570..c6fe3169dc 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "gdscript_text_document.h" + #include "../gdscript.h" #include "core/os/os.h" #include "editor/editor_settings.h" @@ -85,19 +86,15 @@ void GDScriptTextDocument::notify_client_show_symbol(const lsp::DocumentSymbol * } void GDScriptTextDocument::initialize() { - if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { - const HashMap<StringName, ClassMembers> &native_members = GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members; const StringName *class_ptr = native_members.next(nullptr); while (class_ptr) { - const ClassMembers &members = native_members.get(*class_ptr); const String *name = members.next(nullptr); while (name) { - const lsp::DocumentSymbol *symbol = members.get(*name); lsp::CompletionItem item = symbol->make_completion_item(); item.data = JOIN_SYMBOLS(String(*class_ptr), *name); @@ -112,7 +109,6 @@ void GDScriptTextDocument::initialize() { } Variant GDScriptTextDocument::nativeSymbol(const Dictionary &p_params) { - Variant ret; lsp::NativeSymbolInspectParams params; @@ -142,7 +138,6 @@ Array GDScriptTextDocument::documentSymbol(const Dictionary &p_params) { } Array GDScriptTextDocument::completion(const Dictionary &p_params) { - Array arr; lsp::CompletionParams params; @@ -153,12 +148,10 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) { GDScriptLanguageProtocol::get_singleton()->get_workspace()->completion(params, &options); if (!options.empty()) { - int i = 0; arr.resize(options.size()); for (const List<ScriptCodeCompletionOption>::Element *E = options.front(); E; E = E->next()) { - const ScriptCodeCompletionOption &option = E->get(); lsp::CompletionItem item; item.label = option.display; @@ -201,11 +194,9 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) { i++; } } else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { - arr = native_member_completions.duplicate(); for (Map<String, ExtendGDScriptParser *>::Element *E = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.front(); E; E = E->next()) { - ExtendGDScriptParser *script = E->get(); const Array &items = script->get_member_completions(); @@ -220,7 +211,6 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) { } Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) { - lsp::CompletionItem item; item.load(p_params); @@ -230,18 +220,15 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) { const lsp::DocumentSymbol *symbol = nullptr; if (data.get_type() == Variant::DICTIONARY) { - params.load(p_params["data"]); symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_symbol(params, item.label, item.kind == lsp::CompletionItemKind::Method || item.kind == lsp::CompletionItemKind::Function); } else if (data.get_type() == Variant::STRING) { - String query = data; Vector<String> param_symbols = query.split(SYMBOL_SEPERATOR, false); if (param_symbols.size() >= 2) { - String class_ = param_symbols[0]; StringName class_name = class_; String member_name = param_symbols[param_symbols.size() - 1]; @@ -313,13 +300,11 @@ Array GDScriptTextDocument::colorPresentation(const Dictionary &p_params) { } Variant GDScriptTextDocument::hover(const Dictionary &p_params) { - lsp::TextDocumentPositionParams params; params.load(p_params); const lsp::DocumentSymbol *symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_symbol(params); if (symbol) { - lsp::Hover hover; hover.contents = symbol->render(); hover.range.start = params.position; @@ -327,7 +312,6 @@ Variant GDScriptTextDocument::hover(const Dictionary &p_params) { return hover.to_json(); } else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { - Dictionary ret; Array contents; List<const lsp::DocumentSymbol *> list; diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 32fc8f36f0..a203b9bfdb 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "gdscript_workspace.h" + #include "../gdscript.h" #include "../gdscript_parser.h" #include "core/project_settings.h" @@ -41,12 +42,12 @@ void GDScriptWorkspace::_bind_methods() { ClassDB::bind_method(D_METHOD("symbol"), &GDScriptWorkspace::symbol); - ClassDB::bind_method(D_METHOD("parse_script", "p_path", "p_content"), &GDScriptWorkspace::parse_script); - ClassDB::bind_method(D_METHOD("parse_local_script", "p_path"), &GDScriptWorkspace::parse_local_script); - ClassDB::bind_method(D_METHOD("get_file_path", "p_uri"), &GDScriptWorkspace::get_file_path); - ClassDB::bind_method(D_METHOD("get_file_uri", "p_path"), &GDScriptWorkspace::get_file_uri); - ClassDB::bind_method(D_METHOD("publish_diagnostics", "p_path"), &GDScriptWorkspace::publish_diagnostics); - ClassDB::bind_method(D_METHOD("generate_script_api", "p_path"), &GDScriptWorkspace::generate_script_api); + ClassDB::bind_method(D_METHOD("parse_script", "path", "content"), &GDScriptWorkspace::parse_script); + ClassDB::bind_method(D_METHOD("parse_local_script", "path"), &GDScriptWorkspace::parse_local_script); + ClassDB::bind_method(D_METHOD("get_file_path", "uri"), &GDScriptWorkspace::get_file_path); + ClassDB::bind_method(D_METHOD("get_file_uri", "path"), &GDScriptWorkspace::get_file_uri); + ClassDB::bind_method(D_METHOD("publish_diagnostics", "path"), &GDScriptWorkspace::publish_diagnostics); + ClassDB::bind_method(D_METHOD("generate_script_api", "path"), &GDScriptWorkspace::generate_script_api); } void GDScriptWorkspace::remove_cache_parser(const String &p_path) { @@ -71,7 +72,6 @@ void GDScriptWorkspace::remove_cache_parser(const String &p_path) { } const lsp::DocumentSymbol *GDScriptWorkspace::get_native_symbol(const String &p_class, const String &p_member) const { - StringName class_name = p_class; StringName empty; @@ -185,11 +185,12 @@ Array GDScriptWorkspace::symbol(const Dictionary &p_params) { } Error GDScriptWorkspace::initialize() { - if (initialized) return OK; + if (initialized) { + return OK; + } DocData *doc = EditorHelp::get_doc_data(); for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) { - const DocData::ClassDoc &class_data = E->value(); lsp::DocumentSymbol class_symbol; String class_name = E->key(); @@ -314,14 +315,12 @@ Error GDScriptWorkspace::initialize() { } Error GDScriptWorkspace::parse_script(const String &p_path, const String &p_content) { - ExtendGDScriptParser *parser = memnew(ExtendGDScriptParser); Error err = parser->parse(p_content, p_path); Map<String, ExtendGDScriptParser *>::Element *last_parser = parse_results.find(p_path); Map<String, ExtendGDScriptParser *>::Element *last_script = scripts.find(p_path); if (err == OK) { - remove_cache_parser(p_path); parse_results[p_path] = parser; scripts[p_path] = parser; @@ -377,15 +376,15 @@ void GDScriptWorkspace::publish_diagnostics(const String &p_path) { } void GDScriptWorkspace::_get_owners(EditorFileSystemDirectory *efsd, String p_path, List<String> &owners) { - if (!efsd) + if (!efsd) { return; + } for (int i = 0; i < efsd->get_subdir_count(); i++) { _get_owners(efsd->get_subdir(i), p_path, owners); } for (int i = 0; i < efsd->get_file_count(); i++) { - Vector<String> deps = efsd->get_file_deps(i); bool found = false; for (int j = 0; j < deps.size(); j++) { @@ -394,8 +393,9 @@ void GDScriptWorkspace::_get_owners(EditorFileSystemDirectory *efsd, String p_pa break; } } - if (!found) + if (!found) { continue; + } owners.push_back(efsd->get_file_path(i)); } @@ -421,7 +421,6 @@ Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) { } void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<ScriptCodeCompletionOption> *r_options) { - String path = get_file_path(p_params.textDocument.uri); String call_hint; bool forced = false; @@ -437,12 +436,10 @@ void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<S } const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocumentPositionParams &p_doc_pos, const String &p_symbol_name, bool p_func_requred) { - const lsp::DocumentSymbol *symbol = nullptr; String path = get_file_path(p_doc_pos.textDocument.uri); if (const ExtendGDScriptParser *parser = get_parse_result(path)) { - String symbol_identifier = p_symbol_name; Vector<String> identifier_parts = symbol_identifier.split("("); if (identifier_parts.size()) { @@ -457,19 +454,14 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu } if (!symbol_identifier.empty()) { - if (ScriptServer::is_global_class(symbol_identifier)) { - String class_path = ScriptServer::get_global_class_path(symbol_identifier); symbol = get_script_symbol(class_path); } else { - ScriptLanguage::LookupResult ret; if (OK == GDScriptLanguage::get_singleton()->lookup_code(parser->get_text_for_lookup_symbol(pos, symbol_identifier, p_func_requred), symbol_identifier, path, nullptr, ret)) { - if (ret.type == ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION) { - String target_script_path = path; if (!ret.script.is_null()) { target_script_path = ret.script->get_path(); @@ -480,7 +472,6 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu } } else { - String member = ret.class_member; if (member.empty() && symbol_identifier != ret.class_name) { member = symbol_identifier; @@ -498,10 +489,8 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu } void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionParams &p_doc_pos, List<const lsp::DocumentSymbol *> &r_list) { - String path = get_file_path(p_doc_pos.textDocument.uri); if (const ExtendGDScriptParser *parser = get_parse_result(path)) { - String symbol_identifier; Vector2i offset; symbol_identifier = parser->get_identifier_under_position(p_doc_pos.position, offset); @@ -525,7 +514,6 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP const HashMap<String, ClassMembers> &inner_classes = script->get_inner_classes(); const String *_class = inner_classes.next(nullptr); while (_class) { - const ClassMembers *inner_class = inner_classes.getptr(*_class); if (const lsp::DocumentSymbol *const *symbol = inner_class->getptr(symbol_identifier)) { r_list.push_back(*symbol); @@ -538,7 +526,6 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP } const lsp::DocumentSymbol *GDScriptWorkspace::resolve_native_symbol(const lsp::NativeSymbolInspectParams &p_params) { - if (Map<StringName, lsp::DocumentSymbol>::Element *E = native_symbols.find(p_params.native_class)) { const lsp::DocumentSymbol &symbol = E->get(); if (p_params.symbol_name.empty() || p_params.symbol_name == symbol.name) { @@ -574,12 +561,10 @@ Dictionary GDScriptWorkspace::generate_script_api(const String &p_path) { Error GDScriptWorkspace::resolve_signature(const lsp::TextDocumentPositionParams &p_doc_pos, lsp::SignatureHelp &r_signature) { if (const ExtendGDScriptParser *parser = get_parse_result(get_file_path(p_doc_pos.textDocument.uri))) { - lsp::TextDocumentPositionParams text_pos; text_pos.textDocument = p_doc_pos.textDocument; if (parser->get_left_function_call(p_doc_pos.position, text_pos.position, r_signature.activeParameter) == OK) { - List<const lsp::DocumentSymbol *> symbols; if (const lsp::DocumentSymbol *symbol = resolve_symbol(text_pos)) { @@ -591,7 +576,6 @@ Error GDScriptWorkspace::resolve_signature(const lsp::TextDocumentPositionParams for (List<const lsp::DocumentSymbol *>::Element *E = symbols.front(); E; E = E->next()) { const lsp::DocumentSymbol *symbol = E->get(); if (symbol->kind == lsp::SymbolKind::Method || symbol->kind == lsp::SymbolKind::Function) { - lsp::SignatureInformation signature_info; signature_info.label = symbol->detail; signature_info.documentation = symbol->render(); diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp index 124fcbfed8..cf27a1578c 100644 --- a/modules/gdscript/language_server/lsp.hpp +++ b/modules/gdscript/language_server/lsp.hpp @@ -149,7 +149,6 @@ struct Location { * Represents a link between a source and a target location. */ struct LocationLink { - /** * Span of the origin of this link. * @@ -220,7 +219,6 @@ struct DocumentLinkParams { * text document or a web site. */ struct DocumentLink { - /** * The range this link applies to. */ @@ -282,7 +280,9 @@ struct Command { Dictionary dict; dict["title"] = title; dict["command"] = command; - if (arguments.size()) dict["arguments"] = arguments; + if (arguments.size()) { + dict["arguments"] = arguments; + } return dict; } }; @@ -486,7 +486,7 @@ struct TextDocumentSyncOptions { * If present save notifications are sent to the server. If omitted the notification should not be * sent. */ - SaveOptions save; + bool save = false; Dictionary to_json() { Dictionary dict; @@ -494,7 +494,7 @@ struct TextDocumentSyncOptions { dict["willSave"] = willSave; dict["openClose"] = openClose; dict["change"] = change; - dict["save"] = save.to_json(); + dict["save"] = save; return dict; } }; @@ -946,16 +946,24 @@ struct CompletionItem { dict["preselect"] = preselect; dict["sortText"] = sortText; dict["filterText"] = filterText; - if (commitCharacters.size()) dict["commitCharacters"] = commitCharacters; + if (commitCharacters.size()) { + dict["commitCharacters"] = commitCharacters; + } dict["command"] = command.to_json(); } return dict; } void load(const Dictionary &p_dict) { - if (p_dict.has("label")) label = p_dict["label"]; - if (p_dict.has("kind")) kind = p_dict["kind"]; - if (p_dict.has("detail")) detail = p_dict["detail"]; + if (p_dict.has("label")) { + label = p_dict["label"]; + } + if (p_dict.has("kind")) { + kind = p_dict["kind"]; + } + if (p_dict.has("detail")) { + detail = p_dict["detail"]; + } if (p_dict.has("documentation")) { Variant doc = p_dict["documentation"]; if (doc.get_type() == Variant::STRING) { @@ -965,12 +973,24 @@ struct CompletionItem { documentation.value = v["value"]; } } - if (p_dict.has("deprecated")) deprecated = p_dict["deprecated"]; - if (p_dict.has("preselect")) preselect = p_dict["preselect"]; - if (p_dict.has("sortText")) sortText = p_dict["sortText"]; - if (p_dict.has("filterText")) filterText = p_dict["filterText"]; - if (p_dict.has("insertText")) insertText = p_dict["insertText"]; - if (p_dict.has("data")) data = p_dict["data"]; + if (p_dict.has("deprecated")) { + deprecated = p_dict["deprecated"]; + } + if (p_dict.has("preselect")) { + preselect = p_dict["preselect"]; + } + if (p_dict.has("sortText")) { + sortText = p_dict["sortText"]; + } + if (p_dict.has("filterText")) { + filterText = p_dict["filterText"]; + } + if (p_dict.has("insertText")) { + insertText = p_dict["insertText"]; + } + if (p_dict.has("data")) { + data = p_dict["data"]; + } } }; @@ -1096,7 +1116,6 @@ struct DocumentedSymbolInformation : public SymbolInformation { * e.g. the range of an identifier. */ struct DocumentSymbol { - /** * The name of this symbol. Will be displayed in the user interface and therefore must not be * an empty string or a string only consisting of white spaces. @@ -1205,7 +1224,6 @@ struct DocumentSymbol { } _FORCE_INLINE_ CompletionItem make_completion_item(bool resolved = false) const { - lsp::CompletionItem item; item.label = name; @@ -1249,7 +1267,6 @@ struct DocumentSymbol { }; struct NativeSymbolInspectParams { - String native_class; String symbol_name; @@ -1281,7 +1298,6 @@ static const String Region = "region"; * Represents a folding range. */ struct FoldingRange { - /** * The zero-based line number from where the folded range starts. */ @@ -1364,7 +1380,6 @@ struct CompletionContext { }; struct CompletionParams : public TextDocumentPositionParams { - /** * The completion context. This is only available if the client specifies * to send this using `ClientCapabilities.textDocument.completion.contextSupport === true` @@ -1405,7 +1420,6 @@ struct Hover { * have a label and a doc-comment. */ struct ParameterInformation { - /** * The label of this parameter information. * @@ -1642,7 +1656,7 @@ struct ServerCapabilities { _FORCE_INLINE_ Dictionary to_json() { Dictionary dict; - dict["textDocumentSync"] = (int)textDocumentSync.change; + dict["textDocumentSync"] = textDocumentSync.to_json(); dict["completionProvider"] = completionProvider.to_json(); signatureHelpProvider.triggerCharacters.push_back(","); signatureHelpProvider.triggerCharacters.push_back("("); @@ -1684,7 +1698,6 @@ struct InitializeResult { }; struct GodotNativeClassInfo { - String name; const DocData::ClassDoc *class_doc = nullptr; const ClassDB::ClassInfo *class_info = nullptr; @@ -1699,7 +1712,6 @@ struct GodotNativeClassInfo { /** Features not included in the standard lsp specifications */ struct GodotCapabilities { - /** * Native class list */ @@ -1718,7 +1730,6 @@ struct GodotCapabilities { /** Format BBCode documentation from DocData to markdown */ static String marked_documentation(const String &p_bbcode) { - String markdown = p_bbcode.strip_edges(); Vector<String> lines = markdown.split("\n"); diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 62b9d94d6c..0625123530 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -54,12 +54,10 @@ Ref<ResourceFormatSaverGDScript> resource_saver_gd; #endif // !GDSCRIPT_NO_LSP class EditorExportGDScript : public EditorExportPlugin { - GDCLASS(EditorExportGDScript, EditorExportPlugin); public: virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features) { - int script_mode = EditorExportPreset::MODE_SCRIPT_COMPILED; String script_key; @@ -70,21 +68,21 @@ public: script_key = preset->get_script_encryption_key().to_lower(); } - if (!p_path.ends_with(".gd") || script_mode == EditorExportPreset::MODE_SCRIPT_TEXT) + if (!p_path.ends_with(".gd") || script_mode == EditorExportPreset::MODE_SCRIPT_TEXT) { return; + } Vector<uint8_t> file = FileAccess::get_file_as_array(p_path); - if (file.empty()) + if (file.empty()) { return; + } String txt; txt.parse_utf8((const char *)file.ptr(), file.size()); file = GDScriptTokenizerBuffer::parse_code_string(txt); if (!file.empty()) { - if (script_mode == EditorExportPreset::MODE_SCRIPT_ENCRYPTED) { - String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("script.gde"); FileAccess *fa = FileAccess::open(tmp_path, FileAccess::WRITE); @@ -94,19 +92,21 @@ public: int v = 0; if (i * 2 < script_key.length()) { CharType ct = script_key[i * 2]; - if (ct >= '0' && ct <= '9') + if (ct >= '0' && ct <= '9') { ct = ct - '0'; - else if (ct >= 'a' && ct <= 'f') + } else if (ct >= 'a' && ct <= 'f') { ct = 10 + ct - 'a'; + } v |= ct << 4; } if (i * 2 + 1 < script_key.length()) { CharType ct = script_key[i * 2 + 1]; - if (ct >= '0' && ct <= '9') + if (ct >= '0' && ct <= '9') { ct = ct - '0'; - else if (ct >= 'a' && ct <= 'f') + } else if (ct >= 'a' && ct <= 'f') { ct = 10 + ct - 'a'; + } v |= ct; } key.write[i] = v; @@ -127,7 +127,6 @@ public: DirAccess::remove_file_or_error(tmp_path); } else { - add_file(p_path.get_basename() + ".gdc", file, true); } } @@ -135,7 +134,6 @@ public: }; static void _editor_init() { - Ref<EditorExportGDScript> gd_export; gd_export.instance(); EditorExport::get_singleton()->add_export_plugin(gd_export); @@ -151,7 +149,6 @@ static void _editor_init() { #endif // TOOLS_ENABLED void register_gdscript_types() { - ClassDB::register_class<GDScript>(); ClassDB::register_virtual_class<GDScriptFunctionState>(); @@ -171,11 +168,11 @@ void register_gdscript_types() { } void unregister_gdscript_types() { - ScriptServer::unregister_language(script_language_gd); - if (script_language_gd) + if (script_language_gd) { memdelete(script_language_gd); + } ResourceLoader::remove_resource_format_loader(resource_loader_gd); resource_loader_gd.unref(); |