Beispiel #1
1
  /**
   * <strong>[11.6] Identifier Names and Identifiers</strong>
   *
   * <pre>
   * Identifier ::
   *     IdentifierName but not ReservedWord
   * IdentifierName ::
   *     IdentifierStart
   *     IdentifierName IdentifierPart
   * </pre>
   */
  private Token readIdentifier(int c) {
    assert isIdentifierStart(c);

    TokenStreamInput input = this.input;
    StringBuffer buffer = this.buffer();
    buffer.addCodepoint(c);
    for (; ; ) {
      c = input.get();
      if (isIdentifierPart(c)) {
        buffer.add(c);
      } else if (c == '\\') {
        mustMatch('u');
        c = readUnicode();
        if (!isIdentifierPart(c)) {
          throw error(Messages.Key.InvalidUnicodeEscapedIdentifierPart);
        }
        buffer.addCodepoint(c);
        continue;
      } else {
        input.unget(c);
        break;
      }
    }

    Token tok = readReservedWord(buffer);
    if (tok != null) {
      return tok;
    }
    return Token.NAME;
  }
Beispiel #2
1
  /**
   * <strong>[11.8.6] Template Literal Lexical Components</strong>
   *
   * <pre>
   * Template ::
   *     NoSubstitutionTemplate
   *     TemplateHead
   * NoSubstitutionTemplate ::
   *     ` TemplateCharacters<sub>opt</sub>`
   * TemplateHead ::
   *     ` TemplateCharacters<sub>opt</sub>${
   * TemplateSubstitutionTail ::
   *     TemplateMiddle
   *     TemplateTail
   * TemplateMiddle ::
   *     } TemplateCharacters<sub>opt</sub>${
   * TemplateTail ::
   *     } TemplateCharacters<sub>opt</sub>`
   * TemplateCharacters ::
   *     TemplateCharacter TemplateCharacters<sub>opt</sub>
   * TemplateCharacter ::
   *     SourceCharacter but not one of ` or \ or $
   *     $ [LA &#x2209; { ]
   *     \ EscapeSequence
   *     LineContinuation
   * </pre>
   */
  public String[] readTemplateLiteral(Token start) {
    assert start == Token.TEMPLATE || start == Token.RC;
    assert currentToken() == start;
    assert next == null : "template literal in lookahead";

    final int EOF = TokenStreamInput.EOF;
    TokenStreamInput input = this.input;
    StringBuilder raw = new StringBuilder();
    StringBuffer buffer = buffer();
    int pos = input.position();
    for (; ; ) {
      int c = input.get();
      if (c == EOF) {
        throw eofError(Messages.Key.UnterminatedTemplateLiteral);
      }
      if (c == '`') {
        current = Token.TEMPLATE;
        raw.append(input.range(pos, input.position() - 1));
        return new String[] {buffer.toString(), raw.toString()};
      }
      if (c == '$' && match('{')) {
        current = Token.LC;
        raw.append(input.range(pos, input.position() - 2));
        return new String[] {buffer.toString(), raw.toString()};
      }
      if (c != '\\') {
        if (isLineTerminator(c)) {
          // line terminator sequence
          if (c == '\r') {
            // normalise \r and \r\n to \n
            raw.append(input.range(pos, input.position() - 1)).append('\n');
            match('\n');
            pos = input.position();
            c = '\n';
          }
          buffer.add(c);
          incrementLine();
          continue;
        }
        // TODO: add substring range
        buffer.add(c);
        continue;
      }

      c = input.get();
      if (c == EOF) {
        throw eofError(Messages.Key.UnterminatedTemplateLiteral);
      }
      // EscapeSequence
      if (isLineTerminator(c)) {
        // line continuation
        if (c == '\r') {
          // normalise \r and \r\n to \n
          raw.append(input.range(pos, input.position() - 1)).append('\n');
          match('\n');
          pos = input.position();
        }
        incrementLine();
        continue;
      }
      switch (c) {
        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 = '\u000B';
          break;
        case '0':
          if (isDecimalDigit(input.peek(0))) {
            throw error(Messages.Key.InvalidNULLEscape);
          }
          c = '\0';
          break;
        case 'x':
          c = (hexDigit(input.get()) << 4) | hexDigit(input.get());
          if (c < 0) {
            throw error(Messages.Key.InvalidHexEscape);
          }
          break;
        case 'u':
          c = readUnicode();
          break;
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
          throw error(Messages.Key.StrictModeOctalEscapeSequence);
        case '"':
        case '\'':
        case '\\':
        default:
          // fall-through
      }
      buffer.addCodepoint(c);
    }
  }
Beispiel #3
0
  /**
   * <strong>[11.8.4] String Literals</strong>
   *
   * <pre>
   * StringLiteral ::
   *     " DoubleStringCharacters<sub>opt</sub> "
   *     ' SingleStringCharacters<sub>opt</sub> '
   * DoubleStringCharacters ::
   *     DoubleStringCharacter DoubleStringCharacters<sub>opt</sub>
   * SingleStringCharacters ::
   *     SingleStringCharacter SingleStringCharacters<sub>opt</sub>
   * DoubleStringCharacter ::
   *     SourceCharacter but not one of " or \ or LineTerminator
   *     \ EscapeSequence
   *     LineContinuation
   * SingleStringCharacter ::
   *     SourceCharacter but not one of ' or \ or LineTerminator
   *     \ EscapeSequence
   *     LineContinuation
   * LineContinuation ::
   *     \ LineTerminatorSequence
   * EscapeSequence ::
   *     CharacterEscapeSequence
   *     0  [lookahead &#x2209; DecimalDigit]
   *     HexEscapeSequence
   *     UnicodeEscapeSequence
   * CharacterEscapeSequence ::
   *     SingleEscapeCharacter
   *     NonEscapeCharacter
   * SingleEscapeCharacter ::  one of
   *     ' "  \  b f n r t v
   * NonEscapeCharacter ::
   *     SourceCharacter but not one of EscapeCharacter or LineTerminator
   * EscapeCharacter ::
   *     SingleEscapeCharacter
   *     DecimalDigit
   *     x
   *     u
   * HexEscapeSequence ::
   *     x HexDigit HexDigit
   * UnicodeEscapeSequence ::
   *     u HexDigit HexDigit HexDigit HexDigit
   *     u{ HexDigits }
   * </pre>
   *
   * <strong>[B.1.2] String Literals</strong>
   *
   * <pre>
   * EscapeSequence ::
   *     CharacterEscapeSequence
   *     OctalEscapeSequence
   *     HexEscapeSequence
   *     UnicodeEscapeSequence
   * </pre>
   */
  private Token readString(int quoteChar) {
    assert quoteChar == '"' || quoteChar == '\'';

    final int EOF = TokenStreamInput.EOF;
    TokenStreamInput input = this.input;
    int start = input.position();
    StringBuffer buffer = this.buffer();
    hasEscape = false;
    for (; ; ) {
      int c = input.get();
      if (c == EOF) {
        throw eofError(Messages.Key.UnterminatedStringLiteral);
      }
      if (c == quoteChar) {
        buffer.add(input.range(start, input.position() - 1));
        break;
      }
      if (isLineTerminator(c)) {
        throw error(Messages.Key.UnterminatedStringLiteral);
      }
      if (c != '\\') {
        continue;
      }
      buffer.add(input.range(start, input.position() - 1));
      hasEscape = true;
      c = input.get();
      if (isLineTerminator(c)) {
        // line continuation
        if (c == '\r' && match('\n')) {
          // \r\n sequence
        }
        incrementLine();
        start = input.position();
        continue;
      }
      // escape sequences
      switch (c) {
        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 = '\u000B';
          break;
        case 'x':
          c = (hexDigit(input.get()) << 4) | hexDigit(input.get());
          if (c < 0) {
            throw error(Messages.Key.InvalidHexEscape);
          }
          break;
        case 'u':
          c = readUnicode();
          break;
        case '0':
          if (isDecimalDigit(input.peek(0))) {
            if (!parser.isEnabled(CompatibilityOption.OctalEscapeSequence)) {
              throw error(Messages.Key.InvalidNULLEscape);
            }
            c = readOctalEscape(c);
          } else {
            c = '\0';
          }
          break;
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
          if (!parser.isEnabled(CompatibilityOption.OctalEscapeSequence)) {
            throw error(Messages.Key.StrictModeOctalEscapeSequence);
          }
          c = readOctalEscape(c);
          break;
        case '8':
        case '9':
          // FIXME: spec bug - undefined behaviour for \8 and \9
          if (!parser.isEnabled(CompatibilityOption.OctalEscapeSequence)) {
            throw error(Messages.Key.StrictModeOctalEscapeSequence);
          }
          // fall-through
        case '"':
        case '\'':
        case '\\':
        default:
          // fall-through
      }
      buffer.addCodepoint(c);
      start = input.position();
    }

    return Token.STRING;
  }