scan method

Token scan()

Implementation

Token scan() {
  seenLinebreak = false;
  scanLoop:
  while (true) {
    int x = current;
    tokenStart = index;
    tokenLine = currentLine;
    switch (x) {
      case char.NULL:
        return emitToken(Token
            .EOF); // (will produce infinite EOF tokens if pressed for more tokens)

      case char
          .SPACE: // Note: Exotic whitespace symbols are handled in the default clause.
      case char.TAB:
        ++index;
        continue;

      case char.CR:
        seenLinebreak = true;
        ++currentLine;
        x = next();
        if (x == char.LF) {
          ++index; // count as single linebreak
        }
        continue;

      case char.LF:
      case char.LS:
      case char.PS:
        seenLinebreak = true;
        ++currentLine;
        ++index;
        continue;

      case char.SLASH:
        x = next(); // consume "/"
        if (x == char.SLASH) {
          // "//" comment
          x = next();
          while (!isEOL(x)) {
            x = next();
          }
          continue; // line number will be when reading the LF,CR,LS,PS or EOF
        }
        if (x == char.STAR) {
          // "/*" comment
          x = current;
          while (true) {
            switch (x) {
              case char.STAR:
                x = next();
                if (x == char.SLASH) {
                  ++index; // skip final slash
                  continue scanLoop; // Finished block comment.
                }
                break;
              case char.NULL:
                fail("Unterminated block comment");
                break;
              case char.CR:
                ++currentLine;
                x = next();
                if (x == char.LF) {
                  x = next(); // count as one line break
                }
                break;
              case char.LS:
              case char.LF:
              case char.PS:
                ++currentLine;
                x = next();
                break;
              default:
                x = next();
            }
          }
        }
        // parser will recognize these as potential regexp heads
        if (x == char.EQ) {
          // "/="
          ++index;
          return emitToken(Token.ASSIGN, '/=');
        }
        return emitToken(Token.BINARY, '/')
          ..binaryPrecedence = Precedence.MULTIPLICATIVE;

      case char.PLUS:
        x = next();
        if (x == char.PLUS) {
          ++index;
          return emitToken(Token.UPDATE, '++');
        }
        if (x == char.EQ) {
          ++index;
          return emitToken(Token.ASSIGN, '+=');
        }
        return emitToken(Token.UNARY, '+')
          ..binaryPrecedence = Precedence.ADDITIVE;

      case char.MINUS:
        x = next();
        if (x == char.MINUS) {
          ++index;
          return emitToken(Token.UPDATE, '--');
        }
        if (x == char.EQ) {
          ++index;
          return emitToken(Token.ASSIGN, '-=');
        }
        return emitToken(Token.UNARY, '-')
          ..binaryPrecedence = Precedence.ADDITIVE;

      case char.STAR:
        x = next();
        if (x == char.EQ) {
          ++index;
          return emitToken(Token.ASSIGN, '*=');
        }
        return emitToken(Token.BINARY, '*')
          ..binaryPrecedence = Precedence.MULTIPLICATIVE;

      case char.PERCENT:
        x = next();
        if (x == char.EQ) {
          ++index;
          return emitToken(Token.ASSIGN, '%=');
        }
        return emitToken(Token.BINARY, '%')
          ..binaryPrecedence = Precedence.MULTIPLICATIVE;

      case char.LT:
        x = next();
        if (x == char.LT) {
          x = next();
          if (x == char.EQ) {
            ++index;
            return emitToken(Token.ASSIGN, '<<=');
          }
          return emitToken(Token.BINARY, '<<')
            ..binaryPrecedence = Precedence.SHIFT;
        }
        if (x == char.EQ) {
          ++index;
          return emitToken(Token.BINARY, '<=')
            ..binaryPrecedence = Precedence.RELATIONAL;
        }
        return emitToken(Token.BINARY, '<')
          ..binaryPrecedence = Precedence.RELATIONAL;

      case char.GT:
        x = next();
        if (x == char.GT) {
          x = next();
          if (x == char.GT) {
            x = next();
            if (x == char.EQ) {
              ++index;
              return emitToken(Token.ASSIGN, '>>>=');
            }
            return emitToken(Token.BINARY, '>>>')
              ..binaryPrecedence = Precedence.SHIFT;
          }
          if (x == char.EQ) {
            ++index;
            return emitToken(Token.ASSIGN, '>>=');
          }
          return emitToken(Token.BINARY, '>>')
            ..binaryPrecedence = Precedence.SHIFT;
        }
        if (x == char.EQ) {
          ++index;
          return emitToken(Token.BINARY, '>=')
            ..binaryPrecedence = Precedence.RELATIONAL;
        }
        return emitToken(Token.BINARY, '>')
          ..binaryPrecedence = Precedence.RELATIONAL;

      case char.HAT:
        x = next();
        if (x == char.EQ) {
          ++index;
          return emitToken(Token.ASSIGN, '^=');
        }
        return emitToken(Token.BINARY, '^')
          ..binaryPrecedence = Precedence.BITWISE_XOR;

      case char.TILDE:
        ++index;
        return emitToken(Token.UNARY, '~');

      case char.BAR:
        x = next();
        if (x == char.BAR) {
          ++index;
          return emitToken(Token.BINARY, '||')
            ..binaryPrecedence = Precedence.LOGICAL_OR;
        }
        if (x == char.EQ) {
          ++index;
          return emitToken(Token.ASSIGN, '|=');
        }
        return emitToken(Token.BINARY, '|')
          ..binaryPrecedence = Precedence.BITWISE_OR;

      case char.AMPERSAND:
        x = next();
        if (x == char.AMPERSAND) {
          ++index;
          return emitToken(Token.BINARY, '&&')
            ..binaryPrecedence = Precedence.LOGICAL_AND;
        }
        if (x == char.EQ) {
          ++index;
          return emitToken(Token.ASSIGN, '&=');
        }
        return emitToken(Token.BINARY, '&')
          ..binaryPrecedence = Precedence.BITWISE_AND;

      case char.EQ:
        x = next();
        if (x == char.EQ) {
          x = next();
          if (x == char.EQ) {
            ++index;
            return emitToken(Token.BINARY, '===')
              ..binaryPrecedence = Precedence.EQUALITY;
          }
          return emitToken(Token.BINARY, '==')
            ..binaryPrecedence = Precedence.EQUALITY;
        }
        return emitToken(Token.ASSIGN, '=');

      case char.BANG:
        x = next();
        if (x == char.EQ) {
          x = next();
          if (x == char.EQ) {
            ++index;
            return emitToken(Token.BINARY, '!==')
              ..binaryPrecedence = Precedence.EQUALITY;
          }
          return emitToken(Token.BINARY, '!=')
            ..binaryPrecedence = Precedence.EQUALITY;
        }
        return emitToken(Token.UNARY, '!');

      case char.DOT:
        x = next();
        if (isDigit(x)) {
          return scanDecimalPart(x);
        }
        return emitToken(Token.DOT);

      case char.SQUOTE:
      case char.DQUOTE:
      case char.BACKTICK:
        return scanStringLiteral(x);

      case char.LPAREN:
      case char.RPAREN:
      case char.LBRACKET:
      case char.RBRACKET:
      case char.LBRACE:
      case char.RBRACE:
      case char.COMMA:
      case char.COLON:
      case char.SEMICOLON:
      case char.QUESTION:
        ++index;
        return emitToken(x);

      case char.BACKSLASH:
        return scanComplexName(x);

      default:
        if (isNameStart(x)) return scanName(x);
        if (isDigit(x)) return scanNumber(x);
        if (isWhitespace(x)) {
          ++index;
          continue;
        }
        fail(
            "Unrecognized character: '${new String.fromCharCode(x)}' (UTF+${x.toRadixString(16)})");
    }
  }
}