Commit d62ec0d8 authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[scanner] Separate token scanning from TokenDesc management

Change-Id: I6fe237d4aec3745e993a65ddf31f5fafc3ce175d
Reviewed-on: https://chromium-review.googlesource.com/1193368Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55462}
parent 573ed1ef
......@@ -5,12 +5,150 @@
#ifndef V8_PARSING_SCANNER_INL_H_
#define V8_PARSING_SCANNER_INL_H_
#include "src/char-predicates-inl.h"
#include "src/parsing/scanner.h"
#include "src/unicode-cache-inl.h"
namespace v8 {
namespace internal {
// Make sure tokens are stored as a single byte.
STATIC_ASSERT(sizeof(Token::Value) == 1);
// Table of one-character tokens, by character (0x00..0x7F only).
// clang-format off
static const Token::Value one_char_tokens[] = {
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::LPAREN, // 0x28
Token::RPAREN, // 0x29
Token::ILLEGAL,
Token::ILLEGAL,
Token::COMMA, // 0x2C
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::COLON, // 0x3A
Token::SEMICOLON, // 0x3B
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::CONDITIONAL, // 0x3F
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::LBRACK, // 0x5B
Token::ILLEGAL,
Token::RBRACK, // 0x5D
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::LBRACE, // 0x7B
Token::ILLEGAL,
Token::RBRACE, // 0x7D
Token::BIT_NOT, // 0x7E
Token::ILLEGAL
};
// clang-format on
V8_INLINE Token::Value Scanner::SkipWhiteSpace() {
int start_position = source_pos();
......@@ -37,6 +175,175 @@ V8_INLINE Token::Value Scanner::SkipWhiteSpace() {
return Token::WHITESPACE;
}
V8_INLINE Token::Value Scanner::ScanSingleToken() {
Token::Value token;
do {
scan_target().location.beg_pos = source_pos();
if (static_cast<unsigned>(c0_) <= 0x7F) {
Token::Value token = one_char_tokens[c0_];
if (token != Token::ILLEGAL) {
Advance();
return token;
}
}
switch (c0_) {
case '"':
case '\'':
return ScanString();
case '<':
// < <= << <<= <!--
Advance();
if (c0_ == '=') return Select(Token::LTE);
if (c0_ == '<') return Select('=', Token::ASSIGN_SHL, Token::SHL);
if (c0_ == '!') {
token = ScanHtmlComment();
continue;
}
return Token::LT;
case '>':
// > >= >> >>= >>> >>>=
Advance();
if (c0_ == '=') return Select(Token::GTE);
if (c0_ == '>') {
// >> >>= >>> >>>=
Advance();
if (c0_ == '=') return Select(Token::ASSIGN_SAR);
if (c0_ == '>') return Select('=', Token::ASSIGN_SHR, Token::SHR);
return Token::SAR;
}
return Token::GT;
case '=':
// = == === =>
Advance();
if (c0_ == '=') return Select('=', Token::EQ_STRICT, Token::EQ);
if (c0_ == '>') return Select(Token::ARROW);
return Token::ASSIGN;
case '!':
// ! != !==
Advance();
if (c0_ == '=') return Select('=', Token::NE_STRICT, Token::NE);
return Token::NOT;
case '+':
// + ++ +=
Advance();
if (c0_ == '+') return Select(Token::INC);
if (c0_ == '=') return Select(Token::ASSIGN_ADD);
return Token::ADD;
case '-':
// - -- --> -=
Advance();
if (c0_ == '-') {
Advance();
if (c0_ == '>' && scan_target().after_line_terminator) {
// For compatibility with SpiderMonkey, we skip lines that
// start with an HTML comment end '-->'.
token = SkipSingleHTMLComment();
continue;
}
return Token::DEC;
}
if (c0_ == '=') return Select(Token::ASSIGN_SUB);
return Token::SUB;
case '*':
// * *=
Advance();
if (c0_ == '*') return Select('=', Token::ASSIGN_EXP, Token::EXP);
if (c0_ == '=') return Select(Token::ASSIGN_MUL);
return Token::MUL;
case '%':
// % %=
return Select('=', Token::ASSIGN_MOD, Token::MOD);
case '/':
// / // /* /=
Advance();
if (c0_ == '/') {
uc32 c = Peek();
if (c == '#' || c == '@') {
Advance();
Advance();
token = SkipSourceURLComment();
continue;
}
token = SkipSingleLineComment();
continue;
}
if (c0_ == '*') {
token = SkipMultiLineComment();
continue;
}
if (c0_ == '=') return Select(Token::ASSIGN_DIV);
return Token::DIV;
case '&':
// & && &=
Advance();
if (c0_ == '&') return Select(Token::AND);
if (c0_ == '=') return Select(Token::ASSIGN_BIT_AND);
return Token::BIT_AND;
case '|':
// | || |=
Advance();
if (c0_ == '|') return Select(Token::OR);
if (c0_ == '=') return Select(Token::ASSIGN_BIT_OR);
return Token::BIT_OR;
case '^':
// ^ ^=
return Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
case '.':
// . Number
Advance();
if (IsDecimalDigit(c0_)) return ScanNumber(true);
if (c0_ == '.') {
if (Peek() == '.') {
Advance();
Advance();
return Token::ELLIPSIS;
}
}
return Token::PERIOD;
case '`':
Advance();
return ScanTemplateSpan();
case '#':
return ScanPrivateName();
default:
if (unicode_cache_->IsIdentifierStart(c0_) ||
(CombineSurrogatePair() &&
unicode_cache_->IsIdentifierStart(c0_))) {
Token::Value token = ScanIdentifierOrKeyword();
if (!Token::IsContextualKeyword(token)) return token;
scan_target().contextual_token = token;
return Token::IDENTIFIER;
}
if (IsDecimalDigit(c0_)) return ScanNumber(false);
if (c0_ == kEndOfInput) return Token::EOS;
token = SkipWhiteSpace();
continue;
}
// Continue scanning for tokens as long as we're just skipping whitespace.
} while (token == Token::WHITESPACE);
return token;
}
} // namespace internal
} // namespace v8
......
......@@ -11,7 +11,6 @@
#include <cmath>
#include "src/ast/ast-value-factory.h"
#include "src/char-predicates-inl.h"
#include "src/conversions-inl.h"
#include "src/objects/bigint.h"
#include "src/parsing/duplicate-finder.h" // For Scanner::FindSymbol
......@@ -134,7 +133,6 @@ const size_t Scanner::BookmarkScope::kBookmarkWasApplied =
void Scanner::BookmarkScope::Set() {
DCHECK_EQ(bookmark_, kNoBookmark);
DCHECK(!scanner_->HasToken(2));
// The first token is a bit special, since current_ will still be
// uninitialized. In this case, store kBookmarkAtFirstPos and special-case it
......@@ -233,144 +231,6 @@ uc32 Scanner::ScanUnlimitedLengthHexNumber(int max_value, int beg_pos) {
return x;
}
// Ensure that tokens can be stored in a byte.
STATIC_ASSERT(Token::NUM_TOKENS <= 0x100);
// Table of one-character tokens, by character (0x00..0x7F only).
// clang-format off
static const byte one_char_tokens[] = {
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::LPAREN, // 0x28
Token::RPAREN, // 0x29
Token::ILLEGAL,
Token::ILLEGAL,
Token::COMMA, // 0x2C
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::COLON, // 0x3A
Token::SEMICOLON, // 0x3B
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::CONDITIONAL, // 0x3F
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::LBRACK, // 0x5B
Token::ILLEGAL,
Token::RBRACK, // 0x5D
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::ILLEGAL,
Token::LBRACE, // 0x7B
Token::ILLEGAL,
Token::RBRACE, // 0x7D
Token::BIT_NOT, // 0x7E
Token::ILLEGAL
};
// clang-format on
Token::Value Scanner::SkipSingleHTMLComment() {
if (is_module_) {
ReportScannerError(source_pos(), MessageTemplate::kHtmlCommentInModule);
......@@ -496,238 +356,15 @@ Token::Value Scanner::ScanHtmlComment() {
void Scanner::Scan() {
token_end_ = (token_end_ + 1) & kTokenStorageMask;
scan_target().after_line_terminator = (source_pos() == 0);
scan_target().literal_chars.Drop();
scan_target().raw_literal_chars.Drop();
scan_target().contextual_token = Token::UNINITIALIZED;
scan_target().invalid_template_escape_message = MessageTemplate::kNone;
Token::Value token;
Token::Value contextual_token = Token::UNINITIALIZED;
do {
// Remember the position of the next token
scan_target().location.beg_pos = source_pos();
if (static_cast<unsigned>(c0_) <= 0x7F) {
token = static_cast<Token::Value>(one_char_tokens[c0_]);
if (token != Token::ILLEGAL) {
Advance();
break;
}
}
switch (c0_) {
case '"':
case '\'':
token = ScanString();
break;
case '<':
// < <= << <<= <!--
Advance();
if (c0_ == '=') {
token = Select(Token::LTE);
} else if (c0_ == '<') {
token = Select('=', Token::ASSIGN_SHL, Token::SHL);
} else if (c0_ == '!') {
token = ScanHtmlComment();
} else {
token = Token::LT;
}
break;
case '>':
// > >= >> >>= >>> >>>=
Advance();
if (c0_ == '=') {
token = Select(Token::GTE);
} else if (c0_ == '>') {
// >> >>= >>> >>>=
Advance();
if (c0_ == '=') {
token = Select(Token::ASSIGN_SAR);
} else if (c0_ == '>') {
token = Select('=', Token::ASSIGN_SHR, Token::SHR);
} else {
token = Token::SAR;
}
} else {
token = Token::GT;
}
break;
case '=':
// = == === =>
Advance();
if (c0_ == '=') {
token = Select('=', Token::EQ_STRICT, Token::EQ);
} else if (c0_ == '>') {
token = Select(Token::ARROW);
} else {
token = Token::ASSIGN;
}
break;
case '!':
// ! != !==
Advance();
if (c0_ == '=') {
token = Select('=', Token::NE_STRICT, Token::NE);
} else {
token = Token::NOT;
}
break;
case '+':
// + ++ +=
Advance();
if (c0_ == '+') {
token = Select(Token::INC);
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_ADD);
} else {
token = Token::ADD;
}
break;
case '-':
// - -- --> -=
Advance();
if (c0_ == '-') {
Advance();
if (c0_ == '>' && scan_target().after_line_terminator) {
// For compatibility with SpiderMonkey, we skip lines that
// start with an HTML comment end '-->'.
token = SkipSingleHTMLComment();
} else {
token = Token::DEC;
}
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_SUB);
} else {
token = Token::SUB;
}
break;
case '*':
// * *=
Advance();
if (c0_ == '*') {
token = Select('=', Token::ASSIGN_EXP, Token::EXP);
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_MUL);
} else {
token = Token::MUL;
}
break;
case '%':
// % %=
token = Select('=', Token::ASSIGN_MOD, Token::MOD);
break;
case '/':
// / // /* /=
Advance();
if (c0_ == '/') {
uc32 c = Peek();
if (c == '#' || c == '@') {
Advance();
Advance();
token = SkipSourceURLComment();
} else {
token = SkipSingleLineComment();
}
} else if (c0_ == '*') {
token = SkipMultiLineComment();
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_DIV);
} else {
token = Token::DIV;
}
break;
case '&':
// & && &=
Advance();
if (c0_ == '&') {
token = Select(Token::AND);
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_BIT_AND);
} else {
token = Token::BIT_AND;
}
break;
case '|':
// | || |=
Advance();
if (c0_ == '|') {
token = Select(Token::OR);
} else if (c0_ == '=') {
token = Select(Token::ASSIGN_BIT_OR);
} else {
token = Token::BIT_OR;
}
break;
case '^':
// ^ ^=
token = Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
break;
case '.':
// . Number
Advance();
if (IsDecimalDigit(c0_)) {
token = ScanNumber(true);
} else {
token = Token::PERIOD;
if (c0_ == '.') {
if (Peek() == '.') {
Advance();
Advance();
token = Token::ELLIPSIS;
}
}
}
break;
case '`':
Advance();
token = ScanTemplateSpan();
break;
case '#':
token = ScanPrivateName();
break;
default:
if (unicode_cache_->IsIdentifierStart(c0_) ||
(CombineSurrogatePair() &&
unicode_cache_->IsIdentifierStart(c0_))) {
token = ScanIdentifierOrKeyword();
if (Token::IsContextualKeyword(token)) {
contextual_token = token;
token = Token::IDENTIFIER;
}
} else if (IsDecimalDigit(c0_)) {
token = ScanNumber(false);
} else if (c0_ == kEndOfInput) {
token = Token::EOS;
} else {
token = SkipWhiteSpace();
}
break;
}
// Continue scanning for tokens as long as we're just skipping
// whitespace.
} while (token == Token::WHITESPACE);
scan_target().token = ScanSingleToken();
scan_target().location.end_pos = source_pos();
scan_target().token = token;
scan_target().contextual_token = contextual_token;
#ifdef DEBUG
for (TokenDesc& token : token_storage_) {
......
......@@ -237,7 +237,7 @@ class Scanner {
void Initialize();
// Returns the next token and advances input.
Token::Value Next() {
V8_INLINE Token::Value Next() {
// TODO(verwaest): Remove.
if (next().token == Token::EOS) {
next_target().location = current().location;
......@@ -252,7 +252,7 @@ class Scanner {
}
// Returns the token following peek()
Token::Value PeekAhead() {
V8_INLINE Token::Value PeekAhead() {
DCHECK_NE(Token::DIV, next().token);
DCHECK_NE(Token::ASSIGN_DIV, next().token);
DCHECK(HasToken(1));
......@@ -301,6 +301,7 @@ class Scanner {
}
const AstRawString* CurrentSymbol(AstValueFactory* ast_value_factory) const;
const AstRawString* NextSymbol(AstValueFactory* ast_value_factory) const;
const AstRawString* CurrentRawSymbol(
AstValueFactory* ast_value_factory) const;
......@@ -615,7 +616,7 @@ class Scanner {
scan_target().raw_literal_chars.AddChar(c);
}
inline void AddLiteralCharAdvance() {
V8_INLINE void AddLiteralCharAdvance() {
AddLiteralChar(c0_);
Advance();
}
......@@ -735,6 +736,7 @@ class Scanner {
uc32 ScanUnlimitedLengthHexNumber(int max_value, int beg_pos);
// Scans a single JavaScript token.
V8_INLINE Token::Value ScanSingleToken();
void Scan();
V8_INLINE Token::Value SkipWhiteSpace();
......
......@@ -205,13 +205,13 @@ class Token {
public:
// All token values.
#define T(name, string, precedence) name,
enum Value { TOKEN_LIST(T, T, T) NUM_TOKENS };
enum Value : uint8_t { TOKEN_LIST(T, T, T) NUM_TOKENS };
#undef T
// Returns a string corresponding to the C++ token name
// (e.g. "LT" for the token LT).
static const char* Name(Value tok) {
DCHECK(tok < NUM_TOKENS); // tok is unsigned
DCHECK_GT(NUM_TOKENS, tok); // tok is unsigned
return name_[tok];
}
......@@ -312,19 +312,19 @@ class Token {
// (.e., "<" for the token LT) or nullptr if the token doesn't
// have a (unique) string (e.g. an IDENTIFIER).
static const char* String(Value tok) {
DCHECK(tok < NUM_TOKENS); // tok is unsigned.
DCHECK_GT(NUM_TOKENS, tok); // tok is unsigned
return string_[tok];
}
static uint8_t StringLength(Value tok) {
DCHECK(tok < NUM_TOKENS);
DCHECK_GT(NUM_TOKENS, tok); // tok is unsigned
return string_length_[tok];
}
// Returns the precedence > 0 for binary and compare
// operators; returns 0 otherwise.
static int Precedence(Value tok) {
DCHECK(tok < NUM_TOKENS); // tok is unsigned.
DCHECK_GT(NUM_TOKENS, tok); // tok is unsigned
return precedence_[tok];
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment