diff options
Diffstat (limited to 'modules/gdscript')
-rw-r--r-- | modules/gdscript/doc_classes/@GDScript.xml | 27 | ||||
-rw-r--r-- | modules/gdscript/editor/gdscript_highlighter.cpp | 4 | ||||
-rw-r--r-- | modules/gdscript/gdscript_analyzer.cpp | 82 | ||||
-rw-r--r-- | modules/gdscript/gdscript_analyzer.h | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 4 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.h | 1 | ||||
-rw-r--r-- | modules/gdscript/register_types.cpp | 12 |
7 files changed, 112 insertions, 20 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index c86b974f47..9e40a69712 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -112,7 +112,7 @@ </argument> <description> Returns the arc tangent of [code]s[/code] in radians. Use it to get the angle from an angle's tangent in trigonometry: [code]atan(tan(angle)) == angle[/code]. - The method cannot know in which quadrant the angle should fall. See [method atan2] if you have both [code]y[code] and [code]x[/code]. + The method cannot know in which quadrant the angle should fall. See [method atan2] if you have both [code]y[/code] and [code]x[/code]. [codeblock] a = atan(0.5) # a is 0.463648 [/codeblock] @@ -735,16 +735,17 @@ <argument index="0" name="json" type="String"> </argument> <description> - Parse JSON text to a Variant (use [method typeof] to check if it is what you expect). - Be aware that the JSON specification does not define integer or float types, but only a number type. Therefore, parsing a JSON text will convert all numerical values to [float] types. - Note that JSON objects do not preserve key order like Godot dictionaries, thus you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements: + Parse JSON text to a Variant. (Use [method typeof] to check if the Variant's type is what you expect.) + [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, parsing a JSON text will convert all numerical values to [float] types. + [b]Note:[/b] JSON objects do not preserve key order like Godot dictionaries, thus, you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements: [codeblock] - p = parse_json('["a", "b", "c"]') - if typeof(p) == TYPE_ARRAY: - print(p[0]) # Prints a + var p = JSON.parse('["hello", "world", "!"]') + if typeof(p.result) == TYPE_ARRAY: + print(p.result[0]) # Prints "hello" else: - print("unexpected results") + push_error("Unexpected results.") [/codeblock] + See also [JSON] for an alternative way to parse JSON text. </description> </method> <method name="polar2cartesian"> @@ -1220,12 +1221,16 @@ <argument index="0" name="var" type="Variant"> </argument> <description> - Converts a Variant [code]var[/code] to JSON text and return the result. Useful for serializing data to store or send over the network. + Converts a [Variant] [code]var[/code] to JSON text and return the result. Useful for serializing data to store or send over the network. [codeblock] + # Both numbers below are integers. a = { "a": 1, "b": 2 } b = to_json(a) print(b) # {"a":1, "b":2} + # Both numbers above are floats, even if they display without any decimal places. [/codeblock] + [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, converting a [Variant] to JSON text will convert all numerical values to [float] types. + See also [JSON] for an alternative way to convert a [Variant] to JSON text. </description> </method> <method name="type_exists"> @@ -1268,9 +1273,9 @@ j = to_json([1, 2, 3]) v = validate_json(j) if not v: - print("valid") + print("Valid JSON.") else: - prints("invalid", v) + push_error("Invalid JSON: " + v) [/codeblock] </description> </method> diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index aba3e07134..ae1f2893f1 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -82,6 +82,10 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line) const String &str = text_edit->get_line(p_line); const int line_length = str.length(); Color prev_color; + + if (in_region != -1 && str.length() == 0) { + color_region_cache[p_line] = in_region; + } for (int j = 0; j < str.length(); j++) { Dictionary highlighter_info; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 4098425518..1e72216ad2 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -71,6 +71,10 @@ static StringName get_real_class_name(const StringName &p_source) { return p_source; } +void GDScriptAnalyzer::cleanup() { + underscore_map.clear(); +} + static GDScriptParser::DataType make_callable_type(const MethodInfo &p_info) { GDScriptParser::DataType type; type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; @@ -494,7 +498,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas if (member.variable->initializer != nullptr) { if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true)) { - push_error(vformat(R"(Value of type "%s" cannot be assigned to variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer); + push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer); } else if (datatype.builtin_type == Variant::INT && member.variable->initializer->get_datatype().builtin_type == Variant::FLOAT) { #ifdef DEBUG_ENABLED parser->push_warning(member.variable->initializer, GDScriptWarning::NARROWING_CONVERSION); @@ -989,7 +993,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable if (p_variable->initializer != nullptr) { if (!is_type_compatible(type, p_variable->initializer->get_datatype(), true)) { - push_error(vformat(R"(Value of type "%s" cannot be assigned to variable of type "%s".)", p_variable->initializer->get_datatype().to_string(), type.to_string()), p_variable->initializer); + push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", p_variable->initializer->get_datatype().to_string(), type.to_string()), p_variable->initializer); #ifdef DEBUG_ENABLED } else if (type.builtin_type == Variant::INT && p_variable->initializer->get_datatype().builtin_type == Variant::FLOAT) { parser->push_warning(p_variable->initializer, GDScriptWarning::NARROWING_CONVERSION); @@ -1369,11 +1373,61 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig push_error("Cannot assign a new value to a constant.", p_assignment->assignee); } - if (!is_type_compatible(p_assignment->assignee->get_datatype(), p_assignment->assigned_value->get_datatype(), true)) { - if (p_assignment->assignee->get_datatype().is_hard_type()) { - push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", p_assignment->assigned_value->get_datatype().to_string(), p_assignment->assignee->get_datatype().to_string()), p_assignment->assigned_value); + Variant::Operator vop = Variant::Operator::OP_EQUAL; + switch (p_assignment->operation) { + case GDScriptParser::AssignmentNode::OP_NONE: + vop = Variant::Operator::OP_EQUAL; + break; + case GDScriptParser::AssignmentNode::OP_ADDITION: + vop = Variant::Operator::OP_ADD; + break; + case GDScriptParser::AssignmentNode::OP_SUBTRACTION: + vop = Variant::Operator::OP_SUBTRACT; + break; + case GDScriptParser::AssignmentNode::OP_MULTIPLICATION: + vop = Variant::Operator::OP_MULTIPLY; + break; + case GDScriptParser::AssignmentNode::OP_DIVISION: + vop = Variant::Operator::OP_DIVIDE; + break; + case GDScriptParser::AssignmentNode::OP_MODULO: + vop = Variant::Operator::OP_MODULE; + break; + case GDScriptParser::AssignmentNode::OP_BIT_SHIFT_LEFT: + vop = Variant::Operator::OP_SHIFT_LEFT; + break; + case GDScriptParser::AssignmentNode::OP_BIT_SHIFT_RIGHT: + vop = Variant::Operator::OP_SHIFT_RIGHT; + break; + case GDScriptParser::AssignmentNode::OP_BIT_AND: + vop = Variant::Operator::OP_BIT_AND; + break; + case GDScriptParser::AssignmentNode::OP_BIT_OR: + vop = Variant::Operator::OP_BIT_OR; + break; + case GDScriptParser::AssignmentNode::OP_BIT_XOR: + vop = Variant::Operator::OP_BIT_XOR; + break; + } + + if (!p_assignment->assignee->get_datatype().is_variant() && !p_assignment->assigned_value->get_datatype().is_variant()) { + bool compatible = true; + GDScriptParser::DataType op_type = p_assignment->assigned_value->get_datatype(); + if (vop != Variant::OP_EQUAL) { + op_type = get_operation_type(vop, p_assignment->assignee->get_datatype(), p_assignment->assigned_value->get_datatype(), compatible); + } + + if (compatible) { + compatible = is_type_compatible(p_assignment->assignee->get_datatype(), op_type, true); + if (!compatible) { + if (p_assignment->assignee->get_datatype().is_hard_type()) { + push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", p_assignment->assigned_value->get_datatype().to_string(), p_assignment->assignee->get_datatype().to_string()), p_assignment->assigned_value); + } else { + // TODO: Warning in this case. + } + } } else { - // TODO: Warning in this case. + push_error(vformat(R"(Invalid operands "%s" and "%s" for assignment operator.)", p_assignment->assignee->get_datatype().to_string(), p_assignment->assigned_value->get_datatype().to_string()), p_assignment); } } @@ -1488,7 +1542,19 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o if (p_binary_op->left_operand->is_constant && p_binary_op->right_operand->is_constant) { p_binary_op->is_constant = true; if (p_binary_op->variant_op < Variant::OP_MAX) { - p_binary_op->reduced_value = Variant::evaluate(p_binary_op->variant_op, p_binary_op->left_operand->reduced_value, p_binary_op->right_operand->reduced_value); + bool valid = false; + Variant::evaluate(p_binary_op->variant_op, p_binary_op->left_operand->reduced_value, p_binary_op->right_operand->reduced_value, p_binary_op->reduced_value, valid); + if (!valid) { + if (p_binary_op->reduced_value.get_type() == Variant::STRING) { + push_error(vformat(R"(%s in operator %s.)", p_binary_op->reduced_value, Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op); + } else { + push_error(vformat(R"(Invalid operands to operator %s, %s and %s.".)", + Variant::get_operator_name(p_binary_op->variant_op), + Variant::get_type_name(p_binary_op->left_operand->reduced_value.get_type()), + Variant::get_type_name(p_binary_op->right_operand->reduced_value.get_type())), + p_binary_op); + } + } } else { if (p_binary_op->operation == GDScriptParser::BinaryOpNode::OP_TYPE_TEST) { GDScriptParser::DataType test_type = right_type; @@ -2019,7 +2085,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod GDScriptParser::ClassNode *outer = base_class->outer; while (outer != nullptr) { if (outer->has_member(name)) { - const GDScriptParser::ClassNode::Member &member = base_class->get_member(name); + const GDScriptParser::ClassNode::Member &member = outer->get_member(name); if (member.type == GDScriptParser::ClassNode::Member::CONSTANT) { // TODO: Make sure loops won't cause problem. And make special error message for those. // For out-of-order resolution: diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index 85183d3272..06d3530cb6 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -113,6 +113,8 @@ public: Error analyze(); GDScriptAnalyzer(GDScriptParser *p_parser); + + static void cleanup(); }; #endif // GDSCRIPT_ANALYZER_H diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index af07457750..1f3e1c1e40 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -94,6 +94,10 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) { return Variant::VARIANT_MAX; } +void GDScriptParser::cleanup() { + builtin_types.clear(); +} + GDScriptFunctions::Function GDScriptParser::get_builtin_function(const StringName &p_name) { for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) { if (p_name == GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index a741ae0cc7..c9ab3d4e12 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -1335,6 +1335,7 @@ public: void print_tree(const GDScriptParser &p_parser); }; #endif // DEBUG_ENABLED + static void cleanup(); }; #endif // GDSCRIPT_PARSER_H diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 5c1d2f6f1b..c554cbac05 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -35,6 +35,7 @@ #include "core/os/dir_access.h" #include "core/os/file_access.h" #include "gdscript.h" +#include "gdscript_analyzer.h" #include "gdscript_cache.h" #include "gdscript_tokenizer.h" @@ -57,6 +58,8 @@ GDScriptCache *gdscript_cache = nullptr; #include "language_server/gdscript_language_server.h" #endif // !GDSCRIPT_NO_LSP +Ref<GDScriptEditorTranslationParserPlugin> gdscript_translation_parser_plugin; + class EditorExportGDScript : public EditorExportPlugin { GDCLASS(EditorExportGDScript, EditorExportPlugin); @@ -120,7 +123,6 @@ void register_gdscript_types() { #ifdef TOOLS_ENABLED EditorNode::add_init_callback(_editor_init); - Ref<GDScriptEditorTranslationParserPlugin> gdscript_translation_parser_plugin; gdscript_translation_parser_plugin.instance(); EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD); #endif // TOOLS_ENABLED @@ -142,4 +144,12 @@ void unregister_gdscript_types() { ResourceSaver::remove_resource_format_saver(resource_saver_gd); resource_saver_gd.unref(); + +#ifdef TOOLS_ENABLED + EditorTranslationParser::get_singleton()->remove_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD); + gdscript_translation_parser_plugin.unref(); +#endif // TOOLS_ENABLED + + GDScriptParser::cleanup(); + GDScriptAnalyzer::cleanup(); } |