summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp4
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp70
-rw-r--r--modules/gdscript/gdscript_analyzer.h2
-rw-r--r--modules/gdscript/gdscript_editor.cpp11
-rw-r--r--modules/gdscript/gdscript_parser.cpp14
-rw-r--r--modules/gdscript/gdscript_parser.h9
-rw-r--r--modules/gdscript/register_types.cpp4
7 files changed, 83 insertions, 31 deletions
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 531666bec5..616fb1485e 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;
@@ -872,7 +876,8 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
// Use int, Vector2, Vector3 instead, which also can be used as range iterators.
if (p_for->list && p_for->list->type == GDScriptParser::Node::CALL) {
GDScriptParser::CallNode *call = static_cast<GDScriptParser::CallNode *>(p_for->list);
- if (call->callee->type == GDScriptParser::Node::IDENTIFIER) {
+ GDScriptParser::Node::Type callee_type = call->get_callee_type();
+ if (callee_type == GDScriptParser::Node::IDENTIFIER) {
GDScriptParser::IdentifierNode *callee = static_cast<GDScriptParser::IdentifierNode *>(call->callee);
if (callee->name == "range") {
list_resolved = true;
@@ -1406,23 +1411,25 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
break;
}
- 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 (!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.
+ 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 {
+ 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);
}
- } else {
- 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);
}
if (p_assignment->assignee->get_datatype().has_no_type() || p_assignment->assigned_value->get_datatype().is_variant()) {
@@ -1536,7 +1543,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;
@@ -1608,9 +1627,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
all_is_constant = all_is_constant && p_call->arguments[i]->is_constant;
}
+ GDScriptParser::Node::Type callee_type = p_call->get_callee_type();
GDScriptParser::DataType call_type;
- if (!p_call->is_super && p_call->callee->type == GDScriptParser::Node::IDENTIFIER) {
+ if (!p_call->is_super && callee_type == GDScriptParser::Node::IDENTIFIER) {
// Call to name directly.
StringName function_name = p_call->function_name;
Variant::Type builtin_type = GDScriptParser::get_builtin_type(function_name);
@@ -1785,10 +1805,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
if (p_call->is_super) {
base_type = parser->current_class->base_type;
is_self = true;
- } else if (p_call->callee->type == GDScriptParser::Node::IDENTIFIER) {
+ } else if (callee_type == GDScriptParser::Node::IDENTIFIER) {
base_type = parser->current_class->get_datatype();
is_self = true;
- } else if (p_call->callee->type == GDScriptParser::Node::SUBSCRIPT) {
+ } else if (callee_type == GDScriptParser::Node::SUBSCRIPT) {
GDScriptParser::SubscriptNode *subscript = static_cast<GDScriptParser::SubscriptNode *>(p_call->callee);
if (!subscript->is_attribute) {
// Invalid call. Error already sent in parser.
@@ -1825,9 +1845,9 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
} else {
// Check if the name exists as something else.
bool found = false;
- if (!p_call->is_super) {
+ if (!p_call->is_super && callee_type != GDScriptParser::Node::NONE) {
GDScriptParser::IdentifierNode *callee_id;
- if (p_call->callee->type == GDScriptParser::Node::IDENTIFIER) {
+ if (callee_type == GDScriptParser::Node::IDENTIFIER) {
callee_id = static_cast<GDScriptParser::IdentifierNode *>(p_call->callee);
} else {
// Can only be attribute.
@@ -1835,13 +1855,13 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
}
if (callee_id) {
reduce_identifier_from_base(callee_id, &base_type);
- GDScriptParser::DataType callee_type = callee_id->get_datatype();
- if (callee_type.is_set() && !callee_type.is_variant()) {
+ GDScriptParser::DataType callee_datatype = callee_id->get_datatype();
+ if (callee_datatype.is_set() && !callee_datatype.is_variant()) {
found = true;
- if (callee_type.builtin_type == Variant::CALLABLE) {
+ if (callee_datatype.builtin_type == Variant::CALLABLE) {
push_error(vformat(R"*(Name "%s" is a Callable. You can call it with "%s.call()" instead.)*", p_call->function_name, p_call->function_name), p_call->callee);
} else {
- push_error(vformat(R"*(Name "%s" called as a function but is a "%s".)*", p_call->function_name, callee_type.to_string()), p_call->callee);
+ push_error(vformat(R"*(Name "%s" called as a function but is a "%s".)*", p_call->function_name, callee_datatype.to_string()), p_call->callee);
}
#ifdef DEBUG_ENABLED
} else if (!is_self) {
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_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 239015060e..1fdce6eeeb 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1259,8 +1259,10 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
GDScriptParser::CompletionContext c = p_context;
c.current_line = call->start_line;
+ GDScriptParser::Node::Type callee_type = call->get_callee_type();
+
GDScriptCompletionIdentifier base;
- if (call->callee->type == GDScriptParser::Node::IDENTIFIER || call->is_super) {
+ if (callee_type == GDScriptParser::Node::IDENTIFIER || call->is_super) {
// Simple call, so base is 'self'.
if (p_context.current_class) {
base.type.kind = GDScriptParser::DataType::CLASS;
@@ -1271,7 +1273,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
} else {
break;
}
- } else if (call->callee->type == GDScriptParser::Node::SUBSCRIPT && static_cast<const GDScriptParser::SubscriptNode *>(call->callee)->is_attribute) {
+ } else if (callee_type == GDScriptParser::Node::SUBSCRIPT && static_cast<const GDScriptParser::SubscriptNode *>(call->callee)->is_attribute) {
if (!_guess_expression_type(c, static_cast<const GDScriptParser::SubscriptNode *>(call->callee)->base, base)) {
found = false;
break;
@@ -2290,6 +2292,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
GDScriptParser::DataType base_type;
bool _static = false;
const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_call);
+ GDScriptParser::Node::Type callee_type = GDScriptParser::Node::NONE;
GDScriptCompletionIdentifier connect_base;
@@ -2319,14 +2322,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
i++;
}
return;
- } else if (call->is_super || call->callee->type == GDScriptParser::Node::IDENTIFIER) {
+ } else if (call->is_super || callee_type == GDScriptParser::Node::IDENTIFIER) {
base = p_context.base;
if (p_context.current_class) {
base_type = p_context.current_class->get_datatype();
_static = !p_context.current_function || p_context.current_function->is_static;
}
- } else if (call->callee->type == GDScriptParser::Node::SUBSCRIPT) {
+ } else if (callee_type == GDScriptParser::Node::SUBSCRIPT) {
const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee);
if (subscript->is_attribute) {
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index af07457750..d09d9e2998 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))) {
@@ -2328,7 +2332,11 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
GDScriptParser::ExpressionNode *GDScriptParser::parse_grouping(ExpressionNode *p_previous_operand, bool p_can_assign) {
ExpressionNode *grouped = parse_expression(false);
pop_multiline();
- consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected closing ")" after grouping expression.)*");
+ if (grouped == nullptr) {
+ push_error(R"(Expected grouping expression.)");
+ } else {
+ consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected closing ")" after grouping expression.)*");
+ }
return grouped;
}
@@ -2419,7 +2427,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre
} else {
call->callee = p_previous_operand;
- if (call->callee->type == Node::IDENTIFIER) {
+ if (call->callee == nullptr) {
+ push_error(R"*(Cannot call on an expression. Use ".call()" if it's a Callable.)*");
+ } else if (call->callee->type == Node::IDENTIFIER) {
call->function_name = static_cast<IdentifierNode *>(call->callee)->name;
make_completion_context(COMPLETION_METHOD, call->callee);
} else if (call->callee->type == Node::SUBSCRIPT) {
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index a741ae0cc7..edfe330c0c 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -383,6 +383,14 @@ public:
CallNode() {
type = CALL;
}
+
+ Type get_callee_type() const {
+ if (callee == nullptr) {
+ return Type::NONE;
+ } else {
+ return callee->type;
+ }
+ }
};
struct CastNode : public ExpressionNode {
@@ -1335,6 +1343,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 23c7f97b5a..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"
@@ -148,4 +149,7 @@ void unregister_gdscript_types() {
EditorTranslationParser::get_singleton()->remove_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
gdscript_translation_parser_plugin.unref();
#endif // TOOLS_ENABLED
+
+ GDScriptParser::cleanup();
+ GDScriptAnalyzer::cleanup();
}