1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-22 15:06:45 +00:00

Merge pull request #52081 from ThreeRhinosInAnElephantCostume/fixmatchfreeze

Fix gdscript pattern matching expressions
This commit is contained in:
George Marques
2021-09-10 09:28:18 -03:00
committed by GitHub
5 changed files with 127 additions and 43 deletions

View File

@@ -1682,6 +1682,7 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() {
while (!check(GDScriptTokenizer::Token::DEDENT) && !is_at_end()) { while (!check(GDScriptTokenizer::Token::DEDENT) && !is_at_end()) {
MatchBranchNode *branch = parse_match_branch(); MatchBranchNode *branch = parse_match_branch();
if (branch == nullptr) { if (branch == nullptr) {
advance();
continue; continue;
} }
@@ -1745,7 +1746,9 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
push_error(R"(No pattern found for "match" branch.)"); push_error(R"(No pattern found for "match" branch.)");
} }
consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "match" patterns.)"); if (!consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "match" patterns.)")) {
return nullptr;
}
// Save continue state. // Save continue state.
bool could_continue = can_continue; bool could_continue = can_continue;
@@ -1778,15 +1781,6 @@ GDScriptParser::PatternNode *GDScriptParser::parse_match_pattern(PatternNode *p_
PatternNode *pattern = alloc_node<PatternNode>(); PatternNode *pattern = alloc_node<PatternNode>();
switch (current.type) { switch (current.type) {
case GDScriptTokenizer::Token::LITERAL:
advance();
pattern->pattern_type = PatternNode::PT_LITERAL;
pattern->literal = parse_literal();
if (pattern->literal == nullptr) {
// Error happened.
return nullptr;
}
break;
case GDScriptTokenizer::Token::VAR: { case GDScriptTokenizer::Token::VAR: {
// Bind. // Bind.
advance(); advance();
@@ -1849,9 +1843,10 @@ GDScriptParser::PatternNode *GDScriptParser::parse_match_pattern(PatternNode *p_
// Dictionary. // Dictionary.
advance(); advance();
pattern->pattern_type = PatternNode::PT_DICTIONARY; pattern->pattern_type = PatternNode::PT_DICTIONARY;
if (!check(GDScriptTokenizer::Token::BRACE_CLOSE) && !is_at_end()) {
do { do {
if (check(GDScriptTokenizer::Token::BRACE_CLOSE) || is_at_end()) {
break;
}
if (match(GDScriptTokenizer::Token::PERIOD_PERIOD)) { if (match(GDScriptTokenizer::Token::PERIOD_PERIOD)) {
// Rest. // Rest.
if (pattern->rest_used) { if (pattern->rest_used) {
@@ -1886,7 +1881,6 @@ GDScriptParser::PatternNode *GDScriptParser::parse_match_pattern(PatternNode *p_
} }
} }
} while (match(GDScriptTokenizer::Token::COMMA)); } while (match(GDScriptTokenizer::Token::COMMA));
}
consume(GDScriptTokenizer::Token::BRACE_CLOSE, R"(Expected "}" to close the dictionary pattern.)"); consume(GDScriptTokenizer::Token::BRACE_CLOSE, R"(Expected "}" to close the dictionary pattern.)");
break; break;
} }
@@ -1895,8 +1889,13 @@ GDScriptParser::PatternNode *GDScriptParser::parse_match_pattern(PatternNode *p_
ExpressionNode *expression = parse_expression(false); ExpressionNode *expression = parse_expression(false);
if (expression == nullptr) { if (expression == nullptr) {
push_error(R"(Expected expression for match pattern.)"); push_error(R"(Expected expression for match pattern.)");
return nullptr;
} else {
if (expression->type == GDScriptParser::Node::LITERAL) {
pattern->pattern_type = PatternNode::PT_LITERAL;
} else { } else {
pattern->pattern_type = PatternNode::PT_EXPRESSION; pattern->pattern_type = PatternNode::PT_EXPRESSION;
}
pattern->expression = expression; pattern->expression = expression;
} }
break; break;

View File

@@ -0,0 +1,34 @@
func foo(x):
match x:
1 + 1:
print("1+1")
[1,2,[1,{1:2,2:var z,..}]]:
print("[1,2,[1,{1:2,2:var z,..}]]")
print(z)
1 if true else 2:
print("1 if true else 2")
1 < 2:
print("1 < 2")
1 or 2 and 1:
print("1 or 2 and 1")
6 | 1:
print("1 | 1")
1 >> 1:
print("1 >> 1")
1, 2 or 3, 4:
print("1, 2 or 3, 4")
_:
print("wildcard")
func test():
foo(6 | 1)
foo(1 >> 1)
foo(2)
foo(1)
foo(1+1)
foo(1 < 2)
foo([2, 1])
foo(4)
foo([1, 2, [1, {1 : 2, 2:3}]])
foo([1, 2, [1, {1 : 2, 2:[1,3,5, "123"], 4:2}]])
foo([1, 2, [1, {1 : 2}]])

View File

@@ -0,0 +1,14 @@
GDTEST_OK
1 | 1
1 >> 1
1+1
1 if true else 2
1+1
1 < 2
wildcard
1, 2 or 3, 4
[1,2,[1,{1:2,2:var z,..}]]
3
[1,2,[1,{1:2,2:var z,..}]]
[1, 3, 5, 123]
wildcard

View File

@@ -0,0 +1,27 @@
func foo(x):
match x:
1:
print("1")
2:
print("2")
[1, 2]:
print("[1, 2]")
3 or 4:
print("3 or 4")
4:
print("4")
{1 : 2, 2 : 3}:
print("{1 : 2, 2 : 3}")
_:
print("wildcard")
func test():
foo(0)
foo(1)
foo(2)
foo([1, 2])
foo(3)
foo(4)
foo([4,4])
foo({1 : 2, 2 : 3})
foo({1 : 2, 4 : 3})

View File

@@ -0,0 +1,10 @@
GDTEST_OK
wildcard
1
2
[1, 2]
wildcard
4
wildcard
{1 : 2, 2 : 3}
wildcard