| 2380 | } |
| 2381 | |
| 2382 | GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() { |
| 2383 | MatchBranchNode *branch = alloc_node<MatchBranchNode>(); |
| 2384 | reset_extents(branch, current); |
| 2385 | |
| 2386 | bool has_bind = false; |
| 2387 | |
| 2388 | do { |
| 2389 | PatternNode *pattern = parse_match_pattern(); |
| 2390 | if (pattern == nullptr) { |
| 2391 | continue; |
| 2392 | } |
| 2393 | if (pattern->binds.size() > 0) { |
| 2394 | has_bind = true; |
| 2395 | } |
| 2396 | if (branch->patterns.size() > 0 && has_bind) { |
| 2397 | push_error(R"(Cannot use a variable bind with multiple patterns.)"); |
| 2398 | } |
| 2399 | if (pattern->pattern_type == PatternNode::PT_REST) { |
| 2400 | push_error(R"(Rest pattern can only be used inside array and dictionary patterns.)"); |
| 2401 | } else if (pattern->pattern_type == PatternNode::PT_BIND || pattern->pattern_type == PatternNode::PT_WILDCARD) { |
| 2402 | branch->has_wildcard = true; |
| 2403 | } |
| 2404 | branch->patterns.push_back(pattern); |
| 2405 | } while (match(GDScriptTokenizer::Token::COMMA)); |
| 2406 | |
| 2407 | if (branch->patterns.is_empty()) { |
| 2408 | push_error(R"(No pattern found for "match" branch.)"); |
| 2409 | } |
| 2410 | |
| 2411 | bool has_guard = false; |
| 2412 | if (match(GDScriptTokenizer::Token::WHEN)) { |
| 2413 | // Pattern guard. |
| 2414 | // Create block for guard because it also needs to access the bound variables from patterns, and we don't want to add them to the outer scope. |
| 2415 | branch->guard_body = alloc_node<SuiteNode>(); |
| 2416 | if (branch->patterns.size() > 0) { |
| 2417 | for (const KeyValue<StringName, IdentifierNode *> &E : branch->patterns[0]->binds) { |
| 2418 | SuiteNode::Local local(E.value, current_function); |
| 2419 | local.type = SuiteNode::Local::PATTERN_BIND; |
| 2420 | branch->guard_body->add_local(local); |
| 2421 | } |
| 2422 | } |
| 2423 | |
| 2424 | SuiteNode *parent_block = current_suite; |
| 2425 | branch->guard_body->parent_block = parent_block; |
| 2426 | current_suite = branch->guard_body; |
| 2427 | |
| 2428 | ExpressionNode *guard = parse_expression(false); |
| 2429 | if (guard == nullptr) { |
| 2430 | push_error(R"(Expected expression for pattern guard after "when".)"); |
| 2431 | } else { |
| 2432 | branch->guard_body->statements.append(guard); |
| 2433 | } |
| 2434 | current_suite = parent_block; |
| 2435 | complete_extents(branch->guard_body); |
| 2436 | |
| 2437 | has_guard = true; |
| 2438 | branch->has_wildcard = false; // If it has a guard, the wildcard might still not match. |
| 2439 | } |