summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/gdscript_parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gdscript_parser.cpp')
-rw-r--r--modules/gdscript/gdscript_parser.cpp65
1 files changed, 48 insertions, 17 deletions
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index b5cb5a4680..d1d50351d0 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -712,14 +712,14 @@ void GDScriptParser::parse_extends() {
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected superclass name after "extends".)")) {
return;
}
- current_class->extends.push_back(previous.literal);
+ current_class->extends.push_back(parse_identifier());
while (match(GDScriptTokenizer::Token::PERIOD)) {
make_completion_context(COMPLETION_INHERIT_TYPE, current_class, chain_index++);
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected superclass name after ".".)")) {
return;
}
- current_class->extends.push_back(previous.literal);
+ current_class->extends.push_back(parse_identifier());
}
}
@@ -1343,7 +1343,7 @@ void GDScriptParser::parse_function_signature(FunctionNode *p_function, SuiteNod
default_used = true;
} else {
if (default_used) {
- push_error("Cannot have a mandatory parameters after optional parameters.");
+ push_error("Cannot have mandatory parameters after optional parameters.");
continue;
}
}
@@ -1475,7 +1475,7 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali
void GDScriptParser::clear_unused_annotations() {
for (const AnnotationNode *annotation : annotation_stack) {
- push_error(vformat(R"(Annotation "%s" does not precedes a valid target, so it will have no effect.)", annotation->name), annotation);
+ push_error(vformat(R"(Annotation "%s" does not precede a valid target, so it will have no effect.)", annotation->name), annotation);
}
annotation_stack.clear();
@@ -1521,7 +1521,7 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context,
int error_count = 0;
do {
- if (!multiline && previous.type == GDScriptTokenizer::Token::SEMICOLON && check(GDScriptTokenizer::Token::NEWLINE)) {
+ if (is_at_end() || (!multiline && previous.type == GDScriptTokenizer::Token::SEMICOLON && check(GDScriptTokenizer::Token::NEWLINE))) {
break;
}
Node *statement = parse_statement();
@@ -1817,7 +1817,7 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() {
n_for->list = parse_expression(false);
if (!n_for->list) {
- push_error(R"(Expected a list or range after "in".)");
+ push_error(R"(Expected iterable after "in".)");
}
consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "for" condition.)");
@@ -2463,9 +2463,6 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_operator(Expression
operation->operation = BinaryOpNode::OP_LOGIC_OR;
operation->variant_op = Variant::OP_OR;
break;
- case GDScriptTokenizer::Token::IS:
- operation->operation = BinaryOpNode::OP_TYPE_TEST;
- break;
case GDScriptTokenizer::Token::IN:
operation->operation = BinaryOpNode::OP_CONTENT_TEST;
operation->variant_op = Variant::OP_IN;
@@ -3141,6 +3138,14 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_lambda(ExpressionNode *p_p
bool previous_in_lambda = in_lambda;
in_lambda = true;
+ // Save break/continue state.
+ bool could_break = can_break;
+ bool could_continue = can_continue;
+
+ // Disallow break/continue.
+ can_break = false;
+ can_continue = false;
+
function->body = parse_suite("lambda declaration", body, true);
complete_extents(function);
complete_extents(lambda);
@@ -3158,9 +3163,30 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_lambda(ExpressionNode *p_p
current_function = previous_function;
in_lambda = previous_in_lambda;
lambda->function = function;
+
+ // Reset break/continue state.
+ can_break = could_break;
+ can_continue = could_continue;
+
return lambda;
}
+GDScriptParser::ExpressionNode *GDScriptParser::parse_type_test(ExpressionNode *p_previous_operand, bool p_can_assign) {
+ TypeTestNode *type_test = alloc_node<TypeTestNode>();
+ reset_extents(type_test, p_previous_operand);
+ update_extents(type_test);
+
+ type_test->operand = p_previous_operand;
+ type_test->test_type = parse_type();
+ complete_extents(type_test);
+
+ if (type_test->test_type == nullptr) {
+ push_error(R"(Expected type specifier after "is".)");
+ }
+
+ return type_test;
+}
+
GDScriptParser::ExpressionNode *GDScriptParser::parse_yield(ExpressionNode *p_previous_operand, bool p_can_assign) {
push_error(R"("yield" was removed in Godot 4.0. Use "await" instead.)");
return nullptr;
@@ -3529,7 +3555,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
{ nullptr, nullptr, PREC_NONE }, // EXTENDS,
{ &GDScriptParser::parse_lambda, nullptr, PREC_NONE }, // FUNC,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_CONTENT_TEST }, // IN,
- { nullptr, &GDScriptParser::parse_binary_operator, PREC_TYPE_TEST }, // IS,
+ { nullptr, &GDScriptParser::parse_type_test, PREC_TYPE_TEST }, // IS,
{ nullptr, nullptr, PREC_NONE }, // NAMESPACE,
{ &GDScriptParser::parse_preload, nullptr, PREC_NONE }, // PRELOAD,
{ &GDScriptParser::parse_self, nullptr, PREC_NONE }, // SELF,
@@ -3830,7 +3856,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.hint = PROPERTY_HINT_NODE_TYPE;
variable->export_info.hint_string = export_type.to_string();
} else {
- push_error(R"(Export type can only be built-in, a resource, a node or an enum.)", variable);
+ push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", variable);
return false;
}
@@ -3875,8 +3901,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.hint_string = enum_hint_string;
} break;
default:
- // TODO: Allow custom user resources.
- push_error(R"(Export type can only be built-in, a resource, or an enum.)", variable);
+ push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", variable);
break;
}
@@ -4379,9 +4404,6 @@ void GDScriptParser::TreePrinter::print_binary_op(BinaryOpNode *p_binary_op) {
case BinaryOpNode::OP_LOGIC_OR:
push_text(" OR ");
break;
- case BinaryOpNode::OP_TYPE_TEST:
- push_text(" IS ");
- break;
case BinaryOpNode::OP_CONTENT_TEST:
push_text(" IN ");
break;
@@ -4456,7 +4478,7 @@ void GDScriptParser::TreePrinter::print_class(ClassNode *p_class) {
} else {
first = false;
}
- push_text(p_class->extends[i]);
+ push_text(p_class->extends[i]->name);
}
}
@@ -4584,6 +4606,9 @@ void GDScriptParser::TreePrinter::print_expression(ExpressionNode *p_expression)
case Node::TERNARY_OPERATOR:
print_ternary_op(static_cast<TernaryOpNode *>(p_expression));
break;
+ case Node::TYPE_TEST:
+ print_type_test(static_cast<TypeTestNode *>(p_expression));
+ break;
case Node::UNARY_OPERATOR:
print_unary_op(static_cast<UnaryOpNode *>(p_expression));
break;
@@ -4943,6 +4968,12 @@ void GDScriptParser::TreePrinter::print_type(TypeNode *p_type) {
}
}
+void GDScriptParser::TreePrinter::print_type_test(TypeTestNode *p_test) {
+ print_expression(p_test->operand);
+ push_text(" IS ");
+ print_type(p_test->test_type);
+}
+
void GDScriptParser::TreePrinter::print_unary_op(UnaryOpNode *p_unary_op) {
// Surround in parenthesis for disambiguation.
push_text("(");