summaryrefslogtreecommitdiff
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.cpp54
1 files changed, 34 insertions, 20 deletions
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 1a744d59ba..66374d0a6d 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -122,7 +122,7 @@ GDScriptParser::GDScriptParser() {
register_annotation(MethodInfo("@onready"), AnnotationInfo::VARIABLE, &GDScriptParser::onready_annotation);
// Export annotations.
register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>);
- register_annotation(MethodInfo("@export_enum", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::INT>, varray(), true);
+ register_annotation(MethodInfo("@export_enum", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::NIL>, varray(), true);
register_annotation(MethodInfo("@export_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, varray(""), true);
register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>);
register_annotation(MethodInfo("@export_global_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_FILE, Variant::STRING>, varray(""), true);
@@ -840,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.)");
}
- head->annotations.push_back(annotation);
+ 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);
}
@@ -1901,11 +1906,8 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() {
return 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()) {
MatchBranchNode *branch = parse_match_branch();
@@ -1915,31 +1917,22 @@ 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;
- }
#endif
+
+ have_wildcard = have_wildcard || branch->has_wildcard;
+ all_have_return = all_have_return && branch->block->has_return;
match->branches.push_back(branch);
}
complete_extents(match);
consume(GDScriptTokenizer::Token::DEDENT, R"(Expected an indented block after "match" statement.)");
-#ifdef DEBUG_ENABLED
if (all_have_return && have_wildcard) {
current_suite->has_return = true;
}
-#endif
return match;
}
@@ -3665,6 +3658,10 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
String hint_string;
for (int i = 0; i < p_annotation->resolved_arguments.size(); i++) {
+ if (p_annotation->name != SNAME("@export_placeholder") && String(p_annotation->resolved_arguments[i]).contains(",")) {
+ push_error(vformat(R"(Argument %d of annotation "%s" contains a comma. Use separate arguments instead.)", i + 1, p_annotation->name), p_annotation->arguments[i]);
+ return false;
+ }
if (i > 0) {
hint_string += ",";
}
@@ -3809,6 +3806,24 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string;
variable->export_info.type = Variant::ARRAY;
}
+ } else if (p_annotation->name == SNAME("@export_enum")) {
+ Variant::Type enum_type = Variant::INT;
+
+ if (export_type.kind == DataType::BUILTIN && export_type.builtin_type == Variant::STRING) {
+ enum_type = Variant::STRING;
+ } else if (export_type.is_variant() && variable->initializer != nullptr) {
+ DataType initializer_type = variable->initializer->get_datatype();
+ if (initializer_type.kind == DataType::BUILTIN && initializer_type.builtin_type == Variant::STRING) {
+ enum_type = Variant::STRING;
+ }
+ }
+
+ variable->export_info.type = enum_type;
+
+ if (!export_type.is_variant() && (export_type.kind != DataType::BUILTIN || export_type.builtin_type != enum_type)) {
+ push_error(vformat(R"("@export_enum" annotation requires a variable of type "int" or "String" but type "%s" was given instead.)", export_type.to_string()), variable);
+ return false;
+ }
} else {
// Validate variable type with export.
if (!export_type.is_variant() && (export_type.kind != DataType::BUILTIN || export_type.builtin_type != t_type)) {
@@ -3849,7 +3864,6 @@ bool GDScriptParser::export_group_annotations(const AnnotationNode *p_annotation
} break;
}
- current_class->add_member_group(annotation);
return true;
}