Ver Fonte

GDScript: Allow variables in match patterns

To restore an ability available in 3.x and reduce compatibility changes.
George Marques há 2 anos atrás
pai
commit
c68b2358d5

+ 15 - 4
modules/gdscript/gdscript_analyzer.cpp

@@ -1901,11 +1901,22 @@ void GDScriptAnalyzer::resolve_match_pattern(GDScriptParser::PatternNode *p_matc
 			break;
 		case GDScriptParser::PatternNode::PT_EXPRESSION:
 			if (p_match_pattern->expression) {
-				reduce_expression(p_match_pattern->expression);
-				if (!p_match_pattern->expression->is_constant) {
-					push_error(R"(Expression in match pattern must be a constant.)", p_match_pattern->expression);
+				GDScriptParser::ExpressionNode *expr = p_match_pattern->expression;
+				reduce_expression(expr);
+				result = expr->get_datatype();
+				if (!expr->is_constant) {
+					while (expr && expr->type == GDScriptParser::Node::SUBSCRIPT) {
+						GDScriptParser::SubscriptNode *sub = static_cast<GDScriptParser::SubscriptNode *>(expr);
+						if (!sub->is_attribute) {
+							expr = nullptr;
+						} else {
+							expr = sub->base;
+						}
+					}
+					if (!expr || expr->type != GDScriptParser::Node::IDENTIFIER) {
+						push_error(R"(Expression in match pattern must be a constant expression, an identifier, or an attribute access ("A.B").)", expr);
+					}
 				}
-				result = p_match_pattern->expression->get_datatype();
 			}
 			break;
 		case GDScriptParser::PatternNode::PT_BIND:

+ 3 - 11
modules/gdscript/gdscript_parser.cpp

@@ -1904,7 +1904,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()) {
@@ -1915,19 +1914,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);
 	}

+ 5 - 0
modules/gdscript/tests/scripts/analyzer/errors/match_with_subscript.gd

@@ -0,0 +1,5 @@
+func test():
+	var dict = { a = 1 }
+	match 2:
+		dict["a"]:
+			print("not allowed")

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/match_with_subscript.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression in match pattern must be a constant expression, an identifier, or an attribute access ("A.B").

+ 5 - 0
modules/gdscript/tests/scripts/analyzer/errors/match_with_variable_expression.gd

@@ -0,0 +1,5 @@
+func test():
+	var a = 1
+	match 2:
+		a + 2:
+			print("not allowed")

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/match_with_variable_expression.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression in match pattern must be a constant expression, an identifier, or an attribute access ("A.B").

+ 22 - 0
modules/gdscript/tests/scripts/parser/features/match_with_variables.gd

@@ -0,0 +1,22 @@
+func test():
+	var a = 1
+	match 1:
+		a:
+			print("reach 1")
+
+	var dict = { b = 2 }
+	match 2:
+		dict.b:
+			print("reach 2")
+
+	var nested_dict = {
+		sub = { c = 3 }
+	}
+	match 3:
+		nested_dict.sub.c:
+			print("reach 3")
+
+	var sub_pattern = { d = 4 }
+	match [4]:
+		[sub_pattern.d]:
+			print("reach 4")

+ 5 - 0
modules/gdscript/tests/scripts/parser/features/match_with_variables.out

@@ -0,0 +1,5 @@
+GDTEST_OK
+reach 1
+reach 2
+reach 3
+reach 4