| 2467 | } |
| 2468 | |
| 2469 | GDScriptParser::PatternNode *GDScriptParser::parse_match_pattern(PatternNode *p_root_pattern) { |
| 2470 | PatternNode *pattern = alloc_node<PatternNode>(); |
| 2471 | reset_extents(pattern, current); |
| 2472 | |
| 2473 | switch (current.type) { |
| 2474 | case GDScriptTokenizer::Token::VAR: { |
| 2475 | // Bind. |
| 2476 | advance(); |
| 2477 | if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected bind name after "var".)")) { |
| 2478 | complete_extents(pattern); |
| 2479 | return nullptr; |
| 2480 | } |
| 2481 | pattern->pattern_type = PatternNode::PT_BIND; |
| 2482 | pattern->bind = parse_identifier(); |
| 2483 | |
| 2484 | PatternNode *root_pattern = p_root_pattern == nullptr ? pattern : p_root_pattern; |
| 2485 | |
| 2486 | if (p_root_pattern != nullptr) { |
| 2487 | if (p_root_pattern->has_bind(pattern->bind->name)) { |
| 2488 | push_error(vformat(R"(Bind variable name "%s" was already used in this pattern.)", pattern->bind->name)); |
| 2489 | complete_extents(pattern); |
| 2490 | return nullptr; |
| 2491 | } |
| 2492 | } |
| 2493 | |
| 2494 | if (current_suite->has_local(pattern->bind->name)) { |
| 2495 | push_error(vformat(R"(There's already a %s named "%s" in this scope.)", current_suite->get_local(pattern->bind->name).get_name(), pattern->bind->name)); |
| 2496 | complete_extents(pattern); |
| 2497 | return nullptr; |
| 2498 | } |
| 2499 | |
| 2500 | root_pattern->binds[pattern->bind->name] = pattern->bind; |
| 2501 | |
| 2502 | } break; |
| 2503 | case GDScriptTokenizer::Token::UNDERSCORE: |
| 2504 | // Wildcard. |
| 2505 | advance(); |
| 2506 | pattern->pattern_type = PatternNode::PT_WILDCARD; |
| 2507 | break; |
| 2508 | case GDScriptTokenizer::Token::PERIOD_PERIOD: |
| 2509 | // Rest. |
| 2510 | advance(); |
| 2511 | pattern->pattern_type = PatternNode::PT_REST; |
| 2512 | break; |
| 2513 | case GDScriptTokenizer::Token::BRACKET_OPEN: { |
| 2514 | // Array. |
| 2515 | push_multiline(true); |
| 2516 | advance(); |
| 2517 | pattern->pattern_type = PatternNode::PT_ARRAY; |
| 2518 | do { |
| 2519 | if (is_at_end() || check(GDScriptTokenizer::Token::BRACKET_CLOSE)) { |
| 2520 | break; |
| 2521 | } |
| 2522 | PatternNode *sub_pattern = parse_match_pattern(p_root_pattern != nullptr ? p_root_pattern : pattern); |
| 2523 | if (sub_pattern == nullptr) { |
| 2524 | continue; |
| 2525 | } |
| 2526 | if (pattern->rest_used) { |