diff options
Diffstat (limited to 'modules/gdscript')
16 files changed, 81 insertions, 37 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 5fe47d69df..21365da7cc 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -4,8 +4,8 @@ Built-in GDScript constants, functions, and annotations. </brief_description> <description> - A list of GDScript-specific utility functions and annotations accessible from any script. - For the list of the global functions and constants see [@GlobalScope]. + A list of utility functions and annotations accessible from any script written in GDScript. + For the list of global functions and constants that can be accessed in any scripting language, see [@GlobalScope]. </description> <tutorials> <link title="GDScript exports">$DOCS_URL/tutorials/scripting/gdscript/gdscript_exports.html</link> diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp index 32ef429b0d..758887a723 100644 --- a/modules/gdscript/editor/gdscript_docgen.cpp +++ b/modules/gdscript/editor/gdscript_docgen.cpp @@ -217,7 +217,7 @@ String GDScriptDocGen::_docvalue_from_variant(const Variant &p_variant, int p_re List<Variant> keys; dict.get_key_list(&keys); - keys.sort(); + keys.sort_custom<StringLikeVariantOrder>(); for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { if (E->prev()) { diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index d765cfa1ea..0b12f2ff76 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -701,7 +701,9 @@ void GDScriptSyntaxHighlighter::_update_cache() { List<StringName> types; ClassDB::get_class_list(&types); for (const StringName &E : types) { - class_names[E] = types_color; + if (ClassDB::is_class_exposed(E)) { + class_names[E] = types_color; + } } /* User types. */ diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 18f2ccc455..64287cce99 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -76,9 +76,16 @@ bool GDScriptNativeClass::_get(const StringName &p_name, Variant &r_ret) const { if (ok) { r_ret = v; return true; - } else { - return false; } + + MethodBind *method = ClassDB::get_method(name, p_name); + if (method && method->is_static()) { + // Native static method. + r_ret = Callable(this, p_name); + return true; + } + + return false; } void GDScriptNativeClass::_bind_methods() { @@ -2546,11 +2553,11 @@ void GDScriptLanguage::reload_all_scripts() { } } } -#endif +#endif // TOOLS_ENABLED } reload_scripts(scripts, true); -#endif +#endif // DEBUG_ENABLED } void GDScriptLanguage::reload_scripts(const Array &p_scripts, bool p_soft_reload) { @@ -2620,7 +2627,7 @@ void GDScriptLanguage::reload_scripts(const Array &p_scripts, bool p_soft_reload } } -#endif +#endif // TOOLS_ENABLED for (const KeyValue<ObjectID, List<Pair<StringName, Variant>>> &F : scr->pending_reload_state) { map[F.key] = F.value; //pending to reload, use this one instead @@ -2688,7 +2695,7 @@ void GDScriptLanguage::reload_scripts(const Array &p_scripts, bool p_soft_reload //if instance states were saved, set them! } -#endif +#endif // DEBUG_ENABLED } void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) { diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 4a3a3a4b61..93d4a512a9 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -940,8 +940,8 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, Finally finally([&]() { ensure_cached_external_parser_for_class(member.get_datatype().class_type, p_class, "Trying to resolve datatype of class member", p_source); GDScriptParser::DataType member_type = member.get_datatype(); - if (member_type.has_container_element_type(0)) { - ensure_cached_external_parser_for_class(member_type.get_container_element_type(0).class_type, p_class, "Trying to resolve datatype of class member", p_source); + for (int i = 0; i < member_type.get_container_element_type_count(); ++i) { + ensure_cached_external_parser_for_class(member_type.get_container_element_type(i).class_type, p_class, "Trying to resolve datatype of class member", p_source); } }); @@ -3816,6 +3816,12 @@ GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const Str } Ref<GDScriptParserRef> GDScriptAnalyzer::ensure_cached_external_parser_for_class(const GDScriptParser::ClassNode *p_class, const GDScriptParser::ClassNode *p_from_class, const char *p_context, const GDScriptParser::Node *p_source) { + // Delicate piece of code that intentionally doesn't use the GDScript cache or `get_depended_parser_for`. + // Search dependencies for the parser that owns `p_class` and make a cache entry for it. + // Required for how we store pointers to classes owned by other parser trees and need to call `resolve_class_member` and such on the same parser tree. + // Since https://github.com/godotengine/godot/pull/94871 there can technically be multiple parsers for the same script in the same parser tree. + // Even if unlikely, getting the wrong parser could lead to strange undefined behavior without errors. + if (p_class == nullptr) { return nullptr; } @@ -3832,8 +3838,6 @@ Ref<GDScriptParserRef> GDScriptAnalyzer::ensure_cached_external_parser_for_class p_from_class = parser->head; } - String script_path = p_class->get_datatype().script_path; - Ref<GDScriptParserRef> parser_ref; for (const GDScriptParser::ClassNode *look_class = p_from_class; look_class != nullptr; look_class = look_class->base_type.class_type) { if (parser->has_class(look_class)) { @@ -5867,7 +5871,7 @@ void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_identifier parent = ClassDB::get_parent_class(parent); } } -#endif +#endif // DEBUG_ENABLED GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, bool &r_valid, const GDScriptParser::Node *p_source) { // Unary version. diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 3de1decc18..b59c071ae2 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -3534,13 +3534,13 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c return OK; } -#else +#else // !TOOLS_ENABLED Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) { return OK; } -#endif +#endif // TOOLS_ENABLED //////// END COMPLETION ////////// @@ -4125,4 +4125,4 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co return ERR_CANT_RESOLVE; } -#endif +#endif // TOOLS_ENABLED diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 111a39d730..ee8d53639c 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -244,7 +244,7 @@ void GDScriptParser::apply_pending_warnings() { pending_warnings.clear(); } -#endif +#endif // DEBUG_ENABLED void GDScriptParser::override_completion_context(const Node *p_for_node, CompletionType p_type, Node *p_node, int p_argument) { if (!for_completion) { @@ -1624,15 +1624,17 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali valid = false; } - annotation->info = &valid_annotations[annotation->name]; + if (valid) { + annotation->info = &valid_annotations[annotation->name]; - if (!annotation->applies_to(p_valid_targets)) { - if (annotation->applies_to(AnnotationInfo::SCRIPT)) { - push_error(vformat(R"(Annotation "%s" must be at the top of the script, before "extends" and "class_name".)", annotation->name)); - } else { - push_error(vformat(R"(Annotation "%s" is not allowed in this level.)", annotation->name)); + if (!annotation->applies_to(p_valid_targets)) { + if (annotation->applies_to(AnnotationInfo::SCRIPT)) { + push_error(vformat(R"(Annotation "%s" must be at the top of the script, before "extends" and "class_name".)", annotation->name)); + } else { + push_error(vformat(R"(Annotation "%s" is not allowed in this level.)", annotation->name)); + } + valid = false; } - valid = false; } if (check(GDScriptTokenizer::Token::PARENTHESIS_OPEN)) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 7f64ae902b..2ec33831a2 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -165,6 +165,10 @@ public: container_element_types.write[p_index] = DataType(p_type); } + _FORCE_INLINE_ int get_container_element_type_count() const { + return container_element_types.size(); + } + _FORCE_INLINE_ DataType get_container_element_type(int p_index) const { ERR_FAIL_INDEX_V(p_index, container_element_types.size(), get_variant_type()); return container_element_types[p_index]; diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index 59dd983ed2..7dc586186b 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -74,13 +74,13 @@ return; \ } -#else +#else // !DEBUG_ENABLED #define VALIDATE_ARG_COUNT(m_count) #define VALIDATE_ARG_INT(m_arg) #define VALIDATE_ARG_NUM(m_arg) -#endif +#endif // DEBUG_ENABLED struct GDScriptUtilityFunctionsDefinitions { #ifndef DISABLE_DEPRECATED diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index d8139d913a..26c5cfe23c 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -397,32 +397,36 @@ void (*type_init_function_table[])(Variant *) = { #define OPCODES_OUT \ OPSOUT: #define OPCODE_SWITCH(m_test) goto *switch_table_ops[m_test]; + #ifdef DEBUG_ENABLED #define DISPATCH_OPCODE \ last_opcode = _code_ptr[ip]; \ goto *switch_table_ops[last_opcode] -#else +#else // !DEBUG_ENABLED #define DISPATCH_OPCODE goto *switch_table_ops[_code_ptr[ip]] -#endif +#endif // DEBUG_ENABLED + #define OPCODE_BREAK goto OPSEXIT #define OPCODE_OUT goto OPSOUT -#else +#else // !(defined(__GNUC__) || defined(__clang__)) #define OPCODES_TABLE #define OPCODE(m_op) case m_op: #define OPCODE_WHILE(m_test) while (m_test) #define OPCODES_END #define OPCODES_OUT #define DISPATCH_OPCODE continue + #ifdef _MSC_VER #define OPCODE_SWITCH(m_test) \ __assume(m_test <= OPCODE_END); \ switch (m_test) -#else +#else // !_MSC_VER #define OPCODE_SWITCH(m_test) switch (m_test) -#endif +#endif // _MSC_VER + #define OPCODE_BREAK break #define OPCODE_OUT break -#endif +#endif // defined(__GNUC__) || defined(__clang__) // Helpers for VariantInternal methods in macros. #define OP_GET_BOOL get_bool @@ -663,7 +667,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_BREAK; \ } -#else +#else // !DEBUG_ENABLED #define GD_ERR_BREAK(m_cond) #define CHECK_SPACE(m_space) @@ -676,7 +680,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_BREAK; \ } -#endif +#endif // DEBUG_ENABLED #define LOAD_INSTRUCTION_ARGS \ int instr_arg_count = _code_ptr[ip + 1]; \ @@ -1965,7 +1969,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a err_text = _get_call_error("function '" + methodstr + (is_callable ? "" : "' in base '" + basestr) + "'", (const Variant **)argptrs, temp_ret, err); OPCODE_BREAK; } -#endif +#endif // DEBUG_ENABLED ip += 3; } diff --git a/modules/gdscript/tests/scripts/parser/errors/annotation_inapplicable.gd b/modules/gdscript/tests/scripts/parser/errors/annotation_inapplicable.gd new file mode 100644 index 0000000000..cfacb6a010 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/annotation_inapplicable.gd @@ -0,0 +1,3 @@ +@export +func test(): + pass diff --git a/modules/gdscript/tests/scripts/parser/errors/annotation_inapplicable.out b/modules/gdscript/tests/scripts/parser/errors/annotation_inapplicable.out new file mode 100644 index 0000000000..ed677cd39a --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/annotation_inapplicable.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Annotation "@export" cannot be applied to a function. diff --git a/modules/gdscript/tests/scripts/parser/errors/annotation_unrecognized.gd b/modules/gdscript/tests/scripts/parser/errors/annotation_unrecognized.gd new file mode 100644 index 0000000000..a6b171a428 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/annotation_unrecognized.gd @@ -0,0 +1,3 @@ +@hello_world +func test(): + pass diff --git a/modules/gdscript/tests/scripts/parser/errors/annotation_unrecognized.out b/modules/gdscript/tests/scripts/parser/errors/annotation_unrecognized.out new file mode 100644 index 0000000000..540e66f15b --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/annotation_unrecognized.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Unrecognized annotation: "@hello_world". diff --git a/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.gd b/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.gd new file mode 100644 index 0000000000..63d5935d1e --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.gd @@ -0,0 +1,8 @@ +func get_parse_string(t: Variant): + return t.parse_string + +func test(): + var a: Callable = JSON.parse_string + var b: Callable = get_parse_string(JSON) + prints(a.call("{\"test\": \"a\"}"), a.is_valid()) + prints(b.call("{\"test\": \"b\"}"), b.is_valid()) diff --git a/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.out b/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.out new file mode 100644 index 0000000000..a2cb4b9a07 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.out @@ -0,0 +1,3 @@ +GDTEST_OK +{ "test": "a" } false +{ "test": "b" } false |