| 661 | } |
| 662 | |
| 663 | GDScriptV2TokenizerCompat::Token GDScriptV2TokenizerCompatText::string() { |
| 664 | enum StringType { |
| 665 | STRING_REGULAR, |
| 666 | STRING_NAME, |
| 667 | STRING_NODEPATH, |
| 668 | }; |
| 669 | |
| 670 | bool is_raw = false; |
| 671 | bool is_multiline = false; |
| 672 | StringType type = STRING_REGULAR; |
| 673 | |
| 674 | if (_peek(-1) == 'r') { |
| 675 | is_raw = true; |
| 676 | _advance(); |
| 677 | } else if (_peek(-1) == '&') { |
| 678 | type = STRING_NAME; |
| 679 | _advance(); |
| 680 | } else if (_peek(-1) == '^') { |
| 681 | type = STRING_NODEPATH; |
| 682 | _advance(); |
| 683 | } |
| 684 | |
| 685 | char32_t quote_char = _peek(-1); |
| 686 | |
| 687 | if (_peek() == quote_char && _peek(1) == quote_char) { |
| 688 | is_multiline = true; |
| 689 | // Consume all quotes. |
| 690 | _advance(); |
| 691 | _advance(); |
| 692 | } |
| 693 | |
| 694 | String result; |
| 695 | char32_t prev = 0; |
| 696 | int prev_pos = 0; |
| 697 | |
| 698 | for (;;) { |
| 699 | // Consume actual string. |
| 700 | if (_is_at_end()) { |
| 701 | return make_error("Unterminated string."); |
| 702 | } |
| 703 | |
| 704 | char32_t ch = _peek(); |
| 705 | |
| 706 | if (ch == 0x200E || ch == 0x200F || (ch >= 0x202A && ch <= 0x202E) || (ch >= 0x2066 && ch <= 0x2069)) { |
| 707 | Token error; |
| 708 | if (is_raw) { |
| 709 | error = make_error("Invisible text direction control character present in the string, use regular string literal instead of r-string."); |
| 710 | } else { |
| 711 | error = make_error("Invisible text direction control character present in the string, escape it (\"\\u" + String::num_int64(ch, 16) + "\") to avoid confusion."); |
| 712 | } |
| 713 | error.start_column = column; |
| 714 | error.leftmost_column = error.start_column; |
| 715 | error.end_column = column + 1; |
| 716 | error.rightmost_column = error.end_column; |
| 717 | push_error(error); |
| 718 | } |
| 719 | |
| 720 | if (ch == '\\') { |