diff options
Diffstat (limited to 'modules/gdscript')
29 files changed, 2134 insertions, 2145 deletions
diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub index 74e653ce43..e58a1d8edc 100644 --- a/modules/gdscript/SCsub +++ b/modules/gdscript/SCsub @@ -1,19 +1,19 @@ #!/usr/bin/env python -Import('env') -Import('env_modules') +Import("env") +Import("env_modules") env_gdscript = env_modules.Clone() env_gdscript.add_source_files(env.modules_sources, "*.cpp") -if env['tools']: +if env["tools"]: env_gdscript.add_source_files(env.modules_sources, "./editor/*.cpp") # Those two modules are required for the language server protocol - if env['module_jsonrpc_enabled'] and env['module_websocket_enabled']: + if env["module_jsonrpc_enabled"] and env["module_websocket_enabled"]: env_gdscript.add_source_files(env.modules_sources, "./language_server/*.cpp") else: # Using a define in the disabled case, to avoid having an extra define # in regular builds where all modules are enabled. - env_gdscript.Append(CPPDEFINES=['GDSCRIPT_NO_LSP']) + env_gdscript.Append(CPPDEFINES=["GDSCRIPT_NO_LSP"]) diff --git a/modules/gdscript/config.py b/modules/gdscript/config.py index a525eedaaa..6fc227e7f5 100644 --- a/modules/gdscript/config.py +++ b/modules/gdscript/config.py @@ -1,16 +1,18 @@ def can_build(env, platform): return True + def configure(env): pass + def get_doc_classes(): return [ "@GDScript", "GDScript", "GDScriptFunctionState", - "GDScriptNativeClass", ] + def get_doc_path(): return "doc_classes" diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 2f6f9f30a4..f04cb4b4c3 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -90,14 +90,18 @@ </return> <argument index="0" name="condition" type="bool"> </argument> + <argument index="1" name="message" type="String" default=""""> + </argument> <description> - Asserts that the [code]condition[/code] is [code]true[/code] . If the [code]condition[/code] is [code]false[/code], an error is generated and the program is halted until you resume it. Only executes in debug builds, or when running the game from the editor. Use it for debugging purposes, to make sure a statement is [code]true[/code] during development. + Asserts that the [code]condition[/code] is [code]true[/code]. If the [code]condition[/code] is [code]false[/code], an error is generated and the program is halted until you resume it. Only executes in debug builds, or when running the game from the editor. Use it for debugging purposes, to make sure a statement is [code]true[/code] during development. + The optional [code]message[/code] argument, if given, is shown in addition to the generic "Assertion failed" message. You can use this to provide additional details about why the assertion failed. [codeblock] # Imagine we always want speed to be between 0 and 20 speed = -10 assert(speed < 20) # True, the program will continue assert(speed >= 0) # False, the program will stop assert(speed >= 0 && speed < 20) # You can also combine the two conditional statements in one check + assert(speed < 20, "speed = %f, but the speed limit is 20" % speed) # Show a message with clarifying details [/codeblock] </description> </method> @@ -564,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) @@ -615,11 +619,11 @@ <argument index="0" name="path" type="String"> </argument> <description> - Loads a resource from the filesystem located at [code]path[/code]. - [b]Note:[/b] Resource paths can be obtained by right-clicking on a resource in the FileSystem dock and choosing [b]Copy Path[/b]. + Loads a resource from the filesystem located at [code]path[/code]. The resource is loaded on the method call (unless it's referenced already elsewhere, e.g. in another script or in the scene), which might cause slight delay, especially when loading scenes. To avoid unnecessary delays when loading something multiple times, either store the resource in a variable or use [method preload]. + [b]Note:[/b] Resource paths can be obtained by right-clicking on a resource in the FileSystem dock and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script. [codeblock] - # Load a scene called main located in the root of the project directory. - var main = load("res://main.tscn") + # Load a scene called main located in the root of the project directory and cache it in a variable. + var main = load("res://main.tscn") # main will contain a PackedScene resource. [/codeblock] [b]Important:[/b] The path must be absolute, a local path will just return [code]null[/code]. </description> @@ -793,11 +797,11 @@ <argument index="0" name="path" type="String"> </argument> <description> - Returns a resource from the filesystem that is loaded during script parsing. - [b]Note:[/b] Resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path". + Returns a [Resource] from the filesystem located at [code]path[/code]. The resource is loaded during script parsing, i.e. is loaded with the script and [method preload] effectively acts as a reference to that resource. Note that the method requires a constant path. If you want to load a resource from a dynamic/variable path, use [method load]. + [b]Note:[/b] Resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script. [codeblock] - # Load a scene called main located in the root of the project directory. - var main = preload("res://main.tscn") + # Instance a scene. + var diamond = preload("res://diamond.tscn").instance() [/codeblock] </description> </method> @@ -1216,7 +1220,7 @@ <description> Returns whether the given class exists in [ClassDB]. [codeblock] - type_exists("Sprite") # Returns true + type_exists("Sprite2D") # Returns true type_exists("Variant") # Returns false [/codeblock] </description> 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 687e1785be..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; } @@ -358,11 +353,11 @@ List<String> GDScriptSyntaxHighlighter::get_supported_languages() { } void GDScriptSyntaxHighlighter::_update_cache() { - font_color = text_editor->get_color("font_color"); - symbol_color = text_editor->get_color("symbol_color"); - function_color = text_editor->get_color("function_color"); - number_color = text_editor->get_color("number_color"); - member_color = text_editor->get_color("member_variable_color"); + font_color = text_editor->get_theme_color("font_color"); + symbol_color = text_editor->get_theme_color("symbol_color"); + function_color = text_editor->get_theme_color("function_color"); + number_color = text_editor->get_theme_color("number_color"); + member_color = text_editor->get_theme_color("member_variable_color"); const String text_editor_color_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme"); const bool default_theme = text_editor_color_theme == "Default"; diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index c641ce37c5..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,32 +97,28 @@ 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(NULL); + instance->owner->set_script_instance(nullptr); { MutexLock lock(GDScriptLanguage::singleton->lock); instances.erase(p_owner); } - - ERR_FAIL_COND_V(r_error.error != Callable::CallError::CALL_OK, NULL); //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) { @@ -138,7 +128,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr r_error.error = Callable::CallError::CALL_OK; REF ref; - Object *owner = NULL; + Object *owner = nullptr; GDScript *_baseptr = this; while (_baseptr->_base) { @@ -158,7 +148,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr ref = REF(r); } - GDScriptInstance *instance = _create_instance(p_args, p_argcount, owner, r != NULL, r_error); + GDScriptInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error); if (!instance) { if (ref.is_null()) { memdelete(owner); //no owner, sorry @@ -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,23 +287,22 @@ 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 (ScriptDebugger::get_singleton()) { + 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() + "'"); } - ERR_FAIL_V_MSG(NULL, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type '" + p_this->get_class() + "'" + "."); + ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type '" + p_this->get_class() + "'" + "."); } } Callable::CallError unchecked_error; - return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error); + return _create_instance(nullptr, 0, p_this, Object::cast_to<Reference>(p_this) != nullptr, unchecked_error); } PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) { @@ -333,29 +312,28 @@ PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) _update_exports(); return si; #else - return NULL; + return nullptr; #endif } 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()) { - + 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 @@ -556,7 +557,7 @@ Error GDScript::reload(bool p_keep_state) { GDScriptParser parser; Error err = parser.parse(source, basedir, false, path); if (err) { - if (ScriptDebugger::get_singleton()) { + if (EngineDebugger::is_active()) { GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), parser.get_error_line(), "Parser Error: " + parser.get_error()); } _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_error_line(), ("Parse Error: " + parser.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT); @@ -569,9 +570,8 @@ Error GDScript::reload(bool p_keep_state) { err = compiler.compile(&parser, this, p_keep_state); if (err) { - if (can_run) { - if (ScriptDebugger::get_singleton()) { + if (EngineDebugger::is_active()) { GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error()); } _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT); @@ -583,77 +583,29 @@ Error GDScript::reload(bool p_keep_state) { #ifdef DEBUG_ENABLED for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) { const GDScriptWarning &warning = E->get(); - if (ScriptDebugger::get_singleton()) { + if (EngineDebugger::is_active()) { Vector<ScriptLanguage::StackInfo> si; - ScriptDebugger::get_singleton()->send_error("", get_path(), warning.line, warning.get_name(), warning.get_message(), ERR_HANDLER_WARNING, si); + EngineDebugger::get_script_debugger()->send_error("", get_path(), warning.line, warning.get_name(), warning.get_message(), ERR_HANDLER_WARNING, si); } } #endif valid = true; - for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) { - + for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) { _set_subclass_path(E->get(), path); } - // Copy the base rpc methods so we don't mask their IDs. - rpc_functions.clear(); - rpc_variables.clear(); - if (base.is_valid()) { - rpc_functions = base->rpc_functions; - rpc_variables = base->rpc_variables; - } - - GDScript *cscript = this; - Map<StringName, Ref<GDScript> >::Element *sub_E = subclasses.front(); - while (cscript) { - // RPC Methods - for (Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.front(); E; E = E->next()) { - if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) { - ScriptNetData nd; - nd.name = E->key(); - nd.mode = E->get()->get_rpc_mode(); - if (-1 == rpc_functions.find(nd)) { - rpc_functions.push_back(nd); - } - } - } - // RSet - for (Map<StringName, MemberInfo>::Element *E = cscript->member_indices.front(); E; E = E->next()) { - if (E->get().rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) { - ScriptNetData nd; - nd.name = E->key(); - nd.mode = E->get().rpc_mode; - if (-1 == rpc_variables.find(nd)) { - rpc_variables.push_back(nd); - } - } - } - - if (cscript != this) - sub_E = sub_E->next(); - - if (sub_E) - cscript = sub_E->get().ptr(); - else - cscript = NULL; - } - - // Sort so we are 100% that they are always the same. - rpc_functions.sort_custom<SortNetData>(); - rpc_variables.sort_custom<SortNetData>(); + _init_rpc_methods_properties(); return OK; } 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(); @@ -683,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; } @@ -710,13 +666,17 @@ 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_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED); - return rpc_functions[p_rset_member_id].mode; + if (p_rset_member_id >= rpc_variables.size()) { + return MultiplayerAPI::RPC_MODE_DISABLED; + } + return rpc_variables[p_rset_member_id].mode; } MultiplayerAPI::RPCMode GDScript::get_rset_mode(const StringName &p_variable) const { @@ -724,16 +684,13 @@ 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(NULL, p_args, p_argcount, r_error); + return E->get()->call(nullptr, p_args, p_argcount, r_error); } top = top->_base; } @@ -744,25 +701,20 @@ 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; } } { - const Map<StringName, Ref<GDScript> >::Element *E = subclasses.find(p_name); + const Map<StringName, Ref<GDScript>>::Element *E = subclasses.find(p_name); if (E) { - r_ret = E->get(); return true; } @@ -771,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; } @@ -779,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); @@ -843,7 +789,6 @@ Error GDScript::load_byte_code(const String &p_path) { memdelete(fae); } else { - bytecode = FileAccess::get_file_as_array(p_path); } @@ -852,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; @@ -876,21 +823,20 @@ Error GDScript::load_byte_code(const String &p_path) { valid = true; - for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) { - + for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) { _set_subclass_path(E->get(), path); } + _init_rpc_methods_properties(); + return OK; } 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); } @@ -905,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."); } @@ -918,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); } @@ -951,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 { - - for (const Map<StringName, Vector<StringName> >::Element *E = _signals.front(); E; E = E->next()) { +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++) { @@ -978,12 +938,11 @@ void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const { GDScript::GDScript() : script_list(this) { - valid = false; subclass_count = 0; - initializer = NULL; - _base = NULL; - _owner = NULL; + initializer = nullptr; + _base = nullptr; + _owner = nullptr; tool = false; #ifdef TOOLS_ENABLED source_changed_cache = false; @@ -1006,8 +965,8 @@ void GDScript::_save_orphaned_subclasses() { }; Vector<ClassRefWithName> weak_subclasses; // collect subclasses ObjectID and name - for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) { - E->get()->_owner = NULL; //bye, you are no longer owned cause I died + for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) { + E->get()->_owner = nullptr; //bye, you are no longer owned cause I died ClassRefWithName subclass; subclass.id = E->get()->get_instance_id(); subclass.fully_qualified_name = E->get()->fully_qualified_name; @@ -1023,14 +982,75 @@ 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); } } +void GDScript::_init_rpc_methods_properties() { + // Copy the base rpc methods so we don't mask their IDs. + rpc_functions.clear(); + rpc_variables.clear(); + if (base.is_valid()) { + rpc_functions = base->rpc_functions; + rpc_variables = base->rpc_variables; + } + + GDScript *cscript = this; + Map<StringName, Ref<GDScript>>::Element *sub_E = subclasses.front(); + while (cscript) { + // RPC Methods + for (Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.front(); E; E = E->next()) { + if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) { + ScriptNetData nd; + nd.name = E->key(); + nd.mode = E->get()->get_rpc_mode(); + if (-1 == rpc_functions.find(nd)) { + rpc_functions.push_back(nd); + } + } + } + // RSet + for (Map<StringName, MemberInfo>::Element *E = cscript->member_indices.front(); E; E = E->next()) { + if (E->get().rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) { + ScriptNetData nd; + nd.name = E->key(); + nd.mode = E->get().rpc_mode; + if (-1 == rpc_variables.find(nd)) { + rpc_variables.push_back(nd); + } + } + } + + if (cscript != this) { + sub_E = sub_E->next(); + } + + if (sub_E) { + cscript = sub_E->get().ptr(); + } else { + cscript = nullptr; + } + } + + // Sort so we are 100% that they are always the same. + rpc_functions.sort_custom<SortNetData>(); + rpc_variables.sort_custom<SortNetData>(); +} + 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()); } @@ -1051,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); @@ -1086,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; } @@ -1105,16 +1123,14 @@ 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) { if (E->get().getter) { Callable::CallError err; - r_ret = const_cast<GDScriptInstance *>(this)->call(E->get().getter, NULL, 0, err); + r_ret = const_cast<GDScriptInstance *>(this)->call(E->get().getter, nullptr, 0, err); if (err.error == Callable::CallError::CALL_OK) { return true; } @@ -1125,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); @@ -1140,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 }; @@ -1159,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; } @@ -1183,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), NULL, 0, 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")); @@ -1204,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); } @@ -1220,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; @@ -1231,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]); } @@ -1239,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; @@ -1263,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); @@ -1289,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; @@ -1303,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; @@ -1316,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 }; @@ -1345,30 +1350,31 @@ void GDScriptInstance::notification(int p_notification) { String GDScriptInstance::to_string(bool *r_valid) { if (has_method(CoreStringNames::get_singleton()->_to_string)) { Callable::CallError ce; - Variant ret = call(CoreStringNames::get_singleton()->_to_string, NULL, 0, ce); + 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(); } @@ -1413,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 @@ -1423,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; @@ -1436,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; } @@ -1444,31 +1447,34 @@ void GDScriptInstance::reload_members() { } GDScriptInstance::GDScriptInstance() { - owner = NULL; + owner = nullptr; base_ref = false; } 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); } } /************* SCRIPT LANGUAGE **************/ -GDScriptLanguage *GDScriptLanguage::singleton = NULL; +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; @@ -1480,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); } @@ -1494,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)); } @@ -1512,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); } @@ -1529,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); @@ -1574,7 +1576,6 @@ void GDScriptLanguage::profiling_start() { } void GDScriptLanguage::profiling_stop() { - #ifdef DEBUG_ENABLED MutexLock lock(this->lock); @@ -1583,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 @@ -1591,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; @@ -1606,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 @@ -1614,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; @@ -1631,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()) { @@ -1652,10 +1652,9 @@ struct GDScriptDepSort { }; void GDScriptLanguage::reload_all_scripts() { - #ifdef DEBUG_ENABLED print_verbose("GDScript: Reloading all scripts"); - List<Ref<GDScript> > scripts; + List<Ref<GDScript>> scripts; { MutexLock lock(this->lock); @@ -1673,8 +1672,7 @@ 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()) { - + 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); @@ -1683,17 +1681,15 @@ 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; + List<Ref<GDScript>> scripts; { MutexLock lock(this->lock); 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(); @@ -1702,32 +1698,30 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so //when someone asks you why dynamically typed languages are easier to write.... - Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant> > > > to_reload; + Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant>>>> to_reload; //as scripts are going to be reloaded, must proceed without locking here scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order - for (List<Ref<GDScript> >::Element *E = scripts.front(); E; E = E->next()) { - + 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> > >()); + 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()]; + Map<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[E->get()]; while (E->get()->instances.front()) { Object *obj = E->get()->instances.front()->get(); //save instance info - List<Pair<StringName, Variant> > state; + 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()); @@ -1742,9 +1736,8 @@ 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()]; + 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); obj->set_script(Variant()); } else { @@ -1755,25 +1748,24 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so #endif - for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get()->pending_reload_state.front(); F; F = F->next()) { + for (Map<ObjectID, List<Pair<StringName, Variant>>>::Element *F = E->get()->pending_reload_state.front(); F; F = F->next()) { map[F->key()] = F->get(); //pending to reload, use this one instead } } } - for (Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) { - + 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(); + 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) @@ -1793,11 +1785,11 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so if (script_instance->is_placeholder() && scr->is_placeholder_fallback_enabled()) { PlaceHolderScriptInstance *placeholder = static_cast<PlaceHolderScriptInstance *>(script_instance); - for (List<Pair<StringName, Variant> >::Element *G = saved_state.front(); G; G = G->next()) { + for (List<Pair<StringName, Variant>>::Element *G = saved_state.front(); G; G = G->next()) { placeholder->property_set_fallback(G->get().first, G->get().second); } } else { - for (List<Pair<StringName, Variant> >::Element *G = saved_state.front(); G; G = G->next()) { + for (List<Pair<StringName, Variant>>::Element *G = saved_state.front(); G; G = G->next()) { script_instance->set(G->get().first, G->get().second); } } @@ -1812,7 +1804,6 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so } void GDScriptLanguage::frame() { - calls = 0; #ifdef DEBUG_ENABLED @@ -1836,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", @@ -1894,13 +1884,12 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "remotesync", "mastersync", "puppetsync", - 0 + nullptr }; const char **w = _reserved_words; while (*w) { - p_words->push_back(*w); w++; } @@ -1911,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); @@ -1927,19 +1914,18 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b String source = f->get_as_utf8_string(); GDScriptParser parser; - parser.parse(source, p_path.get_base_dir(), true, p_path, false, NULL, true); + 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; @@ -1948,7 +1934,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b if (subclass->extends_file) { if (subclass->extends_class.size() == 0) { get_global_class_name(subclass->extends_file, r_base_type); - subclass = NULL; + subclass = nullptr; break; } else { Vector<StringName> extend_classes = subclass->extends_class; @@ -1967,7 +1953,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b subpath = path.get_base_dir().plus_file(subpath).simplify_path(); } - if (OK != subparser.parse(subsource, subpath.get_base_dir(), true, subpath, false, NULL, true)) { + if (OK != subparser.parse(subsource, subpath.get_base_dir(), true, subpath, false, nullptr, true)) { break; } path = subpath; @@ -1988,20 +1974,20 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b } } if (!found) { - subclass = NULL; + subclass = nullptr; break; } } } } else if (subclass->extends_class.size() == 1) { *r_base_type = subclass->extends_class[0]; - subclass = NULL; + subclass = nullptr; } else { break; } } else { *r_base_type = "Reference"; - subclass = NULL; + subclass = nullptr; } } } @@ -2013,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) { @@ -2120,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) + "."); @@ -2162,7 +2148,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) { "UNSAFE_CALL_ARGUMENT", "DEPRECATED_KEYWORD", "STANDALONE_TERNARY", - NULL + nullptr }; return names[(int)p_code]; @@ -2181,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; @@ -2201,7 +2186,7 @@ GDScriptLanguage::GDScriptLanguage() { int dmcs = GLOBAL_DEF("debug/settings/gdscript/max_call_stack", 1024); ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/gdscript/max_call_stack", PropertyInfo(Variant::INT, "debug/settings/gdscript/max_call_stack", PROPERTY_HINT_RANGE, "1024,4096,1,or_greater")); //minimum is 1024 - if (ScriptDebugger::get_singleton()) { + if (EngineDebugger::is_active()) { //debugging enabled! _debug_max_call_stack = dmcs; @@ -2209,7 +2194,7 @@ GDScriptLanguage::GDScriptLanguage() { } else { _debug_max_call_stack = 0; - _call_stack = NULL; + _call_stack = nullptr; } #ifdef DEBUG_ENABLED @@ -2226,11 +2211,10 @@ GDScriptLanguage::GDScriptLanguage() { } GDScriptLanguage::~GDScriptLanguage() { - if (_call_stack) { memdelete_arr(_call_stack); } - singleton = NULL; + singleton = nullptr; } void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass) { @@ -2239,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); @@ -2276,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 + "'."); @@ -2313,7 +2296,7 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S } GDScriptParser parser; - if (OK != parser.parse(source, p_path.get_base_dir(), true, p_path, false, NULL, true)) { + if (OK != parser.parse(source, p_path.get_base_dir(), true, p_path, false, nullptr, true)) { return; } @@ -2323,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); @@ -2350,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 { - return Object::cast_to<GDScript>(*p_resource) != NULL; +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 3a90f0fc20..e770dc3abd 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -31,13 +31,14 @@ #ifndef GDSCRIPT_H #define GDSCRIPT_H +#include "core/debugger/engine_debugger.h" +#include "core/debugger/script_debugger.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/script_language.h" #include "gdscript_function.h" class GDScriptNativeClass : public Reference { - GDCLASS(GDScriptNativeClass, Reference); StringName name; @@ -54,7 +55,6 @@ public: }; class GDScript : public Script { - GDCLASS(GDScript, Script); bool tool; bool valid; @@ -82,8 +82,8 @@ class GDScript : public Script { Map<StringName, Variant> constants; Map<StringName, GDScriptFunction *> member_functions; Map<StringName, MemberInfo> member_indices; //members are just indices to the instanced script. - Map<StringName, Ref<GDScript> > subclasses; - Map<StringName, Vector<StringName> > _signals; + Map<StringName, Ref<GDScript>> subclasses; + Map<StringName, Vector<StringName>> _signals; Vector<ScriptNetData> rpc_functions; Vector<ScriptNetData> rpc_variables; @@ -115,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); @@ -127,13 +129,14 @@ class GDScript : public Script { #ifdef DEBUG_ENABLED - Map<ObjectID, List<Pair<StringName, Variant> > > pending_reload_state; + Map<ObjectID, List<Pair<StringName, Variant>>> pending_reload_state; #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(); protected: bool _get(const StringName &p_name, Variant &r_ret) const; @@ -148,7 +151,9 @@ protected: public: virtual bool is_valid() const { return valid; } - const Map<StringName, Ref<GDScript> > &get_subclasses() const { return subclasses; } + 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; } const GDScriptDataType &get_member_type(const StringName &p_member) const { @@ -204,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); @@ -249,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: @@ -257,7 +264,7 @@ public: virtual bool set(const StringName &p_name, const Variant &p_value); virtual bool get(const StringName &p_name, Variant &r_ret) const; virtual void get_property_list(List<PropertyInfo> *p_properties) const; - virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const; + virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const; virtual void get_method_list(List<MethodInfo> *p_list) const; virtual bool has_method(const StringName &p_method) const; @@ -325,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; @@ -350,7 +358,6 @@ class GDScriptLanguage : public ScriptLanguage { Map<StringName, Variant> named_globals; struct CallLevel { - Variant *stack; GDScriptFunction *function; GDScriptInstance *instance; @@ -389,17 +396,18 @@ 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 (ScriptDebugger::get_singleton()->get_lines_left() > 0 && ScriptDebugger::get_singleton()->get_depth() >= 0) - ScriptDebugger::get_singleton()->set_depth(ScriptDebugger::get_singleton()->get_depth() + 1); + 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 _debug_error = "Stack Overflow (Stack Size: " + itos(_debug_max_call_stack) + ")"; - ScriptDebugger::get_singleton()->debug(this); + EngineDebugger::get_script_debugger()->debug(this); return; } @@ -412,17 +420,17 @@ 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 (ScriptDebugger::get_singleton()->get_lines_left() > 0 && ScriptDebugger::get_singleton()->get_depth() >= 0) - ScriptDebugger::get_singleton()->set_depth(ScriptDebugger::get_singleton()->get_depth() - 1); + 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)"; - ScriptDebugger::get_singleton()->debug(this); + EngineDebugger::get_script_debugger()->debug(this); return; } @@ -430,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); @@ -446,7 +455,6 @@ public: } struct { - StringName _init; StringName _notification; StringName _set; @@ -480,7 +488,7 @@ public: virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; virtual bool is_using_templates(); virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); - virtual bool 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 = NULL, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const; + virtual bool 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 = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; @@ -516,7 +524,7 @@ public: virtual void frame(); virtual void get_public_functions(List<MethodInfo> *p_functions) const; - virtual void get_public_constants(List<Pair<String, Variant> > *p_constants) const; + virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const; virtual void profiling_start(); virtual void profiling_stop(); @@ -531,7 +539,7 @@ public: /* GLOBAL CLASSES */ virtual bool handles_global_class_type(const String &p_type) const; - virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL, String *r_icon_path = NULL) const; + virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const; void add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass); Ref<GDScript> get_orphan_subclass(const String &p_qualified_name); @@ -542,7 +550,7 @@ public: class ResourceFormatLoaderGDScript : public ResourceFormatLoader { public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL, 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 4bd425f999..5bc9003c29 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 = NULL; + 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 = NULL; + 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,24 @@ 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(); + codegen.opcodes.push_back(GDScriptFunction::OPCODE_LINE); + codegen.opcodes.push_back(cf->body_else->line); + codegen.current_line = cf->body_else->line; + 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 +1439,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 +1450,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 +1480,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 +1492,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 +1500,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 +1517,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 +1526,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 +1536,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 +1561,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 +1585,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 +1602,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 +1613,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; @@ -1579,7 +1622,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser codegen.stack_max = 0; codegen.current_line = 0; codegen.call_max = 0; - codegen.debug_stack = ScriptDebugger::get_singleton() != NULL; + codegen.debug_stack = EngineDebugger::is_active(); Vector<StringName> argnames; int stack_level = 0; @@ -1610,7 +1653,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 +1660,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 +1670,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 +1682,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 +1694,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); @@ -1700,29 +1743,26 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser gdfunc->_constant_count = codegen.constant_map.size(); gdfunc->constants.resize(codegen.constant_map.size()); gdfunc->_constants_ptr = gdfunc->constants.ptrw(); - const Variant *K = NULL; + const Variant *K = nullptr; while ((K = codegen.constant_map.next(K))) { int idx = codegen.constant_map[*K]; gdfunc->constants.write[idx] = *K; } } else { - - gdfunc->_constants_ptr = NULL; + 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(); } else { - gdfunc->_global_names_ptr = NULL; + gdfunc->_global_names_ptr = nullptr; gdfunc->_global_names_count = 0; } @@ -1739,25 +1779,22 @@ 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 = NULL; + 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]; } else { gdfunc->_default_arg_count = 0; - gdfunc->_default_arg_ptr = NULL; + gdfunc->_default_arg_ptr = nullptr; } gdfunc->_argument_count = p_func ? p_func->arguments.size() : 0; @@ -1765,11 +1802,12 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser gdfunc->_call_size = codegen.call_max; gdfunc->name = func_name; #ifdef DEBUG_ENABLED - if (ScriptDebugger::get_singleton()) { + 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 +1847,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) { @@ -1838,7 +1877,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar p_script->native = Ref<GDScriptNativeClass>(); p_script->base = Ref<GDScript>(); - p_script->_base = NULL; + p_script->_base = nullptr; p_script->members.clear(); p_script->constants.clear(); for (Map<StringName, GDScriptFunction *>::Element *E = p_script->member_functions.front(); E; E = E->next()) { @@ -1848,7 +1887,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar p_script->member_indices.clear(); p_script->member_info.clear(); p_script->_signals.clear(); - p_script->initializer = NULL; + p_script->initializer = nullptr; p_script->tool = p_class->tool; p_script->name = p_class->name; @@ -1890,7 +1929,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 +1943,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 +1969,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 +1983,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; @@ -1962,7 +1996,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar if (c->base.is_valid()) { c = c->base.ptr(); } else { - c = NULL; + c = nullptr; } } @@ -1989,8 +2023,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 +2046,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, NULL); - if (err) + Error err = _parse_function(p_script, p_class, nullptr); + if (err) { return err; + } } if (!has_ready && p_class->ready->statements.size()) { //create a constructor - Error err = _parse_function(p_script, p_class, NULL, true); - if (err) + Error err = _parse_function(p_script, p_class, nullptr, true); + if (err) { return err; + } } #ifdef DEBUG_ENABLED @@ -2050,7 +2089,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(); @@ -2077,7 +2115,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa /* STEP 2, INITIALIZE AND CONSTRUCT */ Callable::CallError ce; - p_script->initializer->call(instance, NULL, 0, ce); + p_script->initializer->call(instance, nullptr, 0, ce); if (ce.error != Callable::CallError::CALL_OK) { //well, tough luck, not goinna do anything here @@ -2085,7 +2123,6 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa } #endif } else { - GDScriptInstance *gi = static_cast<GDScriptInstance *>(si); gi->reload_members(); } @@ -2110,8 +2147,7 @@ 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; + Map<StringName, Ref<GDScript>> old_subclasses; if (p_keep_state) { old_subclasses = p_script->subclasses; @@ -2145,7 +2181,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 = ""; @@ -2162,30 +2197,31 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri // Create scripts for subclasses beforehand so they can be referenced _make_scripts(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state); - p_script->_owner = NULL; + 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 7d5234a023..315d4f1842 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -36,23 +36,21 @@ #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; bool debug_stack; - List<Map<StringName, int> > stack_id_stack; + List<Map<StringName, int>> stack_id_stack; Map<StringName, int> stack_identifiers; List<GDScriptFunction::StackDebug> stack_debug; - List<Map<StringName, int> > block_identifier_stack; + List<Map<StringName, int>> block_identifier_stack; Map<StringName, int> block_identifiers; void add_stack_identifier(const StringName &p_id, int p_stackpos) { @@ -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 1bc1aae0d2..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); } @@ -221,12 +203,11 @@ Script *GDScriptLanguage::create_script() const { bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) { //break because of parse error - if (ScriptDebugger::get_singleton() && Thread::get_caller_id() == Thread::get_main_id()) { - + 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; - ScriptDebugger::get_singleton()->debug(this, false, true); + EngineDebugger::get_script_debugger()->debug(this, false, true); return true; } else { return false; @@ -234,14 +215,12 @@ 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 (ScriptDebugger::get_singleton() && Thread::get_caller_id() == Thread::get_main_id()) { - + 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; bool is_error_breakpoint = p_error != "Breakpoint"; - ScriptDebugger::get_singleton()->debug(this, p_allow_continue, is_error_breakpoint); + EngineDebugger::get_script_debugger()->debug(this, p_allow_continue, is_error_breakpoint); return true; } else { return false; @@ -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,55 +250,59 @@ 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; GDScriptFunction *f = _call_stack[l].function; - List<Pair<StringName, int> > locals; + List<Pair<StringName, int>> locals; f->debug_get_stack_member_state(*_call_stack[l].line, &locals); - for (List<Pair<StringName, int> >::Element *E = locals.front(); E; E = E->next()) { - + 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,18 +310,17 @@ 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) { + return nullptr; + } - if (_debug_parse_err_line >= 0) - return NULL; - - ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, NULL); + ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, nullptr); int l = _debug_call_stack_pos - p_level - 1; ScriptInstance *instance = _call_stack[l].instance; @@ -347,32 +329,33 @@ 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(); - List<Pair<String, Variant> > cinfo; + List<Pair<String, Variant>> cinfo; 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()) { + for (List<Pair<String, Variant>>::Element *CE = cinfo.front(); CE; CE = CE->next()) { if (CE->get().first == E->key()) { is_script_constant = true; 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))); } @@ -430,12 +410,13 @@ void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const mi.name = "assert"; mi.return_val.type = Variant::NIL; mi.arguments.push_back(PropertyInfo(Variant::BOOL, "condition")); + mi.arguments.push_back(PropertyInfo(Variant::STRING, "message")); + mi.default_arguments.push_back(String()); p_functions->push_back(mi); } } -void GDScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const { - +void GDScriptLanguage::get_public_constants(List<Pair<String, Variant>> *p_constants) const { Pair<String, Variant> pi; pi.first = "PI"; pi.second = Math_PI; @@ -458,7 +439,6 @@ void GDScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_cons } 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 @@ -468,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); @@ -489,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(NULL), - function(NULL), - block(NULL), - base(NULL), - 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(NULL) {} + 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++) { @@ -533,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) { @@ -833,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); @@ -847,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; @@ -909,7 +878,7 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G Variant ret = mb->call(baseptr, (const Variant **)argptr.ptr(), argptr.size(), ce); if (ce.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) { - if (ret.get_type() != Variant::OBJECT || ret.operator Object *() != NULL) { + if (ret.get_type() != Variant::OBJECT || ret.operator Object *() != nullptr) { r_type = _type_from_variant(ret); found = true; } @@ -963,7 +932,7 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G break; } - const GDScriptParser::DictionaryNode *dn = NULL; + const GDScriptParser::DictionaryNode *dn = nullptr; if (op->arguments[0]->type == GDScriptParser::Node::TYPE_DICTIONARY) { dn = static_cast<const GDScriptParser::DictionaryNode *>(op->arguments[0]); } else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::TYPE_DICTIONARY) { @@ -1017,7 +986,7 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G } // Look if it is a dictionary node - const GDScriptParser::DictionaryNode *dn = NULL; + const GDScriptParser::DictionaryNode *dn = nullptr; if (op->arguments[0]->type == GDScriptParser::Node::TYPE_DICTIONARY) { dn = static_cast<const GDScriptParser::DictionaryNode *>(op->arguments[0]); } else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::TYPE_DICTIONARY) { @@ -1041,7 +1010,7 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G // Look if it is an array node if (!found && index.value.is_num()) { int idx = index.value; - const GDScriptParser::ArrayNode *an = NULL; + const GDScriptParser::ArrayNode *an = nullptr; if (op->arguments[0]->type == GDScriptParser::Node::TYPE_ARRAY) { an = static_cast<const GDScriptParser::ArrayNode *>(op->arguments[0]); } else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::TYPE_ARRAY) { @@ -1061,7 +1030,7 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G found = _guess_identifier_type_from_base(c, base, id, r_type); } else if (!found && index.type.kind == GDScriptParser::DataType::BUILTIN) { Callable::CallError err; - Variant base_val = Variant::construct(base.type.builtin_type, NULL, 0, err); + Variant base_val = Variant::construct(base.type.builtin_type, nullptr, 0, err); bool valid = false; Variant res = base_val.get(index.value, &valid); if (valid) { @@ -1080,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: { } } @@ -1116,9 +1105,9 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G Callable::CallError ce; bool v1_use_value = p1.value.get_type() != Variant::NIL && p1.value.get_type() != Variant::OBJECT; - Variant v1 = (v1_use_value) ? p1.value : Variant::construct(p1.type.builtin_type, NULL, 0, ce); + Variant v1 = (v1_use_value) ? p1.value : Variant::construct(p1.type.builtin_type, nullptr, 0, ce); bool v2_use_value = p2.value.get_type() != Variant::NIL && p2.value.get_type() != Variant::OBJECT; - Variant v2 = (v2_use_value) ? p2.value : Variant::construct(p2.type.builtin_type, NULL, 0, ce); + Variant v2 = (v2_use_value) ? p2.value : Variant::construct(p2.type.builtin_type, nullptr, 0, ce); // avoid potential invalid ops if ((vop == Variant::OP_DIVIDE || vop == Variant::OP_MODULE) && v2.get_type() == Variant::INT) { v2 = 1; @@ -1169,11 +1158,10 @@ 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; - const GDScriptParser::Node *last_assigned_expression = NULL; + const GDScriptParser::Node *last_assigned_expression = nullptr; GDScriptParser::DataType var_type; while (blk) { if (blk->variables.has(p_identifier)) { @@ -1227,7 +1215,7 @@ static bool _guess_identifier_type(GDScriptCompletionContext &p_context, const S r_type.type.is_meta_type = false; // Right-hand of `is` will be a meta type, but the left-hand value is not // Not an assignment, it shouldn't carry any value r_type.value = Variant(); - r_type.assigned_expression = NULL; + r_type.assigned_expression = nullptr; return true; } @@ -1271,8 +1259,8 @@ static bool _guess_identifier_type(GDScriptCompletionContext &p_context, const S return false; } GDScriptCompletionContext c = p_context; - c.function = NULL; - c.block = NULL; + c.function = nullptr; + c.block = nullptr; return _guess_expression_type(c, op->arguments[1], r_type); } } @@ -1425,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; } @@ -1534,7 +1523,7 @@ static bool _guess_identifier_type_from_base(GDScriptCompletionContext &p_contex } break; case GDScriptParser::DataType::BUILTIN: { Callable::CallError err; - Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err); + Variant tmp = Variant::construct(base_type.builtin_type, nullptr, 0, err); if (err.error != Callable::CallError::CALL_OK) { return false; @@ -1612,7 +1601,7 @@ static bool _guess_method_return_type_from_base(GDScriptCompletionContext &p_con for (int i = 0; i < base_type.class_type->static_functions.size(); i++) { if (base_type.class_type->static_functions[i]->name == p_method) { int last_return_line = -1; - const GDScriptParser::Node *last_returned_value = NULL; + const GDScriptParser::Node *last_returned_value = nullptr; GDScriptCompletionContext c = p_context; c._class = base_type.class_type; c.function = base_type.class_type->static_functions[i]; @@ -1629,7 +1618,7 @@ static bool _guess_method_return_type_from_base(GDScriptCompletionContext &p_con for (int i = 0; i < base_type.class_type->functions.size(); i++) { if (base_type.class_type->functions[i]->name == p_method) { int last_return_line = -1; - const GDScriptParser::Node *last_returned_value = NULL; + const GDScriptParser::Node *last_returned_value = nullptr; GDScriptCompletionContext c = p_context; c._class = base_type.class_type; c.function = base_type.class_type->functions[i]; @@ -1704,7 +1693,7 @@ static bool _guess_method_return_type_from_base(GDScriptCompletionContext &p_con } break; case GDScriptParser::DataType::BUILTIN: { Callable::CallError err; - Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err); + Variant tmp = Variant::construct(base_type.builtin_type, nullptr, 0, err); if (err.error != Callable::CallError::CALL_OK) { return false; } @@ -1730,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(); @@ -1775,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(); @@ -1817,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; @@ -1911,8 +1897,8 @@ static void _find_identifiers_in_class(const GDScriptCompletionContext &p_contex base_type.value = p_context.base; GDScriptCompletionContext c = p_context; - c.block = NULL; - c.function = NULL; + c.block = nullptr; + c.function = nullptr; _find_identifiers_in_base(c, base_type, p_only_functions, r_result); } @@ -1932,8 +1918,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context case GDScriptParser::DataType::CLASS: { GDScriptCompletionContext c = p_context; c._class = base_type.class_type; - c.block = NULL; - c.function = NULL; + c.block = nullptr; + c.function = nullptr; _find_identifiers_in_class(c, _static, p_only_functions, false, r_result); base_type = base_type.class_type->base_type; } break; @@ -1972,7 +1958,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context } } if (!p_only_functions) { - for (const Map<StringName, Ref<GDScript> >::Element *E = script->get_subclasses().front(); E; E = E->next()) { + for (const Map<StringName, Ref<GDScript>>::Element *E = script->get_subclasses().front(); E; E = E->next()) { ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS); r_result.insert(option.display, option); } @@ -2055,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) { @@ -2089,14 +2075,18 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context } break; case GDScriptParser::DataType::BUILTIN: { Callable::CallError err; - Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err); + Variant tmp = Variant::construct(base_type.builtin_type, nullptr, 0, err); if (err.error != Callable::CallError::CALL_OK) { return; } 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) { @@ -2128,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++) { @@ -2148,13 +2136,13 @@ 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; c._class = clss; - c.block = NULL; - c.function = NULL; + c.block = nullptr; + c.function = nullptr; _find_identifiers_in_class(c, _static, p_only_functions, false, r_result); _static = true; clss = clss->owner; @@ -2188,7 +2176,7 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p "const", "enum", "export", "onready", "static", "var", "break", "continue", "if", "elif", "else", "for", "pass", "return", "match", "while", "remote", "master", "puppet", "remotesync", "mastersync", "puppetsync", - 0 + nullptr }; const char **kw = _keywords; @@ -2234,6 +2222,8 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; +#define IS_METHOD_SIGNAL(m_method) (m_method == "connect" || m_method == "disconnect" || m_method == "is_connected" || m_method == "emit_signal") + while (base_type.has_type) { switch (base_type.kind) { case GDScriptParser::DataType::CLASS: { @@ -2250,7 +2240,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con } } - if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) { + if (IS_METHOD_SIGNAL(p_method) && p_argidx == 0) { for (int i = 0; i < base_type.class_type->_signals.size(); i++) { ScriptCodeCompletionOption option(base_type.class_type->_signals[i].name.operator String(), ScriptCodeCompletionOption::KIND_SIGNAL); option.insert_text = quote_style + option.display + quote_style; @@ -2263,7 +2253,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con case GDScriptParser::DataType::GDSCRIPT: { Ref<GDScript> gds = base_type.script_type; if (gds.is_valid()) { - if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) { + if (IS_METHOD_SIGNAL(p_method) && p_argidx == 0) { List<MethodInfo> signals; gds->get_script_signal_list(&signals); for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { @@ -2325,7 +2315,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con } } - if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) { + if (IS_METHOD_SIGNAL(p_method) && p_argidx == 0) { List<MethodInfo> signals; ClassDB::get_signal_list(class_name, &signals); for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { @@ -2334,6 +2324,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con r_result.insert(option.display, option); } } +#undef IS_METHOD_SIGNAL if (ClassDB::is_parent_class(class_name, "Node") && (p_method == "get_node" || p_method == "has_node") && p_argidx == 0) { // Get autoloads @@ -2373,7 +2364,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con case GDScriptParser::DataType::BUILTIN: { if (base.get_type() == Variant::NIL) { Callable::CallError err; - base = Variant::construct(base_type.builtin_type, NULL, 0, err); + base = Variant::construct(base_type.builtin_type, nullptr, 0, err); if (err.error != Callable::CallError::CALL_OK) { return; } @@ -2398,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) { @@ -2454,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; } @@ -2528,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; @@ -2542,7 +2530,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path context.function = parser.get_completion_function(); context.line = parser.get_completion_line(); - if (!context._class || context._class->owner == NULL) { + if (!context._class || context._class->owner == nullptr) { context.base = p_owner; context.base_path = p_path.get_base_dir(); } @@ -2576,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; @@ -2626,13 +2613,13 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path } GDScriptCompletionContext c = context; - c.function = NULL; - c.block = NULL; - c.base = base.value.get_type() == Variant::OBJECT ? base.value.operator Object *() : NULL; + c.function = nullptr; + c.block = nullptr; + c.base = base.value.get_type() == Variant::OBJECT ? base.value.operator Object *() : nullptr; if (base.type.kind == GDScriptParser::DataType::CLASS) { c._class = base.type.class_type; } else { - c._class = NULL; + c._class = nullptr; } _find_identifiers_in_base(c, base, is_function, options); @@ -2684,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) { @@ -2818,8 +2804,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = clss->constant_expressions.front(); E; E = E->next()) { GDScriptCompletionIdentifier constant; GDScriptCompletionContext c = context; - c.function = NULL; - c.block = NULL; + c.function = nullptr; + c.block = nullptr; c.line = E->value().expression->line; if (_guess_expression_type(c, E->value().expression, constant)) { if (constant.type.has_type && constant.type.is_meta_type) { @@ -2887,9 +2873,9 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path } GDScriptCompletionContext c = context; - c._class = NULL; - c.function = NULL; - c.block = NULL; + c._class = nullptr; + c.function = nullptr; + c.block = nullptr; bool finding = true; index = index.right(index.find(".") + 1); while (index.find(".") != -1) { @@ -2917,8 +2903,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path GDScriptCompletionIdentifier constant; GDScriptCompletionContext c2 = context; c2._class = base_type.class_type; - c2.function = NULL; - c2.block = NULL; + c2.function = nullptr; + c2.block = nullptr; c2.line = E->value().expression->line; if (_guess_expression_type(c2, E->value().expression, constant)) { if (constant.type.has_type && constant.type.is_meta_type) { @@ -3008,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; @@ -3028,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()) { @@ -3043,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; @@ -3064,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]; } } @@ -3108,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; } @@ -3220,7 +3213,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co v = v_ref; } else { Callable::CallError err; - v = Variant::construct(base_type.builtin_type, NULL, 0, err); + v = Variant::construct(base_type.builtin_type, nullptr, 0, err); if (err.error != Callable::CallError::CALL_OK) { break; } @@ -3252,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; @@ -3333,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(); } @@ -3385,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()); @@ -3403,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); @@ -3440,7 +3429,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol // We cannot determine the exact nature of the identifier here // Otherwise these codes would work StringName enumName = ClassDB::get_integer_constant_enum("@GlobalScope", p_symbol, true); - if (enumName != NULL) { + if (enumName != nullptr) { r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_ENUM; r_result.class_name = "@GlobalScope"; r_result.class_member = enumName; @@ -3485,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 79c550c81c..1aab71d161 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -35,48 +35,43 @@ #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)) { r_error = "Cannot access self without instance."; - return NULL; + return nullptr; } #endif return &self; } break; case ADDR_TYPE_CLASS: { - return &static_ref; } break; case ADDR_TYPE_MEMBER: { #ifdef DEBUG_ENABLED if (unlikely(!p_instance)) { r_error = "Cannot access member without instance."; - return NULL; + return nullptr; } #endif //member indexing is O(1) return &p_instance->members.write[address]; } break; case ADDR_TYPE_CLASS_CONSTANT: { - //todo change to index! GDScript *s = p_script; #ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(address, _global_names_count, NULL); + ERR_FAIL_INDEX_V(address, _global_names_count, nullptr); #endif const StringName *sn = &_global_names_ptr[address]; while (s) { GDScript *o = s; while (o) { - Map<StringName, Variant>::Element *E = o->constants.find(*sn); if (E) { return &E->get(); @@ -86,31 +81,31 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta s = s->_base; } - ERR_FAIL_V_MSG(NULL, "GDScriptCompiler bug."); + ERR_FAIL_V_MSG(nullptr, "GDScriptCompiler bug."); } break; case ADDR_TYPE_LOCAL_CONSTANT: { #ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(address, _constant_count, NULL); + ERR_FAIL_INDEX_V(address, _constant_count, nullptr); #endif return &_constants_ptr[address]; } break; case ADDR_TYPE_STACK: case ADDR_TYPE_STACK_VARIABLE: { #ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(address, _stack_size, NULL); + ERR_FAIL_INDEX_V(address, _stack_size, nullptr); #endif return &p_stack[address]; } break; case ADDR_TYPE_GLOBAL: { #ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(address, GDScriptLanguage::get_singleton()->get_global_array_size(), NULL); + ERR_FAIL_INDEX_V(address, GDScriptLanguage::get_singleton()->get_global_array_size(), nullptr); #endif return &GDScriptLanguage::get_singleton()->get_global_array()[address]; } break; #ifdef TOOLS_ENABLED case ADDR_TYPE_NAMED_GLOBAL: { #ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(address, _named_globals_count, NULL); + ERR_FAIL_INDEX_V(address, _named_globals_count, nullptr); #endif StringName id = _named_globals_ptr[address]; @@ -118,7 +113,7 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta return (Variant *)&GDScriptLanguage::get_singleton()->get_named_globals_map()[id]; } else { r_error = "Autoload singleton '" + String(id) + "' has been removed."; - return NULL; + return nullptr; } } break; #endif @@ -127,13 +122,12 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta } break; } - ERR_FAIL_V_MSG(NULL, "Bad code! (unknown addressing mode)."); - return NULL; + ERR_FAIL_V_MSG(nullptr, "Bad code! (unknown addressing mode)."); + return nullptr; } #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(); } @@ -272,7 +264,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a Variant self; Variant static_ref; Variant retvalue; - Variant *stack = NULL; + Variant *stack = nullptr; Variant **call_args; int defarg = 0; @@ -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); @@ -358,25 +337,22 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a memnew_placement(&stack[i], Variant); } } else { - stack = NULL; + stack = nullptr; } if (_call_size) { - call_args = (Variant **)&aptr[sizeof(Variant) * _stack_size]; } else { - - call_args = NULL; + call_args = nullptr; } } else { - stack = NULL; - call_args = NULL; + stack = nullptr; + call_args = nullptr; } 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 (ScriptDebugger::get_singleton()) + 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); @@ -490,16 +465,14 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GET_VARIANT_PTR(dst, 3); #ifdef DEBUG_ENABLED - if (b->get_type() != Variant::OBJECT || b->operator Object *() == NULL) { - + if (b->get_type() != Variant::OBJECT || b->operator Object *() == nullptr) { err_text = "Right operand of 'is' is not a class."; OPCODE_BREAK; } #endif bool extends_ok = false; - if (a->get_type() == Variant::OBJECT && a->operator Object *() != NULL) { - + 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); @@ -855,8 +811,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_BREAK; } - if (src->get_type() != Variant::NIL && src->operator Object *() != NULL) { - + 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); @@ -960,12 +912,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a bool valid = false; - if (src->get_type() != Variant::NIL && src->operator Object *() != NULL) { - + 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,12 +1038,10 @@ 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, NULL, err); + base->call_ptr(*methodname, (const Variant **)argptrs, argc, nullptr, err); } #ifdef DEBUG_ENABLED if (GDScriptLanguage::get_singleton()->profiling) { @@ -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; } @@ -1137,13 +1075,12 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } #endif - //_call_func(NULL,base,*methodname,ip,argc,p_instance,stack); + //_call_func(nullptr,base,*methodname,ip,argc,p_instance,stack); ip += argc + 1; } 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; } @@ -1216,23 +1149,21 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a const GDScript *gds = _script; - const Map<StringName, GDScriptFunction *>::Element *E = NULL; + const Map<StringName, GDScriptFunction *>::Element *E = nullptr; 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 { @@ -1522,7 +1455,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE(OPCODE_BREAKPOINT) { #ifdef DEBUG_ENABLED - if (ScriptDebugger::get_singleton()) { + if (EngineDebugger::is_active()) { GDScriptLanguage::get_singleton()->debug_break("Breakpoint Statement", true); } #endif @@ -1536,26 +1469,28 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a line = _code_ptr[ip + 1]; ip += 2; - if (ScriptDebugger::get_singleton()) { + if (EngineDebugger::is_active()) { // line bool do_break = false; - if (ScriptDebugger::get_singleton()->get_lines_left() > 0) { - - if (ScriptDebugger::get_singleton()->get_depth() <= 0) - ScriptDebugger::get_singleton()->set_lines_left(ScriptDebugger::get_singleton()->get_lines_left() - 1); - if (ScriptDebugger::get_singleton()->get_lines_left() <= 0) + if (EngineDebugger::get_script_debugger()->get_lines_left() > 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) { do_break = true; + } } - if (ScriptDebugger::get_singleton()->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); } - ScriptDebugger::get_singleton()->line_poll(); + EngineDebugger::get_singleton()->line_poll(); } } DISPATCH_OPCODE; @@ -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 (ScriptDebugger::get_singleton()) + 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 { - +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,13 +1689,12 @@ 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; name = "<anonymous>"; #ifdef DEBUG_ENABLED - _func_cname = NULL; + _func_cname = nullptr; { MutexLock lock(GDScriptLanguage::get_singleton()->lock); @@ -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,33 +1759,53 @@ Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_ar } bool GDScriptFunctionState::is_valid(bool p_extended_check) const { - - if (function == NULL) + 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; Callable::CallError err; - Variant ret = function->call(NULL, NULL, 0, err, &state); + Variant ret = function->call(nullptr, nullptr, 0, err, &state); bool completed = true; @@ -1873,7 +1819,7 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { } } - function = NULL; //cleaned up; + function = nullptr; //cleaned up; state.result = Variant(); if (completed) { @@ -1884,13 +1830,8 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { } #ifdef DEBUG_ENABLED - if (ScriptDebugger::get_singleton()) + 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() { - - function = NULL; +GDScriptFunctionState::GDScriptFunctionState() : + scripts_list(this), + instances_list(this) { + function = nullptr; } GDScriptFunctionState::~GDScriptFunctionState() { + _clear_stack(); - if (function != NULL) { - //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 34019e563d..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: @@ -105,7 +110,7 @@ struct GDScriptDataType { return false; } - Ref<Script> base = obj && obj->get_script_instance() ? obj->get_script_instance()->get_script() : NULL; + Ref<Script> base = obj && obj->get_script_instance() ? obj->get_script_instance()->get_script() : nullptr; bool valid = false; while (base.is_valid()) { if (base == script_type) { @@ -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; @@ -321,7 +324,7 @@ public: GDScript *get_script() const { return _script; } StringName get_source() const { return source; } - void debug_get_stack_member_state(int p_line, List<Pair<StringName, int> > *r_stackvars) const; + void debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const; _FORCE_INLINE_ bool is_empty() const { return _code_size == 0; } @@ -339,7 +342,7 @@ public: return default_arguments[p_idx]; } - Variant call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state = NULL); + Variant call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state = nullptr); _FORCE_INLINE_ MultiplayerAPI::RPCMode get_rpc_mode() const { return rpc_mode; } GDScriptFunction(); @@ -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 aaa308f40f..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(); } @@ -858,7 +829,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ PackedByteArray barr; int len; - Error err = encode_variant(*p_args[0], NULL, len, full_objects); + Error err = encode_variant(*p_args[0], nullptr, len, full_objects); if (err) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; @@ -908,7 +879,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ Variant ret; { const uint8_t *r = varr.ptr(); - Error err = decode_variant(ret, r, varr.size(), NULL, allow_objects); + Error err = decode_variant(ret, r, varr.size(), nullptr, allow_objects); if (err != OK) { r_ret = RTR("Not enough bytes for decoding bytes, or invalid format."); r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; @@ -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(NULL, 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 0382944efd..ca452bf008 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,18 +233,16 @@ 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; Vector<Expression> expression; - Node *expr = NULL; + Node *expr = nullptr; 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,13 +270,13 @@ 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) - return NULL; + if (!subexpr) { + return nullptr; + } if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')' in expression"); - return NULL; + return nullptr; } tokenizer->advance(); @@ -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; @@ -318,7 +311,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (tokenizer->get_token_constant().get_type() != Variant::STRING) { _set_error("Expected string constant or identifier after '$' or '/'."); - return NULL; + return nullptr; } path += String(tokenizer->get_token_constant()); @@ -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; @@ -355,7 +347,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (path == "") { _set_error("Path expected after $."); - return NULL; + return nullptr; } OperatorNode *op = alloc_node<OperatorNode>(); @@ -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,12 +409,11 @@ 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) { _set_error("Expected '(' after 'preload'"); - return NULL; + return nullptr; } tokenizer->advance(); @@ -476,23 +462,22 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (!valid) { _set_error("expected string constant as 'preload' argument."); - return NULL; + 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 NULL; + return nullptr; } Ref<Resource> res; 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,29 +485,28 @@ 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 NULL; + return nullptr; } else if (ScriptCodeCompletionCache::get_singleton()) { res = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(path); } } if (!res.is_valid()) { _set_error("Can't preload resource at path: " + path); - return NULL; + return nullptr; } } if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected ')' after 'preload' path"); - return NULL; + return nullptr; } Ref<GDScript> gds = res; if (gds.is_valid() && !gds->is_valid()) { _set_error("Couldn't fully preload the script, possible cyclic reference or compilation error. Use \"load()\" instead if a cyclic reference is intended."); - return NULL; + return nullptr; } tokenizer->advance(); @@ -533,10 +517,9 @@ 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 NULL; + return nullptr; } current_function->has_yield = true; @@ -544,7 +527,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(); if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) { _set_error("Expected \"(\" after \"yield\"."); - return NULL; + return nullptr; } tokenizer->advance(); @@ -560,23 +543,22 @@ 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) - return NULL; + if (!object) { + return nullptr; + } yield->arguments.push_back(object); if (tokenizer->get_token() != GDScriptTokenizer::TK_COMMA) { _set_error("Expected \",\" after the first argument of \"yield\"."); - return NULL; + return nullptr; } tokenizer->advance(); if (tokenizer->get_token() == GDScriptTokenizer::TK_CURSOR) { - completion_cursor = StringName(); completion_node = object; completion_type = COMPLETION_YIELD; @@ -590,13 +572,14 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } Node *signal = _parse_and_reduce_expression(p_parent, p_static); - if (!signal) - return NULL; + if (!signal) { + return nullptr; + } yield->arguments.push_back(signal); if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected \")\" after the second argument of \"yield\"."); - return NULL; + return nullptr; } parenthesis--; @@ -607,38 +590,32 @@ 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 NULL; + return nullptr; } //constant defined by tokenizer SelfNode *self = alloc_node<SelfNode>(); 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 NULL; + 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)) - return NULL; + if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant)) { + return nullptr; + } expr = op; } else { @@ -674,11 +652,10 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } if (!valid) { _set_error("Static constant '" + identifier.operator String() + "' not present in built-in type " + Variant::get_type_name(bi_type) + "."); - return NULL; + return nullptr; } } } 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)) - return NULL; + if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant)) { + return nullptr; + } expr = op; } } else if (tokenizer->is_token_literal(0, true)) { @@ -789,7 +772,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (lv->assignments == 0) { if (!lv->datatype.has_type) { _set_error("Using assignment with operation on a variable that was never assigned."); - return NULL; + return nullptr; } _add_warning(GDScriptWarning::UNASSIGNED_VARIABLE_OP_ASSIGN, -1, identifier.operator String()); } @@ -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: { } } @@ -912,7 +905,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (e.op != OperatorNode::OP_NOT && tokenizer->get_token() == GDScriptTokenizer::TK_OP_NOT) { _set_error("Misplaced 'not'."); - return NULL; + return nullptr; } expression.push_back(e); @@ -921,7 +914,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s /* Node *subexpr=_parse_expression(op,p_static); if (!subexpr) - return NULL; + return nullptr; op->arguments.push_back(subexpr); expr=op;*/ @@ -929,7 +922,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s // 'is' operator with built-in type if (!expr) { _set_error("Expected identifier before 'is' operator"); - return NULL; + return nullptr; } OperatorNode *op = alloc_node<OperatorNode>(); op->op = OperatorNode::OP_IS_BUILTIN; @@ -951,22 +944,19 @@ 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 NULL; + return nullptr; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_BRACKET_CLOSE) { 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) { _set_error("expression or ']' expected"); - return NULL; + return nullptr; } expecting_comma = false; @@ -975,11 +965,12 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s //parse expression if (expecting_comma) { _set_error("',' or ']' expected"); - return NULL; + return nullptr; } Node *n = _parse_expression(arr, p_static, p_allow_assign, p_parsing_constant); - if (!n) - return NULL; + if (!n) { + return nullptr; + } arr->elements.push_back(n); expecting_comma = true; } @@ -1001,81 +992,73 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s }; - Node *key = NULL; + Node *key = nullptr; Set<Variant> keys; DictExpect expecting = DICT_EXPECT_KEY; while (true) { - if (tokenizer->get_token() == GDScriptTokenizer::TK_EOF) { - _set_error("Unterminated dictionary"); - return NULL; + return nullptr; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CURLY_BRACKET_CLOSE) { - if (expecting == DICT_EXPECT_COLON) { _set_error("':' expected"); - return NULL; + return nullptr; } if (expecting == DICT_EXPECT_VALUE) { _set_error("value expected"); - return NULL; + return nullptr; } 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 NULL; + return nullptr; } if (expecting == DICT_EXPECT_VALUE) { _set_error("value expected"); - return NULL; + return nullptr; } if (expecting == DICT_EXPECT_COLON) { _set_error("':' expected"); - return NULL; + return nullptr; } expecting = DICT_EXPECT_KEY; tokenizer->advance(); //ignore newline } else if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { - if (expecting == DICT_EXPECT_KEY) { _set_error("key or '}' expected"); - return NULL; + return nullptr; } if (expecting == DICT_EXPECT_VALUE) { _set_error("value expected"); - return NULL; + return nullptr; } if (expecting == DICT_EXPECT_COMMA) { _set_error("',' or '}' expected"); - return NULL; + return nullptr; } expecting = DICT_EXPECT_VALUE; tokenizer->advance(); //ignore newline } else { - if (expecting == DICT_EXPECT_COMMA) { _set_error("',' or '}' expected"); - return NULL; + return nullptr; } if (expecting == DICT_EXPECT_COLON) { _set_error("':' expected"); - return NULL; + return nullptr; } 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) - return NULL; + 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) - return NULL; + if (!value) { + return nullptr; + } expecting = DICT_EXPECT_COMMA; if (key->type == GDScriptParser::Node::TYPE_CONSTANT) { @@ -1105,7 +1090,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (keys.has(keyName)) { _set_error("Duplicate key found in Dictionary literal"); - return NULL; + return nullptr; } keys.insert(keyName); } @@ -1114,7 +1099,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s pair.key = key; pair.value = value; dict->elements.push_back(pair); - key = NULL; + key = nullptr; } } } @@ -1142,12 +1127,12 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) { if (!is_completion) { _set_error("Expected '(' for parent function call."); - return NULL; + return nullptr; } } else { tokenizer->advance(); if (!_parse_arguments(op, op->arguments, p_static, false, p_parsing_constant)) { - return NULL; + return nullptr; } } @@ -1163,30 +1148,27 @@ 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 NULL; //nothing + return nullptr; //nothing } - ERR_FAIL_COND_V_MSG(!expr, NULL, "GDScriptParser bug, couldn't figure out what expression is."); + ERR_FAIL_COND_V_MSG(!expr, nullptr, "GDScriptParser bug, couldn't figure out what expression is."); /******************/ /* Parse Indexing */ /******************/ 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)) { // We check with is_token_literal, as this allows us to use match/sync/etc. as a name _set_error("Expected identifier as member"); - return NULL; + return nullptr; } else if (tokenizer->get_token(2) == GDScriptTokenizer::TK_PARENTHESIS_OPEN) { //call!! OperatorNode *op = alloc_node<OperatorNode>(); @@ -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)) - return NULL; + 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 } @@ -1251,12 +1233,12 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s Node *subexpr = _parse_expression(op, p_static, p_allow_assign, p_parsing_constant); if (!subexpr) { - return NULL; + return nullptr; } if (tokenizer->get_token() != GDScriptTokenizer::TK_BRACKET_CLOSE) { _set_error("Expected ']'"); - return NULL; + return nullptr; } op->arguments.push_back(expr); @@ -1264,8 +1246,9 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(1); expr = op; - } else + } else { break; + } } /*****************/ @@ -1276,12 +1259,12 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_AS) { if (has_casting) { _set_error("Unexpected 'as'."); - return NULL; + return nullptr; } CastNode *cn = alloc_node<CastNode>(); if (!_parse_type(cn->cast_type)) { _set_error("Expected type after 'as'."); - return NULL; + return nullptr; } has_casting = true; cn->source_node = expr; @@ -1313,31 +1296,61 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s #define _VALIDATE_ASSIGN \ if (!p_allow_assign || has_casting) { \ _set_error("Unexpected assign."); \ - return NULL; \ + return nullptr; \ } \ p_allow_assign = false; 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,21 +1546,43 @@ 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)); - return NULL; + return nullptr; } } @@ -1488,7 +1591,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s // <= is used for right to left if (error) { _set_error("Unexpected operator"); - return NULL; + return nullptr; } next_op = i; min_priority = priority; @@ -1498,28 +1601,24 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } if (next_op == -1) { - _set_error("Yet another parser bug...."); - ERR_FAIL_V(NULL); + 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.. _set_error("Unexpected end of expression..."); - return NULL; + return nullptr; } } - //consecutively do unary opeators + //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); @@ -1532,16 +1631,16 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } else if (is_ternary) { if (next_op < 1 || next_op >= (expression.size() - 1)) { _set_error("Parser bug..."); - ERR_FAIL_V(NULL); + ERR_FAIL_V(nullptr); } if (next_op >= (expression.size() - 2) || expression[next_op + 2].op != OperatorNode::OP_TERNARY_ELSE) { _set_error("Expected else after ternary if."); - return NULL; + return nullptr; } if (next_op >= (expression.size() - 3)) { _set_error("Expected value after ternary else."); - return NULL; + return nullptr; } OperatorNode *op = alloc_node<OperatorNode>(); @@ -1549,9 +1648,8 @@ 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(NULL); + ERR_FAIL_V(nullptr); } if (expression[next_op + 1].is_op) { @@ -1561,7 +1659,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s // due to how precedence works, unaries will always disappear first _set_error("Unexpected two consecutive operators after ternary if."); - return NULL; + return nullptr; } if (expression[next_op + 3].is_op) { @@ -1571,7 +1669,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s // due to how precedence works, unaries will always disappear first _set_error("Unexpected two consecutive operators after ternary else."); - return NULL; + return nullptr; } op->arguments.push_back(expression[next_op + 1].node); //next expression goes as first @@ -1585,10 +1683,9 @@ 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(NULL); + ERR_FAIL_V(nullptr); } OperatorNode *op = alloc_node<OperatorNode>(); @@ -1596,9 +1693,8 @@ 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(NULL); + ERR_FAIL_V(nullptr); } if (expression[next_op + 1].is_op) { @@ -1608,7 +1704,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s // due to how precedence works, unaries will always disappear first _set_error("Unexpected two consecutive operators."); - return NULL; + return nullptr; } op->arguments.push_back(expression[next_op - 1].node); //expression goes as left @@ -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 = NULL; + 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) - return NULL; + if (!expr || error_set) { + return nullptr; + } expr = _reduce_expression(expr, p_reduce_const); - if (!expr || error_set) - return NULL; + 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,15 +2154,15 @@ 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) - return NULL; + if (error_set) { + return nullptr; + } if (token == GDScriptTokenizer::TK_EOF) { - return NULL; + return nullptr; } switch (token) { @@ -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; @@ -2078,13 +2190,13 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { break; } else { _set_error("'..' pattern only allowed at the end of an array pattern"); - return NULL; + return nullptr; } } PatternNode *sub_pattern = _parse_pattern(p_static); if (!sub_pattern) { - return NULL; + return nullptr; } pattern->array.push_back(sub_pattern); @@ -2097,7 +2209,7 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { break; } else { _set_error("Not a valid pattern"); - return NULL; + return nullptr; } } } break; @@ -2106,7 +2218,7 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { tokenizer->advance(); if (!tokenizer->is_token_literal()) { _set_error("Expected identifier for binding variable name."); - return NULL; + return nullptr; } pattern->pt_type = GDScriptParser::PatternNode::PT_BIND; pattern->bind = tokenizer->get_token_literal(); @@ -2115,7 +2227,7 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { while (bl) { if (bl->variables.has(pattern->bind)) { _set_error("Binding name of '" + pattern->bind.operator String() + "' is already declared in this scope."); - return NULL; + return nullptr; } bl = bl->parent_block; } @@ -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; @@ -2150,19 +2261,19 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { break; } else { _set_error("'..' pattern only allowed at the end of a dictionary pattern"); - return NULL; + return nullptr; } } Node *key = _parse_and_reduce_expression(pattern, p_static); if (!key) { _set_error("Not a valid key in pattern"); - return NULL; + return nullptr; } if (key->type != GDScriptParser::Node::TYPE_CONSTANT) { _set_error("Not a constant expression as key"); - return NULL; + return nullptr; } if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { @@ -2171,12 +2282,12 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { PatternNode *value = _parse_pattern(p_static); if (!value) { _set_error("Expected pattern in dictionary value"); - return NULL; + return nullptr; } pattern->dictionary.insert(static_cast<ConstantNode *>(key), value); } else { - pattern->dictionary.insert(static_cast<ConstantNode *>(key), NULL); + pattern->dictionary.insert(static_cast<ConstantNode *>(key), nullptr); } if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { @@ -2187,7 +2298,7 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { break; } else { _set_error("Not a valid pattern"); - return NULL; + return nullptr; } } } break; @@ -2200,7 +2311,7 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { Node *value = _parse_and_reduce_expression(pattern, p_static); if (!value) { _set_error("Expect constant expression or variables in a pattern"); - return NULL; + return nullptr; } if (value->type == Node::TYPE_OPERATOR) { @@ -2212,19 +2323,19 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { if (op_node->op != OperatorNode::OP_INDEX_NAMED) { _set_error("Invalid operator in pattern. Only index (`A.B`) is allowed"); - return NULL; + return nullptr; } current_value = op_node->arguments[0]; } if (current_value->type != Node::TYPE_IDENTIFIER) { _set_error("Only constant expression or variables allowed in a pattern"); - return NULL; + return nullptr; } } else if (value->type != Node::TYPE_IDENTIFIER && value->type != Node::TYPE_CONSTANT) { _set_error("Only constant expressions or variables allowed in a pattern"); - return NULL; + return nullptr; } pattern->pt_type = PatternNode::PT_CONSTANT; @@ -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,18 +2433,16 @@ 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; } - OperatorNode *type_comp = NULL; + OperatorNode *type_comp = nullptr; // static type check if possible if (pattern_type.has_type && to_match_type.has_type) { @@ -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) { @@ -2402,7 +2512,7 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m // typeof(value_to_match) == TYPE_ARRAY && value_to_match.size() == length { - OperatorNode *type_comp = NULL; + OperatorNode *type_comp = nullptr; // static type check if possible if (to_match_type.has_type) { // must be an array @@ -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; @@ -2461,10 +2572,11 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m for (int i = 0; i < p_pattern->array.size(); i++) { PatternNode *pattern = p_pattern->array[i]; - Node *condition = NULL; + Node *condition = nullptr; 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) { @@ -2495,7 +2606,7 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m // typeof(value_to_match) == TYPE_DICTIONARY && value_to_match.size() == length { - OperatorNode *type_comp = NULL; + OperatorNode *type_comp = nullptr; // static type check if possible if (to_match_type.has_type) { // must be an dictionary @@ -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,8 +2664,7 @@ 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 = NULL; + 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,11 +2735,10 @@ 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; - compiled_branch.compiled_pattern = NULL; + compiled_branch.compiled_pattern = nullptr; Map<StringName, Node *> binding; @@ -2638,7 +2747,7 @@ void GDScriptParser::_transform_match_statment(MatchNode *p_match_statement) { _mark_line_as_safe(pattern->line); Map<StringName, Node *> bindings; - Node *resulting_node = NULL; + Node *resulting_node = nullptr; _generate_pattern(pattern, id, resulting_node, bindings); if (!resulting_node) { @@ -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; } @@ -2838,7 +2948,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { lv->line = var_line; p_block->statements.push_back(lv); - Node *assigned = NULL; + Node *assigned = nullptr; if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { if (tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) { @@ -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,22 +3166,36 @@ 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(); +#ifdef DEBUG_ENABLED + for (int j = 0; j < current_class->variables.size(); j++) { + if (current_class->variables[j].identifier == id->name) { + _add_warning(GDScriptWarning::SHADOWED_VARIABLE, id->line, id->name, itos(current_class->variables[j].line)); + } + } +#endif // DEBUG_ENABLED + + 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(); @@ -3094,7 +3217,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!) @@ -3102,15 +3224,16 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { Vector<Node *> args; Vector<double> constants; - bool constant = false; + bool constant = true; for (int i = 1; i < op->arguments.size(); i++) { args.push_back(op->arguments[i]); - if (constant && op->arguments[i]->type == Node::TYPE_CONSTANT) { + if (op->arguments[i]->type == Node::TYPE_CONSTANT) { 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); - constant = true; + } else { + constant = false; } } else { constant = false; @@ -3118,14 +3241,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; @@ -3137,9 +3264,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++) { @@ -3164,6 +3297,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)) { @@ -3187,12 +3322,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(); @@ -3200,11 +3349,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(); @@ -3212,12 +3375,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; @@ -3241,7 +3403,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; } } @@ -3249,7 +3411,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>(); @@ -3273,12 +3434,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; @@ -3291,7 +3455,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) { @@ -3299,6 +3462,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { return; } + int assert_line = tokenizer->get_token_line(); + tokenizer->advance(); Vector<Node *> args; @@ -3308,41 +3473,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()) { @@ -3356,7 +3521,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; } @@ -3367,9 +3532,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(); @@ -3386,9 +3549,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?"); @@ -3398,7 +3559,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; } @@ -3421,15 +3581,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; } @@ -3446,10 +3603,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; } @@ -3466,16 +3621,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; @@ -3484,7 +3637,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; } @@ -3493,7 +3645,6 @@ void GDScriptParser::_parse_extends(ClassNode *p_class) { tokenizer->advance(1); switch (tokenizer->get_token()) { - case GDScriptTokenizer::TK_IDENTIFIER: case GDScriptTokenizer::TK_PERIOD: continue; @@ -3505,14 +3656,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(); @@ -3520,7 +3670,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } switch (token) { - case GDScriptTokenizer::TK_CURSOR: { tokenizer->advance(); } break; @@ -3540,19 +3689,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."); @@ -3563,7 +3711,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; } @@ -3629,9 +3776,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; } @@ -3646,7 +3791,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; } @@ -3674,6 +3818,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; } @@ -3689,14 +3839,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; } @@ -3714,7 +3863,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; } @@ -3722,12 +3870,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; } @@ -3738,7 +3884,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (name == StringName()) { - _set_error("Expected an identifier after \"func\" (syntax: \"func <identifier>([arguments]):\")."); return; } @@ -3771,7 +3916,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; } @@ -3791,24 +3935,27 @@ 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; } StringName argname = tokenizer->get_token_identifier(); + for (int i = 0; i < arguments.size(); i++) { + if (arguments[i] == argname) { + _set_error("The argument name \"" + String(argname) + "\" is defined multiple times."); + return; + } + } arguments.push_back(argname); #ifdef DEBUG_ENABLED arguments_usage.push_back(0); @@ -3829,7 +3976,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; } @@ -3840,8 +3986,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; @@ -3870,7 +4017,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; } @@ -3898,14 +4044,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); @@ -3926,17 +4070,15 @@ 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 = NULL; + current_function = nullptr; cparent->arguments.push_back(arg); if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { tokenizer->advance(); continue; } else if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { - _set_error("Expected \",\" or \")\"."); return; } @@ -3949,9 +4091,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; } @@ -3960,7 +4100,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; @@ -3968,23 +4107,23 @@ 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; current_block = block; _parse_block(block, _static); - current_block = NULL; + current_block = nullptr; //arguments } break; @@ -4000,6 +4139,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) { @@ -4039,16 +4186,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(); \ @@ -4073,7 +4218,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."); @@ -4092,11 +4236,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) { @@ -4109,7 +4250,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."); @@ -4117,16 +4257,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(); @@ -4140,7 +4282,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."); @@ -4151,7 +4292,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."); @@ -4162,7 +4302,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."); @@ -4173,7 +4312,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."); @@ -4188,25 +4326,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(); @@ -4223,7 +4361,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; @@ -4236,19 +4373,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; @@ -4257,7 +4394,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; @@ -4272,7 +4408,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; @@ -4287,7 +4422,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; @@ -4296,11 +4430,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; @@ -4314,7 +4448,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; @@ -4325,30 +4458,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(); @@ -4362,13 +4494,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")) { @@ -4394,16 +4524,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; @@ -4411,22 +4538,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(); @@ -4441,7 +4568,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) { @@ -4452,9 +4578,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; @@ -4474,7 +4598,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; @@ -4483,7 +4606,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } else { - parenthesis++; Node *subexpr = _parse_and_reduce_expression(p_class, true, true); if (!subexpr) { @@ -4543,10 +4665,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) { @@ -4563,7 +4686,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; @@ -4585,7 +4707,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; @@ -4594,7 +4715,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) { @@ -4605,7 +4725,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) { @@ -4625,7 +4744,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) { @@ -4645,7 +4763,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) { @@ -4665,14 +4782,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; } @@ -4680,14 +4797,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; } @@ -4695,14 +4812,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; } @@ -4724,13 +4841,12 @@ 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; } member.identifier = tokenizer->get_token_literal(); - member.expression = NULL; + member.expression = nullptr; member._export.name = member.identifier; member.line = tokenizer->get_token_line(); member.usages = 0; @@ -4810,11 +4926,10 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { #ifdef TOOLS_ENABLED Callable::CallError ce; - member.default_value = Variant::construct(member._export.type, NULL, 0, ce); + member.default_value = Variant::construct(member._export.type, nullptr, 0, ce); #endif if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) { - #ifdef DEBUG_ENABLED int line = tokenizer->get_token_line(); #endif @@ -4830,12 +4945,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; } @@ -4845,25 +4958,27 @@ 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) { Object *obj = cn->value; Resource *res = Object::cast_to<Resource>(obj); - if (res == NULL) { + if (res == nullptr) { _set_error("The exported constant isn't a type or resource."); return; } @@ -4873,7 +4988,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) { @@ -4893,6 +5007,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; @@ -4902,20 +5017,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; @@ -4935,6 +5051,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; @@ -4947,7 +5064,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) { @@ -4977,7 +5093,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; @@ -4988,7 +5104,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; } @@ -5057,7 +5172,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; } @@ -5104,14 +5219,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 { @@ -5211,7 +5323,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (!_end_statement()) { - _set_error("Expected end of statement (\"enum\")."); + _set_end_statement_error("enum"); return; } @@ -5227,8 +5339,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } break; - default: { + case GDScriptTokenizer::TK_CF_PASS: { + tokenizer->advance(); + } break; + default: { _set_error(String() + "Unexpected token: " + tokenizer->get_token_name(tokenizer->get_token()) + ":" + tokenizer->get_token_identifier()); return; @@ -5238,7 +5353,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) { @@ -5247,13 +5361,12 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive Ref<GDScript> script; StringName native; - ClassNode *base_class = NULL; + ClassNode *base_class = nullptr; if (path != "") { //path (and optionally subclasses) if (path.is_rel_path()) { - String base = base_path; if (base == "" || base.is_rel_path()) { @@ -5268,22 +5381,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; } @@ -5291,7 +5399,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(); @@ -5309,7 +5416,7 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive _set_error("The class \"" + base + "\" couldn't be fully loaded (script error or cyclic dependency).", p_class->line); return; } - p = NULL; + p = nullptr; } else { List<PropertyInfo> props; ProjectSettings::get_singleton()->get_property_list(&props); @@ -5332,13 +5439,12 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive _set_error("Class '" + base + "' could not be fully loaded (script error or cyclic inheritance).", p_class->line); return; } - p = NULL; + p = nullptr; } } } while (p) { - bool found = false; for (int i = 0; i < p->subclasses.size(); i++) { @@ -5367,8 +5473,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) { @@ -5388,21 +5498,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); @@ -5410,7 +5516,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; } @@ -5419,15 +5524,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; } @@ -5470,10 +5572,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: { @@ -5637,8 +5743,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; @@ -5647,12 +5757,11 @@ 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; - ClassNode *p = NULL; + ClassNode *p = nullptr; if (name_part == 0) { if (ScriptServer::is_global_class(id)) { String script_path = ScriptServer::get_global_class_path(id); @@ -5934,7 +6043,7 @@ GDScriptParser::DataType GDScriptParser::_get_operation_type(const Variant::Oper a = a_ref; } else { Callable::CallError err; - a = Variant::construct(a_type, NULL, 0, err); + a = Variant::construct(a_type, nullptr, 0, err); if (err.error != Callable::CallError::CALL_OK) { r_valid = false; return DataType(); @@ -5947,7 +6056,7 @@ GDScriptParser::DataType GDScriptParser::_get_operation_type(const Variant::Oper b = b_ref; } else { Callable::CallError err; - b = Variant::construct(b_type, NULL, 0, err); + b = Variant::construct(b_type, nullptr, 0, err); if (err.error != Callable::CallError::CALL_OK) { r_valid = false; return DataType(); @@ -6108,7 +6217,7 @@ bool GDScriptParser::_is_type_compatible(const DataType &p_container, const Data StringName expr_native; Ref<Script> expr_script; - ClassNode *expr_class = NULL; + ClassNode *expr_class = nullptr; switch (p_expression.kind) { case DataType::NATIVE: { @@ -6219,12 +6328,14 @@ GDScriptParser::Node *GDScriptParser::_get_default_value_for_type(const DataType } else { ConstantNode *c = alloc_node<ConstantNode>(); Callable::CallError err; - c->value = Variant::construct(p_type.builtin_type, NULL, 0, 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; } @@ -6298,7 +6409,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { int idx = current_function->arguments.find(id->name); node_type = current_function->argument_types[idx]; } else { - node_type = _reduce_identifier_type(NULL, id->name, id->line, false); + node_type = _reduce_identifier_type(nullptr, id->name, id->line, false); } } break; case Node::TYPE_CAST: { @@ -6307,7 +6418,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) { @@ -6361,7 +6471,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()); @@ -6397,7 +6506,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; @@ -6435,7 +6543,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()); @@ -6503,7 +6610,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(); @@ -6532,7 +6638,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { } break; default: { Callable::CallError err; - Variant temp = Variant::construct(base_type.builtin_type, NULL, 0, err); + Variant temp = Variant::construct(base_type.builtin_type, nullptr, 0, err); bool valid = false; Variant res = temp.get(member_id->name.operator String(), &valid); @@ -6553,6 +6659,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 @@ -6565,7 +6672,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) { @@ -6573,6 +6679,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; @@ -6661,7 +6768,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { } default: { Callable::CallError err; - Variant temp = Variant::construct(base_type.builtin_type, NULL, 0, err); + Variant temp = Variant::construct(base_type.builtin_type, nullptr, 0, err); bool valid = false; Variant res = temp.get(cn->value, &valid); @@ -6763,13 +6870,12 @@ 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; DataType original_type = p_base_type; - ClassNode *base = NULL; - FunctionNode *callee = NULL; + ClassNode *base = nullptr; + FunctionNode *callee = nullptr; if (p_base_type.kind == DataType::CLASS) { base = p_base_type.class_type; @@ -6874,7 +6980,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."); } @@ -6965,7 +7073,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) { @@ -7033,7 +7143,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 += ")'."; @@ -7102,7 +7214,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat if (base_type.kind == DataType::BUILTIN) { Callable::CallError err; - Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err); + Variant tmp = Variant::construct(base_type.builtin_type, nullptr, 0, err); if (check_types) { if (!tmp.has_method(callee_name)) { @@ -7242,8 +7354,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(); @@ -7262,17 +7374,20 @@ 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 - ClassNode *base = NULL; + ClassNode *base = nullptr; if (base_type.kind == DataType::CLASS) { base = base_type.class_type; } 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; } @@ -7355,6 +7470,8 @@ 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_SUBGROUP | PROPERTY_USAGE_CATEGORY))) + // Check other script types while (scr.is_valid()) { Map<StringName, Variant> constants; @@ -7367,7 +7484,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN List<PropertyInfo> properties; scr->get_script_property_list(&properties); for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - if (E->get().name == p_member) { + if (E->get().name == p_member && IS_USAGE_MEMBER(E->get().usage)) { r_member_type = _type_from_property(E->get()); return true; } @@ -7389,7 +7506,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."); } @@ -7409,7 +7528,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN List<PropertyInfo> properties; ClassDB::get_property_list(native, &properties); for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - if (E->get().name == p_member) { + if (E->get().name == p_member && IS_USAGE_MEMBER(E->get().usage)) { // Check if a getter exists StringName getter_name = ClassDB::get_property_getter(native, p_member); if (getter_name != StringName()) { @@ -7449,7 +7568,7 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN List<PropertyInfo> properties; ClassDB::get_property_list(native, &properties); for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - if (E->get().name == p_member) { + if (E->get().name == p_member && IS_USAGE_MEMBER(E->get().usage)) { // Check if a getter exists StringName getter_name = ClassDB::get_property_getter(native, p_member); if (getter_name != StringName()) { @@ -7471,12 +7590,12 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN } } } +#undef IS_USAGE_MEMBER return false; } 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(); } @@ -7493,7 +7612,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; } @@ -7645,7 +7769,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. @@ -7681,12 +7804,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 @@ -7701,6 +7828,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); @@ -7725,7 +7853,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; @@ -7744,6 +7872,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; } @@ -7761,7 +7893,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; @@ -7804,10 +7938,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++) { @@ -7834,17 +7972,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 @@ -7963,30 +8143,20 @@ 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]; current_block = current_function->body; _mark_line_as_safe(current_function->line); _check_block_types(current_block); - current_block = NULL; - current_function = NULL; - if (error_set) return; + current_block = nullptr; + current_function = nullptr; + if (error_set) { + return; + } } for (int i = 0; i < p_class->functions.size(); i++) { @@ -7994,9 +8164,11 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) { current_block = current_function->body; _mark_line_as_safe(current_function->line); _check_block_types(current_block); - current_block = NULL; - current_function = NULL; - if (error_set) return; + current_block = nullptr; + current_function = nullptr; + if (error_set) { + return; + } } #ifdef DEBUG_ENABLED @@ -8017,7 +8189,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; } } @@ -8043,18 +8217,22 @@ 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 = NULL; + Node *last_var_assign = nullptr; // Check each statement for (List<Node *>::Element *E = p_block->statements.front(); E; E = E->next()) { 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); @@ -8076,6 +8254,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)) { @@ -8097,7 +8280,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; @@ -8120,6 +8304,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; } @@ -8233,6 +8421,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; @@ -8273,7 +8462,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); @@ -8308,7 +8499,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 @@ -8368,7 +8561,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 @@ -8387,9 +8582,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; @@ -8435,7 +8630,7 @@ void GDScriptParser::_add_warning(int p_code, int p_line, const Vector<String> & warn.symbols = p_symbols; warn.line = p_line == -1 ? tokenizer->get_token_line() : p_line; - List<GDScriptWarning>::Element *before = NULL; + List<GDScriptWarning>::Element *before = nullptr; for (List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) { if (E->get().line > warn.line) { break; @@ -8451,16 +8646,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; } @@ -8469,7 +8662,6 @@ bool GDScriptParser::has_error() const { } Error GDScriptParser::_parse(const String &p_base_path) { - base_path = p_base_path; //assume class @@ -8487,7 +8679,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; } @@ -8502,10 +8700,12 @@ Error GDScriptParser::_parse(const String &p_base_path) { } current_class = main_class; - current_function = NULL; - current_block = NULL; + 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); @@ -8517,6 +8717,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; } @@ -8524,7 +8728,7 @@ Error GDScriptParser::_parse(const String &p_base_path) { #ifdef DEBUG_ENABLED // Resolve warning ignores - Vector<Pair<int, String> > warning_skips = tokenizer->get_warning_skips(); + Vector<Pair<int, String>> warning_skips = tokenizer->get_warning_skips(); bool warning_is_error = GLOBAL_GET("debug/gdscript/warnings/treat_warnings_as_errors").booleanize(); for (List<GDScriptWarning>::Element *E = warnings.front(); E;) { GDScriptWarning &w = E->get(); @@ -8557,7 +8761,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; @@ -8566,12 +8769,11 @@ Error GDScriptParser::parse_bytecode(const Vector<uint8_t> &p_bytecode, const St tokenizer = tb; Error ret = _parse(p_base_path); memdelete(tb); - tokenizer = NULL; + tokenizer = nullptr; return ret; } Error GDScriptParser::parse(const String &p_code, const String &p_base_path, bool p_just_validate, const String &p_self_path, bool p_for_completion, Set<int> *r_safe_lines, bool p_dependencies_only) { - clear(); self_path = p_self_path; @@ -8587,44 +8789,40 @@ Error GDScriptParser::parse(const String &p_code, const String &p_base_path, boo tokenizer = tt; Error ret = _parse(p_base_path); memdelete(tt); - tokenizer = NULL; + tokenizer = nullptr; return ret; } 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); } - head = NULL; - list = NULL; + head = nullptr; + list = nullptr; completion_type = COMPLETION_NONE; - completion_node = NULL; - completion_class = NULL; - completion_function = NULL; - completion_block = NULL; - current_block = NULL; - current_class = NULL; + completion_node = nullptr; + completion_class = nullptr; + completion_function = nullptr; + completion_block = nullptr; + current_block = nullptr; + current_class = nullptr; completion_found = false; rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; - current_function = NULL; + current_function = nullptr; validating = false; for_completion = false; @@ -8641,70 +8839,58 @@ void GDScriptParser::clear() { dependencies.clear(); error = ""; #ifdef DEBUG_ENABLED - safe_lines = NULL; + safe_lines = nullptr; #endif // DEBUG_ENABLED } 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 = NULL; - list = NULL; - tokenizer = NULL; + head = nullptr; + list = nullptr; + tokenizer = nullptr; pending_newline = -1; clear(); } GDScriptParser::~GDScriptParser() { - clear(); } diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index c74d7dd856..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(NULL) {} + 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; @@ -201,12 +193,11 @@ public: extends_used = false; classname_used = false; end_line = -1; - owner = NULL; + owner = nullptr; } }; 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 = NULL; type = TYPE_BLOCK; - end_line = -1; - parent_block = NULL; - parent_class = NULL; - 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 = NULL; } }; 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 = NULL; - assign_op = NULL; - 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 = NULL; - body_else = NULL; } }; @@ -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), @@ -608,11 +603,12 @@ private: bool _recover_from_completion(); bool _parse_arguments(Node *p_parent, Vector<Node *> &p_args, bool p_static, bool p_can_codecomplete = false, bool p_parsing_constant = false); - bool _enter_indent_block(BlockNode *p_block = NULL); + bool _enter_indent_block(BlockNode *p_block = nullptr); bool _parse_newline(); 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 } @@ -665,7 +666,7 @@ public: #ifdef DEBUG_ENABLED const List<GDScriptWarning> &get_warnings() const { return warnings; } #endif // DEBUG_ENABLED - Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false, Set<int> *r_safe_lines = NULL, bool p_dependencies_only = false); + Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false, Set<int> *r_safe_lines = nullptr, bool p_dependencies_only = false); Error parse_bytecode(const Vector<uint8_t> &p_bytecode, const String &p_base_path = "", const String &p_self_path = ""); bool is_tool_script() const; @@ -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 9064998d32..82def3f877 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -178,7 +178,7 @@ static const _bit _type_list[] = { { Variant::PACKED_VECTOR2_ARRAY, "PackedVector2Array" }, { Variant::PACKED_VECTOR3_ARRAY, "PackedVector3Array" }, { Variant::PACKED_COLOR_ARRAY, "PackedColorArray" }, - { Variant::VARIANT_MAX, NULL }, + { Variant::VARIANT_MAX, nullptr }, }; struct _kws { @@ -236,11 +236,10 @@ static const _kws _keyword_list[] = { { GDScriptTokenizer::TK_WILDCARD, "_" }, { GDScriptTokenizer::TK_CONST_INF, "INF" }, { GDScriptTokenizer::TK_CONST_NAN, "NAN" }, - { GDScriptTokenizer::TK_ERROR, NULL } + { GDScriptTokenizer::TK_ERROR, nullptr } }; 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++; @@ -952,16 +952,16 @@ void GDScriptTokenizerText::_advance() { INCPOS(i); if (hexa_found) { - int64_t val = str.hex_to_int64(); + int64_t val = str.hex_to_int(); _make_constant(val); } else if (bin_found) { - int64_t val = str.bin_to_int64(); + int64_t val = str.bin_to_int(); _make_constant(val); } else if (period_found || exponent_found) { double val = str.to_double(); _make_constant(val); } else { - int64_t val = str.to_int64(); + int64_t val = str.to_int(); _make_constant(val); } @@ -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,13 +1063,12 @@ void GDScriptTokenizerText::_advance() { } void GDScriptTokenizerText::set_code(const String &p_code) { - code = p_code; len = p_code.length(); if (len) { _code = &code[0]; } else { - _code = NULL; + _code = nullptr; } code_pos = 0; line = 1; //it is stand-ar-ized that lines begin in 1 in code.. @@ -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(); } @@ -1358,7 +1334,7 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code) } Map<int, Variant> rev_constant_map; - const Variant *K = NULL; + const Variant *K = nullptr; while ((K = constant_map.next(K))) { rev_constant_map[constant_map[*K]] = *K; } @@ -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,10 +1380,9 @@ 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(), NULL, len, false); + Error err = encode_variant(E->get(), nullptr, len, false); ERR_FAIL_COND_V_MSG(err != OK, Vector<uint8_t>(), "Error when trying to encode Variant."); int pos = buf.size(); buf.resize(pos + len); @@ -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 3694825d80..32603c010f 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -32,6 +32,7 @@ #define GDSCRIPT_TOKENIZER_H #include "core/pair.h" +#include "core/set.h" #include "core/string_name.h" #include "core/ustring.h" #include "core/variant.h" @@ -170,16 +171,15 @@ public: virtual String get_token_error(int p_offset = 0) const = 0; virtual void advance(int p_amount = 1) = 0; #ifdef DEBUG_ENABLED - virtual const Vector<Pair<int, String> > &get_warning_skips() const = 0; + virtual const Vector<Pair<int, String>> &get_warning_skips() const = 0; virtual const Set<String> &get_warning_global_skips() const = 0; 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 @@ -223,7 +223,7 @@ class GDScriptTokenizerText : public GDScriptTokenizer { bool error_flag; #ifdef DEBUG_ENABLED - Vector<Pair<int, String> > warning_skips; + Vector<Pair<int, String>> warning_skips; Set<String> warning_global_skips; bool ignore_warnings; #endif // DEBUG_ENABLED @@ -244,14 +244,13 @@ public: virtual String get_token_error(int p_offset = 0) const; virtual void advance(int p_amount = 1); #ifdef DEBUG_ENABLED - virtual const Vector<Pair<int, String> > &get_warning_skips() const { return warning_skips; } + virtual const Vector<Pair<int, String>> &get_warning_skips() const { return warning_skips; } virtual const Set<String> &get_warning_global_skips() const { return warning_global_skips; } virtual bool is_ignoring_warnings() const { return ignore_warnings; } #endif // DEBUG_ENABLED }; class GDScriptTokenizerBuffer : public GDScriptTokenizer { - enum { TOKEN_BYTE_MASK = 0x80, @@ -283,8 +282,8 @@ public: virtual String get_token_error(int p_offset = 0) const; virtual void advance(int p_amount = 1); #ifdef DEBUG_ENABLED - virtual const Vector<Pair<int, String> > &get_warning_skips() const { - static Vector<Pair<int, String> > v; + virtual const Vector<Pair<int, String>> &get_warning_skips() const { + static Vector<Pair<int, String>> v; return v; } virtual const Set<String> &get_warning_global_skips() const { diff --git a/modules/gdscript/icons/icon_g_d_script.svg b/modules/gdscript/icons/GDScript.svg index 953bb9ae9e..953bb9ae9e 100644 --- a/modules/gdscript/icons/icon_g_d_script.svg +++ b/modules/gdscript/icons/GDScript.svg diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 0f6f13944b..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; @@ -327,7 +323,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN int default_value_idx = i - (p_func->arguments.size() - p_func->default_values.size()); if (default_value_idx >= 0) { const GDScriptParser::ConstantNode *const_node = dynamic_cast<const GDScriptParser::ConstantNode *>(p_func->default_values[default_value_idx]); - if (const_node == NULL) { + if (const_node == nullptr) { const GDScriptParser::OperatorNode *operator_node = dynamic_cast<const GDScriptParser::OperatorNode *>(p_func->default_values[default_value_idx]); if (operator_node) { const_node = dynamic_cast<const GDScriptParser::ConstantNode *>(operator_node->next); @@ -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(), ""); @@ -507,7 +500,7 @@ String ExtendGDScriptParser::get_uri() const { } const lsp::DocumentSymbol *ExtendGDScriptParser::search_symbol_defined_at_line(int p_line, const lsp::DocumentSymbol &p_parent) const { - const lsp::DocumentSymbol *ret = NULL; + const lsp::DocumentSymbol *ret = nullptr; if (p_line < p_parent.range.start.line) { return ret; } else if (p_parent.range.start.line == p_line) { @@ -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) { @@ -591,7 +582,7 @@ const lsp::DocumentSymbol *ExtendGDScriptParser::get_member_symbol(const String } } - return NULL; + return nullptr; } const List<lsp::DocumentLink> &ExtendGDScriptParser::get_document_links() const { @@ -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(NULL); + 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); @@ -613,11 +601,10 @@ const Array &ExtendGDScriptParser::get_member_completions() { name = members.next(name); } - const String *_class = inner_classes.next(NULL); + const String *_class = inner_classes.next(nullptr); while (_class) { - const ClassMembers *inner_class = inner_classes.getptr(*_class); - const String *member_name = inner_class->next(NULL); + const String *member_name = inner_class->next(nullptr); while (member_name) { const lsp::DocumentSymbol *symbol = inner_class->get(*member_name); lsp::CompletionItem item = symbol->make_completion_item(); @@ -648,7 +635,7 @@ Dictionary ExtendGDScriptParser::dump_function_api(const GDScriptParser::Functio int default_value_idx = i - (p_func->arguments.size() - p_func->default_values.size()); if (default_value_idx >= 0) { const GDScriptParser::ConstantNode *const_node = dynamic_cast<const GDScriptParser::ConstantNode *>(p_func->default_values[default_value_idx]); - if (const_node == NULL) { + if (const_node == nullptr) { const GDScriptParser::OperatorNode *operator_node = dynamic_cast<const GDScriptParser::OperatorNode *>(p_func->default_values[default_value_idx]); if (operator_node) { const_node = dynamic_cast<const GDScriptParser::ConstantNode *>(operator_node->next); @@ -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)) { @@ -778,7 +763,7 @@ Error ExtendGDScriptParser::parse(const String &p_code, const String &p_path) { path = p_path; lines = p_code.split("\n"); - Error err = GDScriptParser::parse(p_code, p_path.get_base_dir(), false, p_path, false, NULL, false); + Error err = GDScriptParser::parse(p_code, p_path.get_base_dir(), false, p_path, false, nullptr, false); update_diagnostics(); update_symbols(); update_document_links(p_code); 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 2243a7b81d..2a67d2ff4f 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -29,13 +29,14 @@ /*************************************************************************/ #include "gdscript_language_protocol.h" + #include "core/io/json.h" #include "core/os/copymem.h" #include "core/project_settings.h" #include "editor/editor_log.h" #include "editor/editor_node.h" -GDScriptLanguageProtocol *GDScriptLanguageProtocol::singleton = NULL; +GDScriptLanguageProtocol *GDScriptLanguageProtocol::singleton = nullptr; Error GDScriptLanguageProtocol::LSPeer::handle_data() { int read = 0; @@ -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,15 +184,16 @@ 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 != NULL) { + if (peer != nullptr) { String msg = JSON::print(request); msg = format_output(msg); (*peer)->res_queue.push_back(msg.utf8()); @@ -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()); @@ -230,26 +230,26 @@ void GDScriptLanguageProtocol::poll() { if (server->is_connection_available()) { on_client_connected(); } - const int *id = NULL; + const int *id = nullptr; while ((id = clients.next(id))) { Ref<LSPeer> peer = clients.get(*id); StreamPeerTCP::Status status = peer->connection->get_status(); if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) { on_client_disconnected(*id); - id = NULL; + id = nullptr; } else { if (peer->connection->get_available_bytes() > 0) { latest_client_id = *id; Error err = peer->handle_data(); if (err != OK && err != ERR_BUSY) { on_client_disconnected(*id); - id = NULL; + id = nullptr; } } Error err = peer->send_data(); if (err != OK && err != ERR_BUSY) { on_client_disconnected(*id); - id = NULL; + id = nullptr; } } } @@ -260,7 +260,7 @@ Error GDScriptLanguageProtocol::start(int p_port, const IP_Address &p_bind_ip) { } void GDScriptLanguageProtocol::stop() { - const int *id = NULL; + const int *id = nullptr; while ((id = clients.next(id))) { Ref<LSPeer> peer = clients.get(*id); peer->connection->disconnect_from_host(); @@ -271,10 +271,13 @@ 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 == NULL); + ERR_FAIL_COND(peer == nullptr); Dictionary message = make_notification(p_method, p_params); String msg = JSON::print(message); @@ -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 3f0ae36af2..cf5242e8c5 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.h +++ b/modules/gdscript/language_server/gdscript_language_protocol.h @@ -68,10 +68,10 @@ private: static GDScriptLanguageProtocol *singleton; - HashMap<int, Ref<LSPeer> > clients; + 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 7170c63058..3387d262f8 100644 --- a/modules/gdscript/language_server/gdscript_language_server.cpp +++ b/modules/gdscript/language_server/gdscript_language_server.cpp @@ -29,13 +29,14 @@ /*************************************************************************/ #include "gdscript_language_server.h" + #include "core/os/file_access.h" #include "core/os/os.h" #include "editor/editor_log.h" #include "editor/editor_node.h" GDScriptLanguageServer::GDScriptLanguageServer() { - thread = NULL; + thread = nullptr; thread_running = false; started = false; @@ -48,7 +49,6 @@ GDScriptLanguageServer::GDScriptLanguageServer() { } void GDScriptLanguageServer::_notification(int p_what) { - switch (p_what) { case NOTIFICATION_ENTER_TREE: start(); @@ -87,7 +87,7 @@ void GDScriptLanguageServer::start() { if (protocol.start(port, IP_Address("127.0.0.1")) == OK) { EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR); if (use_thread) { - ERR_FAIL_COND(thread != NULL); + ERR_FAIL_COND(thread != nullptr); thread_running = true; thread = Thread::create(GDScriptLanguageServer::thread_main, this); } @@ -98,11 +98,11 @@ void GDScriptLanguageServer::start() { void GDScriptLanguageServer::stop() { if (use_thread) { - ERR_FAIL_COND(NULL == thread); + ERR_FAIL_COND(nullptr == thread); thread_running = false; Thread::wait_to_finish(thread); memdelete(thread); - thread = NULL; + thread = nullptr; } protocol.stop(); started = false; diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index d5723fd20f..c6fe3169dc 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -29,12 +29,14 @@ /*************************************************************************/ #include "gdscript_text_document.h" + #include "../gdscript.h" #include "core/os/os.h" #include "editor/editor_settings.h" #include "editor/plugins/script_text_editor.h" #include "gdscript_extend_parser.h" #include "gdscript_language_protocol.h" +#include "servers/display_server.h" void GDScriptTextDocument::_bind_methods() { ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen); @@ -84,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(NULL); + const StringName *class_ptr = native_members.next(nullptr); while (class_ptr) { - const ClassMembers &members = native_members.get(*class_ptr); - const String *name = members.next(NULL); + 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); @@ -111,7 +109,6 @@ void GDScriptTextDocument::initialize() { } Variant GDScriptTextDocument::nativeSymbol(const Dictionary &p_params) { - Variant ret; lsp::NativeSymbolInspectParams params; @@ -141,7 +138,6 @@ Array GDScriptTextDocument::documentSymbol(const Dictionary &p_params) { } Array GDScriptTextDocument::completion(const Dictionary &p_params) { - Array arr; lsp::CompletionParams params; @@ -152,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; @@ -200,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(); @@ -219,28 +211,24 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) { } Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) { - lsp::CompletionItem item; item.load(p_params); lsp::CompletionParams params; Variant data = p_params["data"]; - const lsp::DocumentSymbol *symbol = NULL; + 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]; @@ -312,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; @@ -326,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; @@ -419,7 +404,8 @@ void GDScriptTextDocument::sync_script_content(const String &p_path, const Strin void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) { ScriptEditor::get_singleton()->call_deferred("_help_class_goto", p_symbol_id); - OS::get_singleton()->move_window_to_foreground(); + + DisplayServer::get_singleton()->window_move_to_foreground(); } Array GDScriptTextDocument::find_symbols(const lsp::TextDocumentPositionParams &p_location, List<const lsp::DocumentSymbol *> &r_list) { diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index ea54784f96..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,19 +42,19 @@ 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) { Map<String, ExtendGDScriptParser *>::Element *parser = parse_results.find(p_path); Map<String, ExtendGDScriptParser *>::Element *script = scripts.find(p_path); if (parser && script) { - if (script->get() && script->get() == script->get()) { + if (script->get() && script->get() == parser->get()) { memdelete(script->get()); } else { memdelete(script->get()); @@ -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; @@ -93,7 +93,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_native_symbol(const String &p_ class_name = ClassDB::get_parent_class(class_name); } - return NULL; + return nullptr; } const lsp::DocumentSymbol *GDScriptWorkspace::get_script_symbol(const String &p_path) const { @@ -101,7 +101,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_script_symbol(const String &p_ if (S) { return &(S->get()->get_symbols()); } - return NULL; + return nullptr; } void GDScriptWorkspace::reload_all_workspace_scripts() { @@ -152,7 +152,7 @@ ExtendGDScriptParser *GDScriptWorkspace::get_parse_successed_script(const String if (S) { return S->get(); } - return NULL; + return nullptr; } ExtendGDScriptParser *GDScriptWorkspace::get_parse_result(const String &p_path) { @@ -164,7 +164,7 @@ ExtendGDScriptParser *GDScriptWorkspace::get_parse_result(const String &p_path) if (S) { return S->get(); } - return NULL; + return nullptr; } Array GDScriptWorkspace::symbol(const Dictionary &p_params) { @@ -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,51 +393,53 @@ void GDScriptWorkspace::_get_owners(EditorFileSystemDirectory *efsd, String p_pa break; } } - if (!found) + if (!found) { continue; + } owners.push_back(efsd->get_file_path(i)); } } -Node *GDScriptWorkspace::_get_owner_node(String p_path) { - Node *owner_node = NULL; +Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) { + Node *owner_scene_node = nullptr; List<String> owners; _get_owners(EditorFileSystem::get_singleton()->get_filesystem(), p_path, owners); - if (owners.size() > 0) { - NodePath owner_path = owners[0]; - Ref<PackedScene> owner_res = ResourceLoader::load(owner_path); - owner_node = owner_res->instance(PackedScene::GEN_EDIT_STATE_DISABLED); + for (int i = 0; i < owners.size(); i++) { + NodePath owner_path = owners[i]; + RES owner_res = ResourceLoader::load(owner_path); + if (Object::cast_to<PackedScene>(owner_res.ptr())) { + Ref<PackedScene> owner_packed_scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*owner_res)); + owner_scene_node = owner_packed_scene->instance(); + break; + } } - return owner_node; + return owner_scene_node; } 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; if (const ExtendGDScriptParser *parser = get_parse_result(path)) { - Node *owner_node = _get_owner_node(path); + Node *owner_scene_node = _get_owner_scene_node(path); String code = parser->get_text_for_completion(p_params.position); - GDScriptLanguage::get_singleton()->complete_code(code, path, owner_node, r_options, forced, call_hint); - if (owner_node) { - memdelete(owner_node); + GDScriptLanguage::get_singleton()->complete_code(code, path, owner_scene_node, r_options, forced, call_hint); + if (owner_scene_node) { + memdelete(owner_scene_node); } } } 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 = NULL; + 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()) { @@ -453,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, NULL, 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(); @@ -476,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; @@ -494,15 +489,13 @@ 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); - const StringName *class_ptr = native_members.next(NULL); + const StringName *class_ptr = native_members.next(nullptr); while (class_ptr) { const ClassMembers &members = native_members.get(*class_ptr); if (const lsp::DocumentSymbol *const *symbol = members.getptr(symbol_identifier)) { @@ -519,9 +512,8 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP } const HashMap<String, ClassMembers> &inner_classes = script->get_inner_classes(); - const String *_class = inner_classes.next(NULL); + 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); @@ -534,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) { @@ -548,7 +539,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_native_symbol(const lsp::N } } - return NULL; + return nullptr; } void GDScriptWorkspace::resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list) { @@ -570,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)) { @@ -587,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/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h index 8b46d345d9..e45b06747d 100644 --- a/modules/gdscript/language_server/gdscript_workspace.h +++ b/modules/gdscript/language_server/gdscript_workspace.h @@ -42,7 +42,7 @@ class GDScriptWorkspace : public Reference { private: void _get_owners(EditorFileSystemDirectory *efsd, String p_path, List<String> &owners); - Node *_get_owner_node(String p_path); + Node *_get_owner_scene_node(String p_path); protected: static void _bind_methods(); diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp index a2dcc48820..cf27a1578c 100644 --- a/modules/gdscript/language_server/lsp.hpp +++ b/modules/gdscript/language_server/lsp.hpp @@ -33,7 +33,7 @@ #include "core/class_db.h" #include "core/list.h" -#include "editor/doc/doc_data.h" +#include "editor/doc_data.h" namespace lsp { @@ -149,14 +149,13 @@ struct Location { * Represents a link between a source and a target location. */ struct LocationLink { - /** * Span of the origin of this link. * * Used as the underlined span for mouse interaction. Defaults to the word range at * the mouse position. */ - Range *originSelectionRange = NULL; + Range *originSelectionRange = nullptr; /** * The target resource identifier 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,10 +1698,9 @@ struct InitializeResult { }; struct GodotNativeClassInfo { - String name; - const DocData::ClassDoc *class_doc = NULL; - const ClassDB::ClassInfo *class_info = NULL; + const DocData::ClassDoc *class_doc = nullptr; + const ClassDB::ClassInfo *class_info = nullptr; Dictionary to_json() { Dictionary dict; @@ -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 b5eb09d6ba..0625123530 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -37,7 +37,7 @@ #include "gdscript.h" #include "gdscript_tokenizer.h" -GDScriptLanguage *script_language_gd = NULL; +GDScriptLanguage *script_language_gd = nullptr; Ref<ResourceFormatLoaderGDScript> resource_loader_gd; Ref<ResourceFormatSaverGDScript> resource_saver_gd; @@ -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(); diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h index 55920e8b97..18e57c1211 100644 --- a/modules/gdscript/register_types.h +++ b/modules/gdscript/register_types.h @@ -28,5 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef GDSCRIPT_REGISTER_TYPES_H +#define GDSCRIPT_REGISTER_TYPES_H + void register_gdscript_types(); void unregister_gdscript_types(); + +#endif // GDSCRIPT_REGISTER_TYPES_H |