int readTemplateLiteral()

in rhino/src/main/java/org/mozilla/javascript/TokenStream.java [1643:1850]


    int readTemplateLiteral(boolean isTaggedLiteral) throws IOException {
        rawString.setLength(0);
        stringBufferTop = 0;
        boolean hasInvalidEscapeSequences = false;

        while (true) {
            int c = getTemplateLiteralChar();
            switch (c) {
                case EOF_CHAR:
                    this.string = hasInvalidEscapeSequences ? null : getStringFromBuffer();
                    tokenEnd = cursor - 1; // restore tokenEnd
                    parser.reportError("msg.unexpected.eof");
                    return Token.ERROR;
                case '`':
                    rawString.setLength(rawString.length() - 1); // don't include "`"
                    this.string = hasInvalidEscapeSequences ? null : getStringFromBuffer();
                    cursor = sourceCursor;
                    tokenEnd = cursor;
                    return Token.TEMPLATE_LITERAL;
                case '$':
                    if (matchTemplateLiteralChar('{')) {
                        rawString.setLength(rawString.length() - 2); // don't include "${"
                        this.string = hasInvalidEscapeSequences ? null : getStringFromBuffer();
                        this.tokenEnd = cursor - 1; // don't include "{"
                        return Token.TEMPLATE_LITERAL_SUBST;
                    } else {
                        addToString(c);
                        break;
                    }
                case '\\':
                    // LineContinuation ::
                    //   \ LineTerminatorSequence
                    // EscapeSequence ::
                    //   CharacterEscapeSequence
                    //   0 [LA not DecimalDigit]
                    //   HexEscapeSequence
                    //   UnicodeEscapeSequence
                    // CharacterEscapeSequence ::
                    //   SingleEscapeCharacter
                    //   NonEscapeCharacter
                    // SingleEscapeCharacter ::
                    //   ' "  \  b f n r t v
                    // NonEscapeCharacter ::
                    //   SourceCharacter but not one of EscapeCharacter or LineTerminator
                    // EscapeCharacter ::
                    //   SingleEscapeCharacter
                    //   DecimalDigit
                    //   x
                    //   u
                    c = getTemplateLiteralChar();
                    switch (c) {
                        case '\n':
                        case '\u2028':
                        case '\u2029':
                            continue;
                        case '\'':
                        case '"':
                        case '\\':
                            // use as-is
                            break;
                        case 'b':
                            c = '\b';
                            break;
                        case 'f':
                            c = '\f';
                            break;
                        case 'n':
                            c = '\n';
                            break;
                        case 'r':
                            c = '\r';
                            break;
                        case 't':
                            c = '\t';
                            break;
                        case 'v':
                            c = 0xb;
                            break;
                        case 'x':
                            {
                                int escapeVal = 0;
                                for (int i = 0; i < 2; i++) {
                                    if (peekTemplateLiteralChar() == '`') {
                                        escapeVal = -1;
                                        break;
                                    }
                                    escapeVal =
                                            Kit.xDigitToInt(getTemplateLiteralChar(), escapeVal);
                                }

                                if (escapeVal < 0) {
                                    if (isTaggedLiteral) {
                                        hasInvalidEscapeSequences = true;
                                        continue;
                                    } else {
                                        parser.reportError("msg.syntax");
                                        return Token.ERROR;
                                    }
                                }
                                c = escapeVal;
                                break;
                            }
                        case 'u':
                            {
                                int escapeVal = 0;

                                if (matchTemplateLiteralChar('{')) {
                                    for (; ; ) {
                                        if (peekTemplateLiteralChar() == '`') {
                                            escapeVal = -1;
                                            break;
                                        }

                                        c = getTemplateLiteralChar();
                                        if (c == EOF_CHAR) {
                                            parser.reportError("msg.syntax");
                                            return Token.ERROR;
                                        }

                                        if (c == '}') {
                                            break;
                                        }
                                        escapeVal = Kit.xDigitToInt(c, escapeVal);
                                    }

                                    if (escapeVal < 0 || escapeVal > 0x10FFFF) {
                                        if (isTaggedLiteral) {
                                            hasInvalidEscapeSequences = true;
                                            continue;
                                        } else {
                                            parser.reportError("msg.syntax");
                                            return Token.ERROR;
                                        }
                                    }

                                    if (escapeVal > 0xFFFF) {
                                        addToString(Character.highSurrogate(escapeVal));
                                        addToString(Character.lowSurrogate(escapeVal));
                                        continue;
                                    }
                                    c = escapeVal;
                                    break;
                                }

                                for (int i = 0; i < 4; i++) {
                                    if (peekTemplateLiteralChar() == '`') {
                                        escapeVal = -1;
                                        break;
                                    }
                                    escapeVal =
                                            Kit.xDigitToInt(getTemplateLiteralChar(), escapeVal);
                                }

                                if (escapeVal < 0) {
                                    if (isTaggedLiteral) {
                                        hasInvalidEscapeSequences = true;
                                        continue;
                                    } else {
                                        parser.reportError("msg.syntax");
                                        return Token.ERROR;
                                    }
                                }
                                c = escapeVal;
                                break;
                            }
                        case '0':
                            {
                                int d = peekTemplateLiteralChar();
                                if (d >= '0' && d <= '9') {
                                    if (isTaggedLiteral) {
                                        hasInvalidEscapeSequences = true;
                                        continue;
                                    } else {
                                        parser.reportError("msg.syntax");
                                        return Token.ERROR;
                                    }
                                }
                                c = 0x00;
                                break;
                            }
                        case '1':
                        case '2':
                        case '3':
                        case '4':
                        case '5':
                        case '6':
                        case '7':
                        case '8':
                        case '9':
                            if (isTaggedLiteral) {
                                hasInvalidEscapeSequences = true;
                                continue;
                            } else {
                                parser.reportError("msg.syntax");
                                return Token.ERROR;
                            }
                        default:
                            // use as-is
                            break;
                    }
                    addToString(c);
                    break;
                default:
                    addToString(c);
                    break;
            }
        }
    }