[token] Make sure we can simply range-check IsAnyIdentifier
This CL additionally uses IsInRange for token range checks. That only uses one branch rather than two. Change-Id: I52c6759ba195b55cb50c2ce9afbdc9b397495633 Reviewed-on: https://chromium-review.googlesource.com/1193875 Reviewed-by: Igor Sheludko <ishell@chromium.org> Commit-Queue: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/master@{#55494}
This commit is contained in:
parent
1a8f24d84b
commit
dd6290d189
@ -29,12 +29,6 @@ inline bool IsLineFeed(uc32 c) {
|
||||
}
|
||||
|
||||
|
||||
inline bool IsInRange(int value, int lower_limit, int higher_limit) {
|
||||
DCHECK(lower_limit <= higher_limit);
|
||||
return static_cast<unsigned int>(value - lower_limit) <=
|
||||
static_cast<unsigned int>(higher_limit - lower_limit);
|
||||
}
|
||||
|
||||
inline bool IsAsciiIdentifier(uc32 c) {
|
||||
return IsAlphaNumeric(c) || c == '$' || c == '_';
|
||||
}
|
||||
|
@ -769,14 +769,7 @@ class ParserBase {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_any_identifier(Token::Value token) {
|
||||
return token == Token::IDENTIFIER || token == Token::ENUM ||
|
||||
token == Token::AWAIT || token == Token::ASYNC ||
|
||||
token == Token::ESCAPED_STRICT_RESERVED_WORD ||
|
||||
token == Token::FUTURE_STRICT_RESERVED_WORD || token == Token::LET ||
|
||||
token == Token::STATIC || token == Token::YIELD;
|
||||
}
|
||||
bool peek_any_identifier() { return is_any_identifier(peek()); }
|
||||
bool peek_any_identifier() { return Token::IsAnyIdentifier(peek()); }
|
||||
|
||||
bool CheckContextualKeyword(Token::Value token) {
|
||||
if (PeekContextualKeyword(token)) {
|
||||
@ -997,7 +990,7 @@ class ParserBase {
|
||||
}
|
||||
|
||||
bool IsValidArrowFormalParametersStart(Token::Value token) {
|
||||
return is_any_identifier(token) || token == Token::LPAREN;
|
||||
return Token::IsAnyIdentifier(token) || token == Token::LPAREN;
|
||||
}
|
||||
|
||||
void ValidateArrowFormalParameters(ExpressionT expr,
|
||||
|
@ -29,7 +29,6 @@ const uint8_t Token::string_length_[NUM_TOKENS] = {TOKEN_LIST(T, T, T)};
|
||||
const int8_t Token::precedence_[NUM_TOKENS] = {TOKEN_LIST(T, T, T)};
|
||||
#undef T
|
||||
|
||||
|
||||
#define KT(a, b, c) 'T',
|
||||
#define KK(a, b, c) 'K',
|
||||
#define KC(a, b, c) 'C',
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "src/base/logging.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -32,6 +33,27 @@ namespace internal {
|
||||
|
||||
#define IGNORE_TOKEN(name, string, precedence)
|
||||
|
||||
/* Binary operators sorted by precedence */
|
||||
#define BINARY_OP_TOKEN_LIST(T, E) \
|
||||
E(T, BIT_OR, "|", 6) \
|
||||
E(T, BIT_XOR, "^", 7) \
|
||||
E(T, BIT_AND, "&", 8) \
|
||||
E(T, SHL, "<<", 11) \
|
||||
E(T, SAR, ">>", 11) \
|
||||
E(T, SHR, ">>>", 11) \
|
||||
E(T, ADD, "+", 12) \
|
||||
E(T, SUB, "-", 12) \
|
||||
E(T, MUL, "*", 13) \
|
||||
E(T, DIV, "/", 13) \
|
||||
E(T, MOD, "%", 13) \
|
||||
E(T, EXP, "**", 14)
|
||||
|
||||
#define EXPAND_BINOP_ASSIGN_TOKEN(T, name, string, precedence) \
|
||||
T(ASSIGN_##name, string "=", 2)
|
||||
|
||||
#define EXPAND_BINOP_TOKEN(T, name, string, precedence) \
|
||||
T(name, string, precedence)
|
||||
|
||||
#define TOKEN_LIST(T, K, C) \
|
||||
/* End of source indicator. */ \
|
||||
T(EOS, "EOS", 0) \
|
||||
@ -57,18 +79,7 @@ namespace internal {
|
||||
/* contiguous and sorted in the same order! */ \
|
||||
T(INIT, "=init", 2) /* AST-use only. */ \
|
||||
T(ASSIGN, "=", 2) \
|
||||
T(ASSIGN_BIT_OR, "|=", 2) \
|
||||
T(ASSIGN_BIT_XOR, "^=", 2) \
|
||||
T(ASSIGN_BIT_AND, "&=", 2) \
|
||||
T(ASSIGN_SHL, "<<=", 2) \
|
||||
T(ASSIGN_SAR, ">>=", 2) \
|
||||
T(ASSIGN_SHR, ">>>=", 2) \
|
||||
T(ASSIGN_ADD, "+=", 2) \
|
||||
T(ASSIGN_SUB, "-=", 2) \
|
||||
T(ASSIGN_MUL, "*=", 2) \
|
||||
T(ASSIGN_DIV, "/=", 2) \
|
||||
T(ASSIGN_MOD, "%=", 2) \
|
||||
T(ASSIGN_EXP, "**=", 2) \
|
||||
BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_ASSIGN_TOKEN) \
|
||||
\
|
||||
/* Binary operators sorted by precedence. */ \
|
||||
/* IsBinaryOp() relies on this block of enum values */ \
|
||||
@ -76,25 +87,14 @@ namespace internal {
|
||||
T(COMMA, ",", 1) \
|
||||
T(OR, "||", 4) \
|
||||
T(AND, "&&", 5) \
|
||||
T(BIT_OR, "|", 6) \
|
||||
T(BIT_XOR, "^", 7) \
|
||||
T(BIT_AND, "&", 8) \
|
||||
T(SHL, "<<", 11) \
|
||||
T(SAR, ">>", 11) \
|
||||
T(SHR, ">>>", 11) \
|
||||
T(ADD, "+", 12) \
|
||||
T(SUB, "-", 12) \
|
||||
T(MUL, "*", 13) \
|
||||
T(DIV, "/", 13) \
|
||||
T(MOD, "%", 13) \
|
||||
T(EXP, "**", 14) \
|
||||
BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_TOKEN) \
|
||||
\
|
||||
/* Compare operators sorted by precedence. */ \
|
||||
/* IsCompareOp() relies on this block of enum values */ \
|
||||
/* being contiguous and sorted in the same order! */ \
|
||||
T(EQ, "==", 9) \
|
||||
T(NE, "!=", 9) \
|
||||
T(EQ_STRICT, "===", 9) \
|
||||
T(NE, "!=", 9) \
|
||||
T(NE_STRICT, "!==", 9) \
|
||||
T(LT, "<", 10) \
|
||||
T(GT, ">", 10) \
|
||||
@ -151,28 +151,27 @@ namespace internal {
|
||||
\
|
||||
/* Identifiers (not keywords or future reserved words). */ \
|
||||
T(IDENTIFIER, nullptr, 0) \
|
||||
T(PRIVATE_NAME, nullptr, 0) \
|
||||
\
|
||||
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \
|
||||
T(FUTURE_STRICT_RESERVED_WORD, nullptr, 0) \
|
||||
K(ASYNC, "async", 0) \
|
||||
/* `await` is a reserved word in module code only */ \
|
||||
K(AWAIT, "await", 0) \
|
||||
K(CLASS, "class", 0) \
|
||||
K(CONST, "const", 0) \
|
||||
K(ENUM, "enum", 0) \
|
||||
K(EXPORT, "export", 0) \
|
||||
K(EXTENDS, "extends", 0) \
|
||||
K(IMPORT, "import", 0) \
|
||||
K(LET, "let", 0) \
|
||||
K(STATIC, "static", 0) \
|
||||
K(YIELD, "yield", 0) \
|
||||
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \
|
||||
T(FUTURE_STRICT_RESERVED_WORD, nullptr, 0) \
|
||||
T(ESCAPED_STRICT_RESERVED_WORD, nullptr, 0) \
|
||||
K(CLASS, "class", 0) \
|
||||
K(CONST, "const", 0) \
|
||||
K(EXPORT, "export", 0) \
|
||||
K(EXTENDS, "extends", 0) \
|
||||
K(IMPORT, "import", 0) \
|
||||
K(SUPER, "super", 0) \
|
||||
T(PRIVATE_NAME, nullptr, 0) \
|
||||
\
|
||||
/* Illegal token - not able to scan. */ \
|
||||
T(ILLEGAL, "ILLEGAL", 0) \
|
||||
T(ESCAPED_KEYWORD, nullptr, 0) \
|
||||
T(ESCAPED_STRICT_RESERVED_WORD, nullptr, 0) \
|
||||
\
|
||||
/* Scanner-internal use only. */ \
|
||||
T(WHITESPACE, nullptr, 0) \
|
||||
@ -243,70 +242,41 @@ class Token {
|
||||
}
|
||||
|
||||
static bool IsAssignmentOp(Value tok) {
|
||||
return INIT <= tok && tok <= ASSIGN_EXP;
|
||||
return IsInRange(tok, INIT, ASSIGN_EXP);
|
||||
}
|
||||
|
||||
static bool IsBinaryOp(Value op) { return COMMA <= op && op <= EXP; }
|
||||
static bool IsBinaryOp(Value op) { return IsInRange(op, COMMA, EXP); }
|
||||
|
||||
static bool IsCompareOp(Value op) {
|
||||
return EQ <= op && op <= IN;
|
||||
}
|
||||
static bool IsCompareOp(Value op) { return IsInRange(op, EQ, IN); }
|
||||
|
||||
static bool IsOrderedRelationalCompareOp(Value op) {
|
||||
return op == LT || op == LTE || op == GT || op == GTE;
|
||||
return IsInRange(op, LT, GTE);
|
||||
}
|
||||
|
||||
static bool IsEqualityOp(Value op) {
|
||||
return op == EQ || op == EQ_STRICT;
|
||||
static bool IsEqualityOp(Value op) { return IsInRange(op, EQ, EQ_STRICT); }
|
||||
|
||||
static bool IsAnyIdentifier(Value tok) {
|
||||
return IsInRange(tok, IDENTIFIER, ESCAPED_STRICT_RESERVED_WORD);
|
||||
}
|
||||
|
||||
static Value BinaryOpForAssignment(Value op) {
|
||||
DCHECK(IsAssignmentOp(op));
|
||||
switch (op) {
|
||||
case Token::ASSIGN_BIT_OR:
|
||||
return Token::BIT_OR;
|
||||
case Token::ASSIGN_BIT_XOR:
|
||||
return Token::BIT_XOR;
|
||||
case Token::ASSIGN_BIT_AND:
|
||||
return Token::BIT_AND;
|
||||
case Token::ASSIGN_SHL:
|
||||
return Token::SHL;
|
||||
case Token::ASSIGN_SAR:
|
||||
return Token::SAR;
|
||||
case Token::ASSIGN_SHR:
|
||||
return Token::SHR;
|
||||
case Token::ASSIGN_ADD:
|
||||
return Token::ADD;
|
||||
case Token::ASSIGN_SUB:
|
||||
return Token::SUB;
|
||||
case Token::ASSIGN_MUL:
|
||||
return Token::MUL;
|
||||
case Token::ASSIGN_DIV:
|
||||
return Token::DIV;
|
||||
case Token::ASSIGN_MOD:
|
||||
return Token::MOD;
|
||||
case Token::ASSIGN_EXP:
|
||||
return Token::EXP;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
DCHECK(IsInRange(op, ASSIGN_BIT_OR, ASSIGN_EXP));
|
||||
Value result = static_cast<Value>(op - ASSIGN_BIT_OR + BIT_OR);
|
||||
DCHECK(IsBinaryOp(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool IsBitOp(Value op) {
|
||||
return (BIT_OR <= op && op <= SHR) || op == BIT_NOT;
|
||||
return IsInRange(op, BIT_OR, SHR) || op == BIT_NOT;
|
||||
}
|
||||
|
||||
static bool IsUnaryOp(Value op) {
|
||||
return (NOT <= op && op <= VOID) || op == ADD || op == SUB;
|
||||
return IsInRange(op, NOT, VOID) || IsInRange(op, ADD, SUB);
|
||||
}
|
||||
|
||||
static bool IsCountOp(Value op) {
|
||||
return op == INC || op == DEC;
|
||||
}
|
||||
static bool IsCountOp(Value op) { return IsInRange(op, INC, DEC); }
|
||||
|
||||
static bool IsShiftOp(Value op) {
|
||||
return (SHL <= op) && (op <= SHR);
|
||||
}
|
||||
static bool IsShiftOp(Value op) { return IsInRange(op, SHL, SHR); }
|
||||
|
||||
// Returns a string corresponding to the JS token string
|
||||
// (.e., "<" for the token LT) or nullptr if the token doesn't
|
||||
|
@ -56,6 +56,14 @@ inline bool CStringEquals(const char* s1, const char* s2) {
|
||||
return (s1 == s2) || (s1 != nullptr && s2 != nullptr && strcmp(s1, s2) == 0);
|
||||
}
|
||||
|
||||
// Checks if value is in range [lower_limit, higher_limit] using a single
|
||||
// branch.
|
||||
inline bool IsInRange(int value, int lower_limit, int higher_limit) {
|
||||
DCHECK_LE(lower_limit, higher_limit);
|
||||
return static_cast<unsigned int>(value - lower_limit) <=
|
||||
static_cast<unsigned int>(higher_limit - lower_limit);
|
||||
}
|
||||
|
||||
// X must be a power of 2. Returns the number of trailing zeros.
|
||||
template <typename T,
|
||||
typename = typename std::enable_if<std::is_integral<T>::value>::type>
|
||||
|
@ -71,6 +71,212 @@ void MockUseCounterCallback(v8::Isolate* isolate,
|
||||
|
||||
} // namespace
|
||||
|
||||
bool TokenIsAnyIdentifier(Token::Value tok) {
|
||||
switch (tok) {
|
||||
case Token::IDENTIFIER:
|
||||
case Token::ASYNC:
|
||||
case Token::AWAIT:
|
||||
case Token::ENUM:
|
||||
case Token::LET:
|
||||
case Token::STATIC:
|
||||
case Token::YIELD:
|
||||
case Token::FUTURE_STRICT_RESERVED_WORD:
|
||||
case Token::ESCAPED_STRICT_RESERVED_WORD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AnyIdentifierToken) {
|
||||
for (int i = 0; i < Token::NUM_TOKENS; i++) {
|
||||
Token::Value tok = static_cast<Token::Value>(i);
|
||||
CHECK_EQ(TokenIsAnyIdentifier(tok), Token::IsAnyIdentifier(tok));
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenIsAssignmentOp(Token::Value tok) {
|
||||
switch (tok) {
|
||||
case Token::INIT:
|
||||
case Token::ASSIGN:
|
||||
#define T(name, string, precedence) case Token::name:
|
||||
BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_ASSIGN_TOKEN)
|
||||
#undef T
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AssignmentOp) {
|
||||
for (int i = 0; i < Token::NUM_TOKENS; i++) {
|
||||
Token::Value tok = static_cast<Token::Value>(i);
|
||||
CHECK_EQ(TokenIsAssignmentOp(tok), Token::IsAssignmentOp(tok));
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenIsBinaryOp(Token::Value tok) {
|
||||
switch (tok) {
|
||||
case Token::COMMA:
|
||||
case Token::OR:
|
||||
case Token::AND:
|
||||
#define T(name, string, precedence) case Token::name:
|
||||
BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_TOKEN)
|
||||
#undef T
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BinaryOp) {
|
||||
for (int i = 0; i < Token::NUM_TOKENS; i++) {
|
||||
Token::Value tok = static_cast<Token::Value>(i);
|
||||
CHECK_EQ(TokenIsBinaryOp(tok), Token::IsBinaryOp(tok));
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenIsCompareOp(Token::Value tok) {
|
||||
switch (tok) {
|
||||
case Token::EQ:
|
||||
case Token::EQ_STRICT:
|
||||
case Token::NE:
|
||||
case Token::NE_STRICT:
|
||||
case Token::LT:
|
||||
case Token::GT:
|
||||
case Token::LTE:
|
||||
case Token::GTE:
|
||||
case Token::INSTANCEOF:
|
||||
case Token::IN:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CompareOp) {
|
||||
for (int i = 0; i < Token::NUM_TOKENS; i++) {
|
||||
Token::Value tok = static_cast<Token::Value>(i);
|
||||
CHECK_EQ(TokenIsCompareOp(tok), Token::IsCompareOp(tok));
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenIsOrderedRelationalCompareOp(Token::Value tok) {
|
||||
switch (tok) {
|
||||
case Token::LT:
|
||||
case Token::GT:
|
||||
case Token::LTE:
|
||||
case Token::GTE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IsOrderedRelationalCompareOp) {
|
||||
for (int i = 0; i < Token::NUM_TOKENS; i++) {
|
||||
Token::Value tok = static_cast<Token::Value>(i);
|
||||
CHECK_EQ(TokenIsOrderedRelationalCompareOp(tok),
|
||||
Token::IsOrderedRelationalCompareOp(tok));
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenIsEqualityOp(Token::Value tok) {
|
||||
switch (tok) {
|
||||
case Token::EQ:
|
||||
case Token::EQ_STRICT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IsEqualityOp) {
|
||||
for (int i = 0; i < Token::NUM_TOKENS; i++) {
|
||||
Token::Value tok = static_cast<Token::Value>(i);
|
||||
CHECK_EQ(TokenIsEqualityOp(tok), Token::IsEqualityOp(tok));
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenIsBitOp(Token::Value tok) {
|
||||
switch (tok) {
|
||||
case Token::BIT_OR:
|
||||
case Token::BIT_XOR:
|
||||
case Token::BIT_AND:
|
||||
case Token::SHL:
|
||||
case Token::SAR:
|
||||
case Token::SHR:
|
||||
case Token::BIT_NOT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IsBitOp) {
|
||||
for (int i = 0; i < Token::NUM_TOKENS; i++) {
|
||||
Token::Value tok = static_cast<Token::Value>(i);
|
||||
CHECK_EQ(TokenIsBitOp(tok), Token::IsBitOp(tok));
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenIsUnaryOp(Token::Value tok) {
|
||||
switch (tok) {
|
||||
case Token::NOT:
|
||||
case Token::BIT_NOT:
|
||||
case Token::DELETE:
|
||||
case Token::TYPEOF:
|
||||
case Token::VOID:
|
||||
case Token::ADD:
|
||||
case Token::SUB:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IsUnaryOp) {
|
||||
for (int i = 0; i < Token::NUM_TOKENS; i++) {
|
||||
Token::Value tok = static_cast<Token::Value>(i);
|
||||
CHECK_EQ(TokenIsUnaryOp(tok), Token::IsUnaryOp(tok));
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenIsCountOp(Token::Value tok) {
|
||||
switch (tok) {
|
||||
case Token::INC:
|
||||
case Token::DEC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IsCountOp) {
|
||||
for (int i = 0; i < Token::NUM_TOKENS; i++) {
|
||||
Token::Value tok = static_cast<Token::Value>(i);
|
||||
CHECK_EQ(TokenIsCountOp(tok), Token::IsCountOp(tok));
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenIsShiftOp(Token::Value tok) {
|
||||
switch (tok) {
|
||||
case Token::SHL:
|
||||
case Token::SAR:
|
||||
case Token::SHR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IsShiftOp) {
|
||||
for (int i = 0; i < Token::NUM_TOKENS; i++) {
|
||||
Token::Value tok = static_cast<Token::Value>(i);
|
||||
CHECK_EQ(TokenIsShiftOp(tok), Token::IsShiftOp(tok));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ScanKeywords) {
|
||||
struct KeywordToken {
|
||||
const char* keyword;
|
||||
|
Loading…
Reference in New Issue
Block a user