| 2644 | } |
| 2645 | |
| 2646 | GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_precedence, bool p_can_assign, bool p_stop_on_assign) { |
| 2647 | // Switch multiline mode on for grouping tokens. |
| 2648 | // Do this early to avoid the tokenizer generating whitespace tokens. |
| 2649 | switch (current.type) { |
| 2650 | case GDScriptTokenizer::Token::PARENTHESIS_OPEN: |
| 2651 | case GDScriptTokenizer::Token::BRACE_OPEN: |
| 2652 | case GDScriptTokenizer::Token::BRACKET_OPEN: |
| 2653 | push_multiline(true); |
| 2654 | break; |
| 2655 | default: |
| 2656 | break; // Nothing to do. |
| 2657 | } |
| 2658 | |
| 2659 | // Completion can appear whenever an expression is expected. |
| 2660 | make_completion_context(COMPLETION_IDENTIFIER, nullptr, -1, false); |
| 2661 | |
| 2662 | GDScriptTokenizer::Token token = current; |
| 2663 | GDScriptTokenizer::Token::Type token_type = token.type; |
| 2664 | if (token.is_identifier()) { |
| 2665 | // Allow keywords that can be treated as identifiers. |
| 2666 | token_type = GDScriptTokenizer::Token::IDENTIFIER; |
| 2667 | } |
| 2668 | ParseFunction prefix_rule = get_rule(token_type)->prefix; |
| 2669 | |
| 2670 | if (prefix_rule == nullptr) { |
| 2671 | // Expected expression. Let the caller give the proper error message. |
| 2672 | return nullptr; |
| 2673 | } |
| 2674 | |
| 2675 | advance(); // Only consume the token if there's a valid rule. |
| 2676 | |
| 2677 | // After a token was consumed, update the completion context regardless of a previously set context. |
| 2678 | |
| 2679 | ExpressionNode *previous_operand = (this->*prefix_rule)(nullptr, p_can_assign); |
| 2680 | |
| 2681 | #ifdef TOOLS_ENABLED |
| 2682 | /// @todo HACK: We can't create a context in parse_identifier since it is used in places were we don't want completion. |
| 2683 | if (previous_operand != nullptr && previous_operand->type == GDScriptParser::Node::IDENTIFIER && prefix_rule == static_cast<ParseFunction>(&GDScriptParser::parse_identifier)) { |
| 2684 | make_completion_context(COMPLETION_IDENTIFIER, previous_operand); |
| 2685 | } |
| 2686 | #endif |
| 2687 | |
| 2688 | while (p_precedence <= get_rule(current.type)->precedence) { |
| 2689 | if (previous_operand == nullptr || (p_stop_on_assign && current.type == GDScriptTokenizer::Token::EQUAL) || lambda_ended) { |
| 2690 | return previous_operand; |
| 2691 | } |
| 2692 | // Also switch multiline mode on here for infix operators. |
| 2693 | switch (current.type) { |
| 2694 | // case GDScriptTokenizer::Token::BRACE_OPEN: // Not an infix operator. |
| 2695 | case GDScriptTokenizer::Token::PARENTHESIS_OPEN: |
| 2696 | case GDScriptTokenizer::Token::BRACKET_OPEN: |
| 2697 | push_multiline(true); |
| 2698 | break; |
| 2699 | default: |
| 2700 | break; // Nothing to do. |
| 2701 | } |
| 2702 | token = advance(); |
| 2703 | ParseFunction infix_rule = get_rule(token.type)->infix; |
nothing calls this directly
no test coverage detected