()
| 853 | // https://tc39.github.io/ecma262/#sec-literals-string-literals |
| 854 | |
| 855 | private scanStringLiteral(): RawToken { |
| 856 | const start = this.index; |
| 857 | let quote = this.source[start]; |
| 858 | assert((quote === '\'' || quote === '"'), |
| 859 | 'String literal must starts with a quote'); |
| 860 | |
| 861 | ++this.index; |
| 862 | let octal = false; |
| 863 | let str = ''; |
| 864 | |
| 865 | while (!this.eof()) { |
| 866 | let ch = this.source[this.index++]; |
| 867 | |
| 868 | if (ch === quote) { |
| 869 | quote = ''; |
| 870 | break; |
| 871 | } else if (ch === '\\') { |
| 872 | ch = this.source[this.index++]; |
| 873 | if (!ch || !Character.isLineTerminator(ch.charCodeAt(0))) { |
| 874 | switch (ch) { |
| 875 | case 'u': |
| 876 | if (this.source[this.index] === '{') { |
| 877 | ++this.index; |
| 878 | str += this.scanUnicodeCodePointEscape(); |
| 879 | } else { |
| 880 | const unescaped = this.scanHexEscape(ch); |
| 881 | if (unescaped === null) { |
| 882 | this.throwUnexpectedToken(); |
| 883 | } |
| 884 | str += unescaped; |
| 885 | } |
| 886 | break; |
| 887 | case 'x': |
| 888 | const unescaped = this.scanHexEscape(ch); |
| 889 | if (unescaped === null) { |
| 890 | this.throwUnexpectedToken(Messages.InvalidHexEscapeSequence); |
| 891 | } |
| 892 | str += unescaped; |
| 893 | break; |
| 894 | case 'n': |
| 895 | str += '\n'; |
| 896 | break; |
| 897 | case 'r': |
| 898 | str += '\r'; |
| 899 | break; |
| 900 | case 't': |
| 901 | str += '\t'; |
| 902 | break; |
| 903 | case 'b': |
| 904 | str += '\b'; |
| 905 | break; |
| 906 | case 'f': |
| 907 | str += '\f'; |
| 908 | break; |
| 909 | case 'v': |
| 910 | str += '\x0B'; |
| 911 | break; |
| 912 | case '8': |
no test coverage detected