diff options
Diffstat (limited to 'modules/gdscript/gdscript_parser.cpp')
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 95 |
1 files changed, 19 insertions, 76 deletions
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 6dc63c502c..267718207f 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -529,7 +529,7 @@ void GDScriptParser::parse_program() { AnnotationNode *annotation = parse_annotation(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE | AnnotationInfo::CLASS_LEVEL); if (annotation != nullptr) { if (annotation->applies_to(AnnotationInfo::SCRIPT)) { - annotation->apply(this, head); + head->annotations.push_back(annotation); } else { annotation_stack.push_back(annotation); // This annotation must appear after script-level annotations @@ -771,7 +771,6 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)() return; } - // Apply annotations. for (AnnotationNode *&annotation : annotations) { member->annotations.push_back(annotation); } @@ -841,14 +840,19 @@ void GDScriptParser::parse_class_body(bool p_is_multiline) { case GDScriptTokenizer::Token::ANNOTATION: { advance(); - // Check for class-level annotations. + // Check for standalone and class-level annotations. AnnotationNode *annotation = parse_annotation(AnnotationInfo::STANDALONE | AnnotationInfo::CLASS_LEVEL); if (annotation != nullptr) { if (annotation->applies_to(AnnotationInfo::STANDALONE)) { if (previous.type != GDScriptTokenizer::Token::NEWLINE) { push_error(R"(Expected newline after a standalone annotation.)"); } - annotation->apply(this, head); + if (annotation->name == "@export_category" || annotation->name == "@export_group" || annotation->name == "@export_subgroup") { + current_class->add_member_group(annotation); + } else { + // For potential non-group standalone annotations. + push_error(R"(Unexpected standalone annotation in class body.)"); + } } else { annotation_stack.push_back(annotation); } @@ -1434,7 +1438,11 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali annotation->info = &valid_annotations[annotation->name]; if (!annotation->applies_to(p_valid_targets)) { - push_error(vformat(R"(Annotation "%s" is not allowed in this level.)", annotation->name)); + 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; } @@ -1466,7 +1474,7 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali match(GDScriptTokenizer::Token::NEWLINE); // Newline after annotation is optional. if (valid) { - valid = validate_annotation_arguments(annotation); + valid = validate_annotation_argument_count(annotation); } return valid ? annotation : nullptr; @@ -1697,6 +1705,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { case Node::CALL: case Node::ASSIGNMENT: case Node::AWAIT: + case Node::TERNARY_OPERATOR: // Fine. break; case Node::LAMBDA: @@ -1712,7 +1721,6 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { } } - // Apply annotations to statement. while (!is_annotation && result != nullptr && !annotation_stack.is_empty()) { AnnotationNode *last_annotation = annotation_stack.back()->get(); if (last_annotation->applies_to(AnnotationInfo::STATEMENT)) { @@ -1901,7 +1909,6 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() { #ifdef DEBUG_ENABLED bool all_have_return = true; bool have_wildcard = false; - bool have_wildcard_without_continue = false; #endif while (!check(GDScriptTokenizer::Token::DEDENT) && !is_at_end()) { @@ -1912,19 +1919,12 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() { } #ifdef DEBUG_ENABLED - if (have_wildcard_without_continue && !branch->patterns.is_empty()) { + if (have_wildcard && !branch->patterns.is_empty()) { push_warning(branch->patterns[0], GDScriptWarning::UNREACHABLE_PATTERN); } - if (branch->has_wildcard) { - have_wildcard = true; - if (!branch->block->has_continue) { - have_wildcard_without_continue = true; - } - } - if (!branch->block->has_return) { - all_have_return = false; - } + have_wildcard = have_wildcard || branch->has_wildcard; + all_have_return = all_have_return && branch->block->has_return; #endif match->branches.push_back(branch); } @@ -3593,7 +3593,7 @@ bool GDScriptParser::AnnotationNode::applies_to(uint32_t p_target_kinds) const { return (info->target_kind & p_target_kinds) > 0; } -bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation) { +bool GDScriptParser::validate_annotation_argument_count(AnnotationNode *p_annotation) { ERR_FAIL_COND_V_MSG(!valid_annotations.has(p_annotation->name), false, vformat(R"(Annotation "%s" not found to validate.)", p_annotation->name)); const MethodInfo &info = valid_annotations[p_annotation->name].info; @@ -3608,62 +3608,6 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation) return false; } - const List<PropertyInfo>::Element *E = info.arguments.front(); - for (int i = 0; i < p_annotation->arguments.size(); i++) { - ExpressionNode *argument = p_annotation->arguments[i]; - const PropertyInfo ¶meter = E->get(); - - if (E->next() != nullptr) { - E = E->next(); - } - - switch (parameter.type) { - case Variant::STRING: - case Variant::STRING_NAME: - case Variant::NODE_PATH: - // Allow "quote-less strings", as long as they are recognized as identifiers. - if (argument->type == Node::IDENTIFIER) { - IdentifierNode *string = static_cast<IdentifierNode *>(argument); - Callable::CallError error; - Vector<Variant> args = varray(string->name); - const Variant *name = args.ptr(); - Variant r; - Variant::construct(parameter.type, r, &(name), 1, error); - p_annotation->resolved_arguments.push_back(r); - if (error.error != Callable::CallError::CALL_OK) { - push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name)); - p_annotation->resolved_arguments.remove_at(p_annotation->resolved_arguments.size() - 1); - return false; - } - break; - } - [[fallthrough]]; - default: { - if (argument->type != Node::LITERAL) { - push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name)); - return false; - } - - Variant value = static_cast<LiteralNode *>(argument)->value; - if (!Variant::can_convert_strict(value.get_type(), parameter.type)) { - push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name)); - return false; - } - Callable::CallError error; - const Variant *args = &value; - Variant r; - Variant::construct(parameter.type, r, &(args), 1, error); - p_annotation->resolved_arguments.push_back(r); - if (error.error != Callable::CallError::CALL_OK) { - push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name)); - p_annotation->resolved_arguments.remove_at(p_annotation->resolved_arguments.size() - 1); - return false; - } - break; - } - } - } - return true; } @@ -3902,7 +3846,6 @@ bool GDScriptParser::export_group_annotations(const AnnotationNode *p_annotation } break; } - current_class->add_member_group(annotation); return true; } |