diff options
Diffstat (limited to 'modules/gdscript')
-rw-r--r-- | modules/gdscript/doc_classes/@GDScript.xml | 100 | ||||
-rw-r--r-- | modules/gdscript/editor/gdscript_highlighter.cpp | 4 | ||||
-rw-r--r-- | modules/gdscript/gdscript.h | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_editor.cpp | 227 | ||||
-rw-r--r-- | modules/gdscript/gdscript_function.cpp | 50 | ||||
-rw-r--r-- | modules/gdscript/gdscript_functions.cpp | 32 | ||||
-rw-r--r-- | modules/gdscript/gdscript_functions.h | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 81 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.h | 4 |
9 files changed, 312 insertions, 190 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 3870a5ea7d..f65f2a8935 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -345,45 +345,47 @@ <method name="fmod"> <return type="float"> </return> - <argument index="0" name="x" type="float"> + <argument index="0" name="a" type="float"> </argument> - <argument index="1" name="y" type="float"> + <argument index="1" name="b" type="float"> </argument> <description> - Returns the floating-point remainder of [code]x/y[/code]. + Returns the floating-point remainder of [code]a/b[/code], keeping the sign of [code]a[/code]. [codeblock] # Remainder is 1.5 var remainder = fmod(7, 5.5) [/codeblock] + For the integer remainder operation, use the % operator. </description> </method> <method name="fposmod"> <return type="float"> </return> - <argument index="0" name="x" type="float"> + <argument index="0" name="a" type="float"> </argument> - <argument index="1" name="y" type="float"> + <argument index="1" name="b" type="float"> </argument> <description> - Returns the floating-point remainder of [code]x/y[/code] that wraps equally in positive and negative. + Returns the floating-point modulus of [code]a/b[/code] that wraps equally in positive and negative. [codeblock] - var i = -10 - while i < 0: - prints(i, fposmod(i, 10)) + var i = -6 + while i < 5: + prints(i, fposmod(i, 3)) i += 1 [/codeblock] Produces: [codeblock] - -10 10 - -9 1 - -8 2 - -7 3 - -6 4 - -5 5 - -4 6 - -3 7 - -2 8 - -1 9 + -6 0 + -5 1 + -4 2 + -3 0 + -2 1 + -1 2 + 0 0 + 1 1 + 2 2 + 3 0 + 4 1 [/codeblock] </description> </method> @@ -571,6 +573,29 @@ [/codeblock] </description> </method> + <method name="lerp_angle"> + <return type="float"> + </return> + <argument index="0" name="from" type="float"> + </argument> + <argument index="1" name="to" type="float"> + </argument> + <argument index="2" name="weight" type="float"> + </argument> + <description> + Linearly interpolates between two angles (in radians) by a normalized value. + Similar to [method lerp] but interpolate correctly when the angles wrap around [constant @GDScript.TAU]. + [codeblock] + extends Sprite + var elapsed = 0.0 + func _process(delta): + var min_angle = deg2rad(0.0) + var max_angle = deg2rad(90.0) + rotation = lerp_angle(min_angle, max_angle, elapsed) + elapsed += delta + [/codeblock] + </description> + </method> <method name="linear2db"> <return type="float"> </return> @@ -697,12 +722,43 @@ Converts a 2D point expressed in the polar coordinate system (a distance from the origin [code]r[/code] and an angle [code]th[/code]) to the cartesian coordinate system (X and Y axis). </description> </method> + <method name="posmod"> + <return type="int"> + </return> + <argument index="0" name="a" type="int"> + </argument> + <argument index="1" name="b" type="int"> + </argument> + <description> + Returns the integer modulus of [code]a/b[/code] that wraps equally in positive and negative. + [codeblock] + var i = -6 + while i < 5: + prints(i, posmod(i, 3)) + i += 1 + [/codeblock] + Produces: + [codeblock] + -6 0 + -5 1 + -4 2 + -3 0 + -2 1 + -1 2 + 0 0 + 1 1 + 2 2 + 3 0 + 4 1 + [/codeblock] + </description> + </method> <method name="pow"> <return type="float"> </return> - <argument index="0" name="x" type="float"> + <argument index="0" name="base" type="float"> </argument> - <argument index="1" name="y" type="float"> + <argument index="1" name="exp" type="float"> </argument> <description> Returns the result of [code]x[/code] raised to the power of [code]y[/code]. @@ -1039,7 +1095,7 @@ <argument index="0" name="step" type="float"> </argument> <description> - Returns the position of the first non-zero digit, after the decimal point. + Returns the position of the first non-zero digit, after the decimal point. Note that the maximum return value is 10, which is a design decision in the implementation. [codeblock] # n is 0 n = step_decimals(5) diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index 62b65fe96b..963b40529d 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -370,8 +370,8 @@ void GDScriptSyntaxHighlighter::_update_cache() { bool default_theme = text_editor_color_theme == "Default"; bool dark_theme = settings->is_dark_theme(); - function_definition_color = Color::html(default_theme ? "#01e1ff" : dark_theme ? "#01e1ff" : "#00a5ba"); - node_path_color = Color::html(default_theme ? "#64c15a" : dark_theme ? "64c15a" : "#518b4b"); + function_definition_color = default_theme ? Color(0.0, 0.88, 1.0) : dark_theme ? Color(0.0, 0.88, 1.0) : Color(0.0, 0.65, 0.73); + node_path_color = default_theme ? Color(0.39, 0.76, 0.35) : dark_theme ? Color(0.39, 0.76, 0.35) : Color(0.32, 0.55, 0.29); EDITOR_DEF("text_editor/highlighting/gdscript/function_definition_color", function_definition_color); EDITOR_DEF("text_editor/highlighting/gdscript/node_path_color", node_path_color); diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 1756f6eabc..a5ad23c75d 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -458,7 +458,7 @@ public: virtual bool can_inherit_from_file() { return true; } virtual int find_function(const String &p_function, const String &p_code) const; virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const; - virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint); + virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint); #ifdef TOOLS_ENABLED virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result); #endif diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 26b14a6148..9f65a9fff1 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -159,7 +159,11 @@ bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int & 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) + "." + String(cl->subclasses[i]->functions[j]->name); + 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; } } @@ -382,8 +386,6 @@ 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) { - if (_debug_parse_err_line >= 0) - return ""; return ""; } @@ -509,12 +511,14 @@ struct GDScriptCompletionIdentifier { assigned_expression(NULL) {} }; -static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Set<String> &r_list) { +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++) { - r_list.insert(quote_style + p_dir->get_file_path(i) + quote_style); + ScriptCodeCompletionOption option(p_dir->get_file_path(i), ScriptCodeCompletionOption::KIND_FILE_PATH); + option.insert_text = quote_style + option.display + quote_style; + r_list.insert(option.display, option); } for (int i = 0; i < p_dir->get_subdir_count(); i++) { @@ -1807,14 +1811,15 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio return arghint; } -static void _find_enumeration_candidates(const String p_enum_hint, Set<String> &r_result) { +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; for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) { if (GlobalConstants::get_global_constant_enum(i) == current_enum) { - r_result.insert(GlobalConstants::get_global_constant_name(i)); + ScriptCodeCompletionOption option(GlobalConstants::get_global_constant_name(i), ScriptCodeCompletionOption::KIND_ENUM); + r_result.insert(option.display, option); } } } else { @@ -1829,15 +1834,17 @@ static void _find_enumeration_candidates(const String p_enum_hint, Set<String> & ClassDB::get_enum_constants(class_name, enum_name, &enum_constants); for (List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) { String candidate = class_name + "." + E->get(); - r_result.insert(candidate); + ScriptCodeCompletionOption option(candidate, ScriptCodeCompletionOption::KIND_ENUM); + r_result.insert(option.display, option); } } } -static void _find_identifiers_in_block(const GDScriptCompletionContext &p_context, Set<String> &r_result) { +static void _find_identifiers_in_block(const GDScriptCompletionContext &p_context, Map<String, ScriptCodeCompletionOption> &r_result) { for (Map<StringName, GDScriptParser::LocalVarNode *>::Element *E = p_context.block->variables.front(); E; E = E->next()) { if (E->get()->line < p_context.line) { - r_result.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_VARIABLE); + r_result.insert(option.display, option); } } if (p_context.block->parent_block) { @@ -1847,40 +1854,47 @@ static void _find_identifiers_in_block(const GDScriptCompletionContext &p_contex } } -static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Set<String> &r_result); +static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result); -static void _find_identifiers_in_class(const GDScriptCompletionContext &p_context, bool p_static, bool p_only_functions, bool p_parent_only, Set<String> &r_result) { +static void _find_identifiers_in_class(const GDScriptCompletionContext &p_context, bool p_static, bool p_only_functions, bool p_parent_only, Map<String, ScriptCodeCompletionOption> &r_result) { if (!p_parent_only) { if (!p_static && !p_only_functions) { for (int i = 0; i < p_context._class->variables.size(); i++) { - r_result.insert(p_context._class->variables[i].identifier); + ScriptCodeCompletionOption option(p_context._class->variables[i].identifier, ScriptCodeCompletionOption::KIND_MEMBER); + r_result.insert(option.display, option); } } if (!p_only_functions) { for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_context._class->constant_expressions.front(); E; E = E->next()) { - r_result.insert(E->key()); + ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_CONSTANT); + r_result.insert(option.display, option); } for (int i = 0; i < p_context._class->subclasses.size(); i++) { - r_result.insert(p_context._class->subclasses[i]->name); + ScriptCodeCompletionOption option(p_context._class->subclasses[i]->name, ScriptCodeCompletionOption::KIND_CLASS); + r_result.insert(option.display, option); } } for (int i = 0; i < p_context._class->static_functions.size(); i++) { + ScriptCodeCompletionOption option(p_context._class->static_functions[i]->name.operator String(), ScriptCodeCompletionOption::KIND_FUNCTION); if (p_context._class->static_functions[i]->arguments.size()) { - r_result.insert(p_context._class->static_functions[i]->name.operator String() + "("); + option.insert_text += "("; } else { - r_result.insert(p_context._class->static_functions[i]->name.operator String() + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } if (!p_static) { for (int i = 0; i < p_context._class->functions.size(); i++) { + ScriptCodeCompletionOption option(p_context._class->functions[i]->name.operator String(), ScriptCodeCompletionOption::KIND_FUNCTION); if (p_context._class->functions[i]->arguments.size()) { - r_result.insert(p_context._class->functions[i]->name.operator String() + "("); + option.insert_text += "("; } else { - r_result.insert(p_context._class->functions[i]->name.operator String() + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } } } @@ -1898,12 +1912,14 @@ static void _find_identifiers_in_class(const GDScriptCompletionContext &p_contex _find_identifiers_in_base(c, base_type, p_only_functions, r_result); } -static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Set<String> &r_result) { +static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) { GDScriptParser::DataType base_type = p_base.type; bool _static = base_type.is_meta_type; if (_static && base_type.kind != GDScriptParser::DataType::BUILTIN) { - r_result.insert("new("); + ScriptCodeCompletionOption option("new", ScriptCodeCompletionOption::KIND_FUNCTION); + option.insert_text += "("; + r_result.insert(option.display, option); } while (base_type.has_type) { @@ -1921,26 +1937,31 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context if (script.is_valid()) { if (!_static && !p_only_functions) { for (const Set<StringName>::Element *E = script->get_members().front(); E; E = E->next()) { - r_result.insert(E->get().operator String()); + ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_MEMBER); + r_result.insert(option.display, option); } } if (!p_only_functions) { for (const Map<StringName, Variant>::Element *E = script->get_constants().front(); E; E = E->next()) { - r_result.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT); + r_result.insert(option.display, option); } } for (const Map<StringName, GDScriptFunction *>::Element *E = script->get_member_functions().front(); E; E = E->next()) { if (!_static || E->get()->is_static()) { + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_FUNCTION); if (E->get()->get_argument_count()) { - r_result.insert(E->key().operator String() + "("); + option.insert_text += "("; } else { - r_result.insert(E->key().operator String() + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } } if (!p_only_functions) { for (const Map<StringName, Ref<GDScript> >::Element *E = script->get_subclasses().front(); E; E = E->next()) { - r_result.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + r_result.insert(option.display, option); } } base_type = GDScriptParser::DataType(); @@ -1964,25 +1985,29 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context List<PropertyInfo> members; scr->get_script_property_list(&members); for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { - r_result.insert(E->get().name); + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER); + r_result.insert(option.display, option); } } if (!p_only_functions) { Map<StringName, Variant> constants; scr->get_constants(&constants); for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { - r_result.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT); + r_result.insert(option.display, option); } } List<MethodInfo> methods; scr->get_script_method_list(&methods); for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION); if (E->get().arguments.size()) { - r_result.insert(E->get().name + "("); + option.insert_text += "("; } else { - r_result.insert(E->get().name + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } Ref<Script> base_script = scr->get_base_script(); @@ -2009,7 +2034,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context List<String> constants; ClassDB::get_integer_constant_list(type, &constants); for (List<String>::Element *E = constants.front(); E; E = E->next()) { - r_result.insert(E->get()); + ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CONSTANT); + r_result.insert(option.display, option); } if (!_static) { @@ -2022,7 +2048,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context if (E->get().name.find("/") != -1) { continue; } - r_result.insert(E->get().name); + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER); + r_result.insert(option.display, option); } } } @@ -2035,11 +2062,13 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context if (E->get().name.begins_with("_")) { continue; } + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION); if (E->get().arguments.size()) { - r_result.insert(E->get().name + "("); + option.insert_text += "("; } else { - r_result.insert(E->get().name + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } } @@ -2058,7 +2087,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { if (String(E->get().name).find("/") == -1) { - r_result.insert(E->get().name); + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER); + r_result.insert(option.display, option); } } } @@ -2066,11 +2096,13 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context List<MethodInfo> methods; tmp.get_method_list(&methods); for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION); if (E->get().arguments.size()) { - r_result.insert(E->get().name + "("); + option.insert_text += "("; } else { - r_result.insert(E->get().name + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } return; @@ -2082,7 +2114,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context } } -static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p_only_functions, Set<String> &r_result) { +static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) { const GDScriptParser::BlockNode *block = p_context.block; @@ -2091,7 +2123,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p const GDScriptParser::FunctionNode *f = p_context.function; for (int i = 0; i < f->arguments.size(); i++) { - r_result.insert(f->arguments[i].operator String()); + ScriptCodeCompletionOption option(f->arguments[i].operator String(), ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + r_result.insert(option.display, option); } } @@ -2116,11 +2149,13 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) { MethodInfo mi = GDScriptFunctions::get_info(GDScriptFunctions::Function(i)); + ScriptCodeCompletionOption option(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))), ScriptCodeCompletionOption::KIND_FUNCTION); if (mi.arguments.size() || (mi.flags & METHOD_FLAG_VARARG)) { - r_result.insert(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) + "("); + option.insert_text += "("; } else { - r_result.insert(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) + "()"); + option.insert_text += "()"; } + r_result.insert(option.display, option); } static const char *_type_names[Variant::VARIANT_MAX] = { @@ -2130,7 +2165,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p }; for (int i = 0; i < Variant::VARIANT_MAX; i++) { - r_result.insert(_type_names[i]); + ScriptCodeCompletionOption option(_type_names[i], ScriptCodeCompletionOption::KIND_CLASS); + r_result.insert(option.display, option); } static const char *_keywords[] = { @@ -2144,7 +2180,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p const char **kw = _keywords; while (*kw) { - r_result.insert(*kw); + ScriptCodeCompletionOption option(*kw, ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + r_result.insert(option.display, option); kw++; } @@ -2158,7 +2195,8 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p } String path = ProjectSettings::get_singleton()->get(s); if (path.begins_with("*")) { - r_result.insert(s.get_slice("/", 1)); + ScriptCodeCompletionOption option(s.get_slice("/", 1), ScriptCodeCompletionOption::KIND_CONSTANT); + r_result.insert(option.display, option); } } @@ -2166,16 +2204,18 @@ static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p List<StringName> named_scripts; ScriptServer::get_global_class_list(&named_scripts); for (List<StringName>::Element *E = named_scripts.front(); E; E = E->next()) { - r_result.insert(E->get().operator String()); + ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + r_result.insert(option.display, option); } // Native classes for (const Map<StringName, int>::Element *E = GDScriptLanguage::get_singleton()->get_global_map().front(); E; E = E->next()) { - r_result.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + r_result.insert(option.display, option); } } -static void _find_call_arguments(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Set<String> &r_result, String &r_arghint) { +static void _find_call_arguments(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Map<String, ScriptCodeCompletionOption> &r_result, String &r_arghint) { Variant base = p_base.value; GDScriptParser::DataType base_type = p_base.type; @@ -2199,7 +2239,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) { for (int i = 0; i < base_type.class_type->_signals.size(); i++) { - r_result.insert(quote_style + base_type.class_type->_signals[i].name.operator String() + quote_style); + ScriptCodeCompletionOption option(base_type.class_type->_signals[i].name.operator String(), ScriptCodeCompletionOption::KIND_SIGNAL); + option.insert_text = quote_style + option.display + quote_style; + r_result.insert(option.display, option); } } @@ -2212,7 +2254,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con List<MethodInfo> signals; gds->get_script_signal_list(&signals); for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { - r_result.insert(quote_style + E->get().name + quote_style); + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_SIGNAL); + option.insert_text = quote_style + option.display + quote_style; + r_result.insert(option.display, option); } } Ref<GDScript> base_script = gds->get_base_script(); @@ -2250,7 +2294,8 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con List<String> options; obj->get_argument_options(p_method, p_argidx, &options); for (List<String>::Element *F = options.front(); F; F = F->next()) { - r_result.insert(F->get()); + ScriptCodeCompletionOption option(F->get(), ScriptCodeCompletionOption::KIND_FUNCTION); + r_result.insert(option.display, option); } } } @@ -2271,7 +2316,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con List<MethodInfo> signals; ClassDB::get_signal_list(class_name, &signals); for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { - r_result.insert(quote_style + E->get().name + quote_style); + ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_SIGNAL); + option.insert_text = quote_style + option.display + quote_style; + r_result.insert(option.display, option); } } @@ -2286,7 +2333,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con continue; } String name = s.get_slice("/", 1); - r_result.insert(quote_style + "/root/" + name + quote_style); + ScriptCodeCompletionOption option("/root/" + name, ScriptCodeCompletionOption::KIND_NODE_PATH); + option.insert_text = quote_style + option.display + quote_style; + r_result.insert(option.display, option); } } @@ -2300,7 +2349,9 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con continue; } String name = s.get_slice("/", 1); - r_result.insert(quote_style + name + quote_style); + ScriptCodeCompletionOption option(name, ScriptCodeCompletionOption::KIND_CONSTANT); + option.insert_text = quote_style + option.display + quote_style; + r_result.insert(option.display, option); } } @@ -2333,7 +2384,7 @@ 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, Set<String> &r_result, bool &r_forced, String &r_arghint) { +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) ? "'" : "\""; @@ -2451,17 +2502,19 @@ static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDS _find_call_arguments(p_context, ci, function, p_argidx, _static, r_result, r_arghint); if (function == "connect" && p_argidx == 2) { - Set<String> methods; + Map<String, ScriptCodeCompletionOption> methods; _find_identifiers_in_base(p_context, connect_base, true, methods); - for (Set<String>::Element *E = methods.front(); E; E = E->next()) { - r_result.insert(quote_style + E->get().replace("(", "").replace(")", "") + quote_style); + for (Map<String, ScriptCodeCompletionOption>::Element *E = methods.front(); E; E = E->next()) { + ScriptCodeCompletionOption &option = E->value(); + option.insert_text = quote_style + option.display + quote_style; + r_result.insert(option.display, option); } } r_forced = r_result.size() > 0; } -Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint) { +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) ? "'" : "\""; @@ -2469,7 +2522,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path parser.parse(p_code, p_path.get_base_dir(), false, p_path, true); r_forced = false; - Set<String> options; + Map<String, ScriptCodeCompletionOption> options; GDScriptCompletionContext context; context._class = parser.get_completion_class(); context.block = parser.get_completion_block(); @@ -2490,7 +2543,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path List<StringName> constants; Variant::get_constants_for_type(parser.get_completion_built_in_constant(), &constants); for (List<StringName>::Element *E = constants.front(); E; E = E->next()) { - options.insert(E->get().operator String()); + ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT); + options.insert(option.display, option); } } break; case GDScriptParser::COMPLETION_PARENT_FUNCTION: { @@ -2515,9 +2569,11 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path r_forced = true; String idopt = opt.unquote(); if (idopt.replace("/", "_").is_valid_identifier()) { - options.insert(idopt); + ScriptCodeCompletionOption option(idopt, ScriptCodeCompletionOption::KIND_NODE_PATH); + options.insert(option.display, option); } else { - options.insert(opt); + ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH); + options.insert(option.display, option); } } } @@ -2532,7 +2588,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path continue; } String name = s.get_slice("/", 1); - options.insert(quote_style + "/root/" + name + quote_style); + ScriptCodeCompletionOption option(quote_style + "/root/" + name + quote_style, ScriptCodeCompletionOption::KIND_NODE_PATH); + options.insert(option.display, option); } } } break; @@ -2655,7 +2712,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path } method_hint += ":"; - options.insert(method_hint); + ScriptCodeCompletionOption option(method_hint, ScriptCodeCompletionOption::KIND_FUNCTION); + options.insert(option.display, option); } } break; case GDScriptParser::COMPLETION_YIELD: { @@ -2673,7 +2731,9 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path switch (base_type.kind) { case GDScriptParser::DataType::CLASS: { for (int i = 0; i < base_type.class_type->_signals.size(); i++) { - options.insert(quote_style + base_type.class_type->_signals[i].name.operator String() + quote_style); + ScriptCodeCompletionOption option(base_type.class_type->_signals[i].name.operator String(), ScriptCodeCompletionOption::KIND_SIGNAL); + option.insert_text = quote_style + option.display + quote_style; + options.insert(option.display, option); } base_type = base_type.class_type->base_type; } break; @@ -2684,7 +2744,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path List<MethodInfo> signals; scr->get_script_signal_list(&signals); for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { - options.insert(quote_style + E->get().name + quote_style); + ScriptCodeCompletionOption option(quote_style + E->get().name + quote_style, ScriptCodeCompletionOption::KIND_SIGNAL); + options.insert(option.display, option); } Ref<Script> base_script = scr->get_base_script(); if (base_script.is_valid()) { @@ -2711,7 +2772,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path List<MethodInfo> signals; ClassDB::get_signal_list(class_name, &signals); for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { - options.insert(quote_style + E->get().name + quote_style); + ScriptCodeCompletionOption option(quote_style + E->get().name + quote_style, ScriptCodeCompletionOption::KIND_SIGNAL); + options.insert(option.display, option); } } break; default: { @@ -2748,18 +2810,21 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path 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) { - options.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } } } for (int i = 0; i < clss->subclasses.size(); i++) { if (clss->subclasses[i]->name != StringName()) { - options.insert(clss->subclasses[i]->name.operator String()); + ScriptCodeCompletionOption option(clss->subclasses[i]->name.operator String(), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } } clss = clss->owner; for (int i = 0; i < Variant::VARIANT_MAX; i++) { - options.insert(Variant::get_type_name((Variant::Type)i)); + ScriptCodeCompletionOption option(Variant::get_type_name((Variant::Type)i), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } } @@ -2773,18 +2838,21 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path if (Engine::get_singleton()->has_singleton(class_name)) { continue; } - options.insert(class_name); + ScriptCodeCompletionOption option(class_name, ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } // Named scripts List<StringName> named_scripts; ScriptServer::get_global_class_list(&named_scripts); for (List<StringName>::Element *E = named_scripts.front(); E; E = E->next()) { - options.insert(E->get().operator String()); + ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } if (parser.get_completion_identifier_is_function()) { - options.insert("void"); + ScriptCodeCompletionOption option("void", ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + options.insert(option.display, option); } r_forced = true; } break; @@ -2831,13 +2899,15 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path 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) { - options.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } } } for (int i = 0; i < base_type.class_type->subclasses.size(); i++) { if (base_type.class_type->subclasses[i]->name != StringName()) { - options.insert(base_type.class_type->subclasses[i]->name.operator String()); + ScriptCodeCompletionOption option(base_type.class_type->subclasses[i]->name.operator String(), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } } @@ -2855,7 +2925,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { Ref<Script> const_scr = E->value(); if (const_scr.is_valid()) { - options.insert(E->key().operator String()); + ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS); + options.insert(option.display, option); } } Ref<Script> base_script = scr->get_base_script(); @@ -2877,7 +2948,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path } break; } - for (Set<String>::Element *E = options.front(); E; E = E->next()) { + for (Map<String, ScriptCodeCompletionOption>::Element *E = options.front(); E; E = E->next()) { r_options->push_back(E->get()); } @@ -2886,7 +2957,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path #else -Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint) { +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) { return OK; } diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index d5e74c07c9..42f349ffc0 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -1784,20 +1784,9 @@ GDScriptFunction::~GDScriptFunction() { Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) { -#ifdef DEBUG_ENABLED - ERR_EXPLAIN("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(Variant()); -#else - return Variant(); -#endif - } - Variant arg; r_error.error = Variant::CallError::CALL_OK; - ERR_FAIL_COND_V(!function, Variant()); - if (p_argcount == 0) { r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = 1; @@ -1823,44 +1812,7 @@ Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_ar return Variant(); } - state.result = arg; - Variant ret = function->call(NULL, NULL, 0, r_error, &state); - - bool completed = true; - - // If the return value is a GDScriptFunctionState reference, - // then the function did yield again after resuming. - if (ret.is_ref()) { - GDScriptFunctionState *gdfs = Object::cast_to<GDScriptFunctionState>(ret); - if (gdfs && gdfs->function == function) { - completed = false; - gdfs->first_state = first_state.is_valid() ? first_state : Ref<GDScriptFunctionState>(this); - } - } - - function = NULL; //cleaned up; - state.result = Variant(); - - if (completed) { - if (first_state.is_valid()) { - first_state->emit_signal("completed", ret); - } else { - emit_signal("completed", ret); - } - } - -#ifdef DEBUG_ENABLED - if (ScriptDebugger::get_singleton()) - 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 - - return ret; + return resume(arg); } bool GDScriptFunctionState::is_valid(bool p_extended_check) const { diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp index 0736f3d010..f5f245b25f 100644 --- a/modules/gdscript/gdscript_functions.cpp +++ b/modules/gdscript/gdscript_functions.cpp @@ -58,6 +58,7 @@ const char *GDScriptFunctions::get_func_name(Function p_func) { "sqrt", "fmod", "fposmod", + "posmod", "floor", "ceil", "round", @@ -75,6 +76,7 @@ const char *GDScriptFunctions::get_func_name(Function p_func) { "step_decimals", "stepify", "lerp", + "lerp_angle", "inverse_lerp", "range_lerp", "smoothstep", @@ -243,6 +245,12 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ VALIDATE_ARG_NUM(1); r_ret = Math::fposmod((double)*p_args[0], (double)*p_args[1]); } break; + case MATH_POSMOD: { + VALIDATE_ARG_COUNT(2); + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + r_ret = Math::posmod((int)*p_args[0], (int)*p_args[1]); + } break; case MATH_FLOOR: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); @@ -376,6 +384,13 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } break; } } break; + case MATH_LERP_ANGLE: { + VALIDATE_ARG_COUNT(3); + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + r_ret = Math::lerp_angle((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]); + } break; case MATH_INVERSE_LERP: { VALIDATE_ARG_COUNT(3); VALIDATE_ARG_NUM(0); @@ -1456,6 +1471,7 @@ bool GDScriptFunctions::is_deterministic(Function p_func) { case MATH_SQRT: case MATH_FMOD: case MATH_FPOSMOD: + case MATH_POSMOD: case MATH_FLOOR: case MATH_CEIL: case MATH_ROUND: @@ -1568,15 +1584,20 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { return mi; } break; case MATH_FMOD: { - MethodInfo mi("fmod", PropertyInfo(Variant::REAL, "x"), PropertyInfo(Variant::REAL, "y")); + MethodInfo mi("fmod", PropertyInfo(Variant::REAL, "a"), PropertyInfo(Variant::REAL, "b")); mi.return_val.type = Variant::REAL; return mi; } break; case MATH_FPOSMOD: { - MethodInfo mi("fposmod", PropertyInfo(Variant::REAL, "x"), PropertyInfo(Variant::REAL, "y")); + MethodInfo mi("fposmod", PropertyInfo(Variant::REAL, "a"), PropertyInfo(Variant::REAL, "b")); mi.return_val.type = Variant::REAL; return mi; } break; + case MATH_POSMOD: { + MethodInfo mi("posmod", PropertyInfo(Variant::INT, "a"), PropertyInfo(Variant::INT, "b")); + mi.return_val.type = Variant::INT; + return mi; + } break; case MATH_FLOOR: { MethodInfo mi("floor", PropertyInfo(Variant::REAL, "s")); mi.return_val.type = Variant::REAL; @@ -1603,7 +1624,7 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { return mi; } break; case MATH_POW: { - MethodInfo mi("pow", PropertyInfo(Variant::REAL, "x"), PropertyInfo(Variant::REAL, "y")); + MethodInfo mi("pow", PropertyInfo(Variant::REAL, "base"), PropertyInfo(Variant::REAL, "exp")); mi.return_val.type = Variant::REAL; return mi; } break; @@ -1663,6 +1684,11 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; return mi; } break; + case MATH_LERP_ANGLE: { + MethodInfo mi("lerp_angle", PropertyInfo(Variant::REAL, "from"), PropertyInfo(Variant::REAL, "to"), PropertyInfo(Variant::REAL, "weight")); + mi.return_val.type = Variant::REAL; + return mi; + } break; case MATH_INVERSE_LERP: { MethodInfo mi("inverse_lerp", PropertyInfo(Variant::REAL, "from"), PropertyInfo(Variant::REAL, "to"), PropertyInfo(Variant::REAL, "weight")); mi.return_val.type = Variant::REAL; diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_functions.h index 6ad70f2eb4..8f7ba76d2c 100644 --- a/modules/gdscript/gdscript_functions.h +++ b/modules/gdscript/gdscript_functions.h @@ -49,6 +49,7 @@ public: MATH_SQRT, MATH_FMOD, MATH_FPOSMOD, + MATH_POSMOD, MATH_FLOOR, MATH_CEIL, MATH_ROUND, @@ -66,6 +67,7 @@ public: MATH_STEP_DECIMALS, MATH_STEPIFY, MATH_LERP, + MATH_LERP_ANGLE, MATH_INVERSE_LERP, MATH_RANGE_LERP, MATH_SMOOTHSTEP, diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 9ab86a5459..f006d50a83 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -125,7 +125,7 @@ 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 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(); @@ -149,7 +149,7 @@ bool GDScriptParser::_parse_arguments(Node *p_parent, Vector<Node *> &p_args, bo return false; } - Node *arg = _parse_expression(p_parent, p_static); + Node *arg = _parse_expression(p_parent, p_static, false, p_parsing_constant); if (!arg) { return false; } @@ -639,7 +639,7 @@ 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)) + if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant)) return NULL; expr = op; @@ -731,7 +731,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s completion_node = op; } if (!replaced) { - if (!_parse_arguments(op, op->arguments, p_static, true)) + if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant)) return NULL; expr = op; } @@ -826,11 +826,12 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } // Check parents for the constant - if (!bfn && cln->extends_file != StringName()) { - Ref<GDScript> parent = ResourceLoader::load(cln->extends_file); - if (parent.is_valid() && parent->is_valid()) { + if (!bfn) { + // Using current_class instead of cln here, since cln is const* + _determine_inheritance(current_class, false); + if (cln->base_type.has_type && cln->base_type.kind == DataType::GDSCRIPT && cln->base_type.script_type->is_valid()) { Map<StringName, Variant> parent_constants; - parent->get_constants(&parent_constants); + current_class->base_type.script_type->get_constants(&parent_constants); if (parent_constants.has(identifier)) { ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = parent_constants[identifier]; @@ -1112,7 +1113,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } } else { tokenizer->advance(); - if (!_parse_arguments(op, op->arguments, p_static)) { + if (!_parse_arguments(op, op->arguments, p_static, false, p_parsing_constant)) { return NULL; } } @@ -1164,22 +1165,14 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s tokenizer->advance(); IdentifierNode *id = alloc_node<IdentifierNode>(); - if (tokenizer->get_token() == GDScriptTokenizer::TK_BUILT_IN_FUNC) { - //small hack so built in funcs don't obfuscate methods - - id->name = GDScriptFunctions::get_func_name(tokenizer->get_token_built_in_func()); - tokenizer->advance(); - - } else { - StringName identifier; - if (_get_completable_identifier(COMPLETION_METHOD, identifier)) { - completion_node = op; - //indexing stuff - } - - id->name = identifier; + StringName identifier; + if (_get_completable_identifier(COMPLETION_METHOD, identifier)) { + completion_node = op; + //indexing stuff } + id->name = identifier; + op->arguments.push_back(expr); // call what op->arguments.push_back(id); // call func //get arguments @@ -1188,7 +1181,7 @@ 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)) + if (!_parse_arguments(op, op->arguments, p_static, true, p_parsing_constant)) return NULL; expr = op; @@ -1773,8 +1766,6 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to cn->value = v; cn->datatype = _type_from_variant(v); return cn; - - } else if (op->arguments[0]->type == Node::TYPE_BUILT_IN_FUNCTION && last_not_constant == 0) { } return op; //don't reduce yet @@ -2218,6 +2209,8 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran p_block->has_return = true; + bool catch_all_appeared = false; + while (true) { while (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE && _parse_newline()) @@ -2228,7 +2221,7 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran return; if (indent_level > tab_level.back()->get()) { - return; // go back a level + break; // go back a level } if (pending_newline != -1) { @@ -2243,12 +2236,20 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran branch->patterns.push_back(_parse_pattern(p_static)); if (!branch->patterns[0]) { - return; + break; } bool has_binding = branch->patterns[0]->pt_type == PatternNode::PT_BIND; bool catch_all = has_binding || branch->patterns[0]->pt_type == PatternNode::PT_WILDCARD; +#ifdef DEBUG_ENABLED + // Branches after a wildcard or binding are unreachable + if (catch_all_appeared && !current_function->has_unreachable_code) { + _add_warning(GDScriptWarning::UNREACHABLE_CODE, -1, current_function->name.operator String()); + current_function->has_unreachable_code = true; + } +#endif + while (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { tokenizer->advance(); branch->patterns.push_back(_parse_pattern(p_static)); @@ -2266,6 +2267,8 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran catch_all = catch_all || pt == PatternNode::PT_WILDCARD; } + catch_all_appeared = catch_all_appeared || catch_all; + if (!_enter_indent_block()) { _set_error("Expected block in pattern branch"); return; @@ -2281,6 +2284,11 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran p_branches.push_back(branch); } + + // Even if all branches return, there is possibility of default fallthrough + if (!catch_all_appeared) { + p_block->has_return = false; + } } void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_match, Node *&p_resulting_node, Map<StringName, Node *> &p_bindings) { @@ -5084,6 +5092,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { tokenizer->advance(); + } else if (tokenizer->is_token_literal(0, true)) { + _set_error("Unexpected identifier"); + return; } if (enum_name != "") { @@ -5158,9 +5169,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } -void GDScriptParser::_determine_inheritance(ClassNode *p_class) { +void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive) { - if (p_class->extends_used) { + if (p_class->base_type.has_type) { + // Already determined + } else if (p_class->extends_used) { //do inheritance String path = p_class->extends_file; @@ -5355,9 +5368,11 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class) { p_class->base_type.native_type = "Reference"; } - // Recursively determine subclasses - for (int i = 0; i < p_class->subclasses.size(); i++) { - _determine_inheritance(p_class->subclasses[i]); + if (p_recursive) { + // Recursively determine subclasses + for (int i = 0; i < p_class->subclasses.size(); i++) { + _determine_inheritance(p_class->subclasses[i], p_recursive); + } } } diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 5e4de11357..62d7bdb393 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -582,7 +582,7 @@ private: #endif // DEBUG_ENABLED bool _recover_from_completion(); - bool _parse_arguments(Node *p_parent, Vector<Node *> &p_args, bool p_static, bool p_can_codecomplete = false); + 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 _parse_newline(); Node *_parse_expression(Node *p_parent, bool p_static, bool p_allow_assign = false, bool p_parsing_constant = false); @@ -599,7 +599,7 @@ private: void _parse_class(ClassNode *p_class); bool _end_statement(); - void _determine_inheritance(ClassNode *p_class); + void _determine_inheritance(ClassNode *p_class, bool p_recursive = true); bool _parse_type(DataType &r_type, bool p_can_be_void = false); DataType _resolve_type(const DataType &p_source, int p_line); DataType _type_from_variant(const Variant &p_value) const; |