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.cpp102
1 files changed, 39 insertions, 63 deletions
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 1a744d59ba..bb08b017c9 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -51,46 +51,8 @@
static HashMap<StringName, Variant::Type> builtin_types;
Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
if (builtin_types.is_empty()) {
- builtin_types["bool"] = Variant::BOOL;
- builtin_types["int"] = Variant::INT;
- builtin_types["float"] = Variant::FLOAT;
- builtin_types["String"] = Variant::STRING;
- builtin_types["Vector2"] = Variant::VECTOR2;
- builtin_types["Vector2i"] = Variant::VECTOR2I;
- builtin_types["Rect2"] = Variant::RECT2;
- builtin_types["Rect2i"] = Variant::RECT2I;
- builtin_types["Transform2D"] = Variant::TRANSFORM2D;
- builtin_types["Vector3"] = Variant::VECTOR3;
- builtin_types["Vector3i"] = Variant::VECTOR3I;
- builtin_types["Vector4"] = Variant::VECTOR4;
- builtin_types["Vector4i"] = Variant::VECTOR4I;
- builtin_types["AABB"] = Variant::AABB;
- builtin_types["Plane"] = Variant::PLANE;
- builtin_types["Quaternion"] = Variant::QUATERNION;
- builtin_types["Basis"] = Variant::BASIS;
- builtin_types["Transform3D"] = Variant::TRANSFORM3D;
- builtin_types["Projection"] = Variant::PROJECTION;
- builtin_types["Color"] = Variant::COLOR;
- builtin_types["RID"] = Variant::RID;
- builtin_types["Object"] = Variant::OBJECT;
- builtin_types["StringName"] = Variant::STRING_NAME;
- builtin_types["NodePath"] = Variant::NODE_PATH;
- builtin_types["Dictionary"] = Variant::DICTIONARY;
- builtin_types["Callable"] = Variant::CALLABLE;
- builtin_types["Signal"] = Variant::SIGNAL;
- builtin_types["Array"] = Variant::ARRAY;
- builtin_types["PackedByteArray"] = Variant::PACKED_BYTE_ARRAY;
- builtin_types["PackedInt32Array"] = Variant::PACKED_INT32_ARRAY;
- builtin_types["PackedInt64Array"] = Variant::PACKED_INT64_ARRAY;
- builtin_types["PackedFloat32Array"] = Variant::PACKED_FLOAT32_ARRAY;
- builtin_types["PackedFloat64Array"] = Variant::PACKED_FLOAT64_ARRAY;
- builtin_types["PackedStringArray"] = Variant::PACKED_STRING_ARRAY;
- builtin_types["PackedVector2Array"] = Variant::PACKED_VECTOR2_ARRAY;
- builtin_types["PackedVector3Array"] = Variant::PACKED_VECTOR3_ARRAY;
- builtin_types["PackedColorArray"] = Variant::PACKED_COLOR_ARRAY;
- // NIL is not here, hence the -1.
- if (builtin_types.size() != Variant::VARIANT_MAX - 1) {
- ERR_PRINT("Outdated parser: amount of built-in types don't match the amount of types in Variant.");
+ for (int i = 1; i < Variant::VARIANT_MAX; i++) {
+ builtin_types[Variant::get_type_name((Variant::Type)i)] = (Variant::Type)i;
}
}
@@ -122,7 +84,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 +802,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);
}
@@ -977,14 +944,14 @@ GDScriptParser::VariableNode *GDScriptParser::parse_property(VariableNode *p_var
// Run with a loop because order doesn't matter.
for (int i = 0; i < 2; i++) {
- if (function->name == "set") {
+ if (function->name == SNAME("set")) {
if (setter_used) {
push_error(R"(Properties can only have one setter.)");
} else {
parse_property_setter(property);
setter_used = true;
}
- } else if (function->name == "get") {
+ } else if (function->name == SNAME("get")) {
if (getter_used) {
push_error(R"(Properties can only have one getter.)");
} else {
@@ -1901,11 +1868,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 +1879,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;
}
@@ -2928,7 +2883,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre
// Arguments.
CompletionType ct = COMPLETION_CALL_ARGUMENTS;
- if (call->function_name == "load") {
+ if (call->function_name == SNAME("load")) {
ct = COMPLETION_RESOURCE_PATH;
}
push_completion_call(call);
@@ -3665,6 +3620,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 +3768,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 +3826,6 @@ bool GDScriptParser::export_group_annotations(const AnnotationNode *p_annotation
} break;
}
- current_class->add_member_group(annotation);
return true;
}