[parser] Fix escaped contextual keyword handling
Escaped contextual keywords are simply valid identifiers if they do not occur in the context where they are a keyword. Escape sequences of the form \uNNNN or \u{NNNNNN} must be consumed as part of the identifier. If such escaped contextual keywords do occur in a context where they are a keyword, they are a syntax error. In that case we manually check locally whether they are escaped. Bug: v8:6543, v8:6541 Change-Id: I7e1557963883e722310b9078d7d7636ec94aa603 Reviewed-on: https://chromium-review.googlesource.com/c/1473293 Reviewed-by: Leszek Swirski <leszeks@chromium.org> Commit-Queue: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/master@{#59628}
This commit is contained in:
parent
5d1d079538
commit
a94c91ca48
@ -49,14 +49,14 @@ struct PerfectKeywordHashTableEntry {
|
||||
Token::Value value;
|
||||
};
|
||||
enum {
|
||||
TOTAL_KEYWORDS = 47,
|
||||
TOTAL_KEYWORDS = 49,
|
||||
MIN_WORD_LENGTH = 2,
|
||||
MAX_WORD_LENGTH = 10,
|
||||
MIN_HASH_VALUE = 2,
|
||||
MAX_HASH_VALUE = 51
|
||||
MAX_HASH_VALUE = 55
|
||||
};
|
||||
|
||||
/* maximum key range = 50, duplicates = 0 */
|
||||
/* maximum key range = 54, duplicates = 0 */
|
||||
|
||||
class PerfectKeywordHash {
|
||||
private:
|
||||
@ -70,22 +70,22 @@ inline unsigned int PerfectKeywordHash::Hash(const char* str, int len) {
|
||||
DCHECK_LT(str[1], 128);
|
||||
DCHECK_LT(str[0], 128);
|
||||
static const unsigned char asso_values[128] = {
|
||||
52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
|
||||
52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
|
||||
52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
|
||||
52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
|
||||
52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
|
||||
52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
|
||||
52, 8, 2, 6, 0, 0, 9, 52, 21, 0, 52, 52, 36, 40, 0, 3,
|
||||
6, 52, 17, 13, 16, 16, 38, 25, 6, 26, 52, 52, 52, 52, 52, 52};
|
||||
56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
|
||||
56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
|
||||
56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
|
||||
56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
|
||||
56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
|
||||
56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
|
||||
56, 8, 0, 6, 0, 0, 9, 9, 9, 0, 56, 56, 34, 41, 0, 3,
|
||||
6, 56, 19, 10, 13, 16, 39, 26, 37, 36, 56, 56, 56, 56, 56, 56};
|
||||
return len + asso_values[static_cast<unsigned char>(str[1])] +
|
||||
asso_values[static_cast<unsigned char>(str[0])];
|
||||
}
|
||||
|
||||
static const unsigned char kPerfectKeywordLengthTable[64] = {
|
||||
0, 0, 2, 3, 4, 2, 6, 7, 8, 9, 10, 2, 6, 7, 5, 3, 7, 8, 4, 5, 4, 7,
|
||||
5, 6, 5, 0, 5, 0, 6, 4, 7, 5, 9, 8, 5, 6, 3, 4, 5, 3, 4, 4, 5, 0,
|
||||
6, 4, 6, 5, 6, 3, 10, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
0, 0, 2, 3, 4, 2, 6, 7, 8, 9, 10, 2, 3, 3, 5, 3, 7, 8, 4, 5, 4, 7,
|
||||
5, 5, 5, 6, 4, 5, 6, 6, 4, 5, 7, 8, 9, 3, 4, 3, 4, 5, 5, 5, 6, 6,
|
||||
7, 5, 4, 6, 0, 0, 3, 10, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
static const struct PerfectKeywordHashTableEntry kPerfectKeywordHashTable[64] =
|
||||
{{"", Token::IDENTIFIER},
|
||||
@ -100,8 +100,8 @@ static const struct PerfectKeywordHashTableEntry kPerfectKeywordHashTable[64] =
|
||||
{"interface", Token::FUTURE_STRICT_RESERVED_WORD},
|
||||
{"instanceof", Token::INSTANCEOF},
|
||||
{"if", Token::IF},
|
||||
{"export", Token::EXPORT},
|
||||
{"extends", Token::EXTENDS},
|
||||
{"get", Token::GET},
|
||||
{"set", Token::SET},
|
||||
{"const", Token::CONST},
|
||||
{"for", Token::FOR},
|
||||
{"finally", Token::FINALLY},
|
||||
@ -111,39 +111,39 @@ static const struct PerfectKeywordHashTableEntry kPerfectKeywordHashTable[64] =
|
||||
{"null", Token::NULL_LITERAL},
|
||||
{"package", Token::FUTURE_STRICT_RESERVED_WORD},
|
||||
{"false", Token::FALSE_LITERAL},
|
||||
{"return", Token::RETURN},
|
||||
{"break", Token::BREAK},
|
||||
{"", Token::IDENTIFIER},
|
||||
{"async", Token::ASYNC},
|
||||
{"", Token::IDENTIFIER},
|
||||
{"public", Token::FUTURE_STRICT_RESERVED_WORD},
|
||||
{"with", Token::WITH},
|
||||
{"private", Token::FUTURE_STRICT_RESERVED_WORD},
|
||||
{"yield", Token::YIELD},
|
||||
{"protected", Token::FUTURE_STRICT_RESERVED_WORD},
|
||||
{"function", Token::FUNCTION},
|
||||
{"super", Token::SUPER},
|
||||
{"static", Token::STATIC},
|
||||
{"try", Token::TRY},
|
||||
{"true", Token::TRUE_LITERAL},
|
||||
{"await", Token::AWAIT},
|
||||
{"let", Token::LET},
|
||||
{"else", Token::ELSE},
|
||||
{"break", Token::BREAK},
|
||||
{"return", Token::RETURN},
|
||||
{"this", Token::THIS},
|
||||
{"throw", Token::THROW},
|
||||
{"", Token::IDENTIFIER},
|
||||
{"public", Token::FUTURE_STRICT_RESERVED_WORD},
|
||||
{"static", Token::STATIC},
|
||||
{"with", Token::WITH},
|
||||
{"super", Token::SUPER},
|
||||
{"private", Token::FUTURE_STRICT_RESERVED_WORD},
|
||||
{"function", Token::FUNCTION},
|
||||
{"protected", Token::FUTURE_STRICT_RESERVED_WORD},
|
||||
{"try", Token::TRY},
|
||||
{"true", Token::TRUE_LITERAL},
|
||||
{"let", Token::LET},
|
||||
{"else", Token::ELSE},
|
||||
{"await", Token::AWAIT},
|
||||
{"while", Token::WHILE},
|
||||
{"yield", Token::YIELD},
|
||||
{"switch", Token::SWITCH},
|
||||
{"export", Token::EXPORT},
|
||||
{"extends", Token::EXTENDS},
|
||||
{"class", Token::CLASS},
|
||||
{"void", Token::VOID},
|
||||
{"import", Token::IMPORT},
|
||||
{"class", Token::CLASS},
|
||||
{"typeof", Token::TYPEOF},
|
||||
{"", Token::IDENTIFIER},
|
||||
{"", Token::IDENTIFIER},
|
||||
{"var", Token::VAR},
|
||||
{"implements", Token::FUTURE_STRICT_RESERVED_WORD},
|
||||
{"while", Token::WHILE},
|
||||
{"", Token::IDENTIFIER},
|
||||
{"", Token::IDENTIFIER},
|
||||
{"", Token::IDENTIFIER},
|
||||
{"", Token::IDENTIFIER},
|
||||
{"typeof", Token::TYPEOF},
|
||||
{"", Token::IDENTIFIER},
|
||||
{"", Token::IDENTIFIER},
|
||||
{"", Token::IDENTIFIER},
|
||||
|
@ -35,6 +35,7 @@ false, Token::FALSE_LITERAL
|
||||
finally, Token::FINALLY
|
||||
for, Token::FOR
|
||||
function, Token::FUNCTION
|
||||
get, Token::GET
|
||||
if, Token::IF
|
||||
implements, Token::FUTURE_STRICT_RESERVED_WORD
|
||||
import, Token::IMPORT
|
||||
@ -49,6 +50,7 @@ private, Token::FUTURE_STRICT_RESERVED_WORD
|
||||
protected, Token::FUTURE_STRICT_RESERVED_WORD
|
||||
public, Token::FUTURE_STRICT_RESERVED_WORD
|
||||
return, Token::RETURN
|
||||
set, Token::SET
|
||||
static, Token::STATIC
|
||||
super, Token::SUPER
|
||||
switch, Token::SWITCH
|
||||
|
@ -797,6 +797,7 @@ class ParserBase {
|
||||
|
||||
bool PeekContextualKeyword(const AstRawString* name) {
|
||||
return peek() == Token::IDENTIFIER &&
|
||||
!scanner()->next_literal_contains_escapes() &&
|
||||
scanner()->NextSymbol(ast_value_factory()) == name;
|
||||
}
|
||||
|
||||
@ -808,14 +809,21 @@ class ParserBase {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ExpectMetaProperty(const AstRawString* property_name,
|
||||
const char* full_name, int pos);
|
||||
|
||||
void ExpectContextualKeyword(const AstRawString* name) {
|
||||
void ExpectContextualKeyword(const AstRawString* name,
|
||||
const char* fullname = nullptr, int pos = -1) {
|
||||
Expect(Token::IDENTIFIER);
|
||||
if (V8_UNLIKELY(scanner()->CurrentSymbol(ast_value_factory()) != name)) {
|
||||
ReportUnexpectedToken(scanner()->current_token());
|
||||
}
|
||||
if (V8_UNLIKELY(scanner()->literal_contains_escapes())) {
|
||||
const char* full = fullname == nullptr
|
||||
? reinterpret_cast<const char*>(name->raw_data())
|
||||
: fullname;
|
||||
int start = pos == -1 ? position() : pos;
|
||||
impl()->ReportMessageAt(Scanner::Location(start, end_position()),
|
||||
MessageTemplate::kInvalidEscapedMetaProperty,
|
||||
full);
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode) {
|
||||
@ -1472,7 +1480,6 @@ template <typename Impl>
|
||||
typename ParserBase<Impl>::IdentifierT
|
||||
ParserBase<Impl>::ParseAndClassifyIdentifier(Token::Value next) {
|
||||
DCHECK_EQ(scanner()->current_token(), next);
|
||||
STATIC_ASSERT(Token::IDENTIFIER + 1 == Token::ASYNC);
|
||||
if (V8_LIKELY(IsInRange(next, Token::IDENTIFIER, Token::ASYNC))) {
|
||||
IdentifierT name = impl()->GetSymbol();
|
||||
if (V8_UNLIKELY(impl()->IsArguments(name) &&
|
||||
@ -1648,7 +1655,8 @@ ParserBase<Impl>::ParsePrimaryExpression() {
|
||||
FunctionKind kind = FunctionKind::kArrowFunction;
|
||||
|
||||
if (V8_UNLIKELY(token == Token::ASYNC &&
|
||||
!scanner()->HasLineTerminatorBeforeNext())) {
|
||||
!scanner()->HasLineTerminatorBeforeNext() &&
|
||||
!scanner()->literal_contains_escapes())) {
|
||||
// async function ...
|
||||
if (peek() == Token::FUNCTION) return ParseAsyncFunctionLiteral();
|
||||
|
||||
@ -1929,6 +1937,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty(
|
||||
impl()->PushLiteralName(prop_info->name);
|
||||
return factory()->NewStringLiteral(prop_info->name, position());
|
||||
}
|
||||
if (V8_UNLIKELY(scanner()->literal_contains_escapes())) {
|
||||
impl()->ReportUnexpectedToken(Token::ESCAPED_KEYWORD);
|
||||
}
|
||||
prop_info->function_flags = ParseFunctionFlag::kIsAsync;
|
||||
prop_info->kind = ParsePropertyKind::kMethod;
|
||||
}
|
||||
@ -1939,21 +1950,21 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty(
|
||||
}
|
||||
|
||||
if (prop_info->kind == ParsePropertyKind::kNotSet &&
|
||||
Check(Token::IDENTIFIER)) {
|
||||
IdentifierT symbol = impl()->GetSymbol();
|
||||
if (!prop_info->ParsePropertyKindFromToken(peek())) {
|
||||
if (impl()->IdentifierEquals(symbol, ast_value_factory()->get_string())) {
|
||||
prop_info->kind = ParsePropertyKind::kAccessorGetter;
|
||||
} else if (impl()->IdentifierEquals(symbol,
|
||||
ast_value_factory()->set_string())) {
|
||||
prop_info->kind = ParsePropertyKind::kAccessorSetter;
|
||||
}
|
||||
}
|
||||
if (!IsAccessor(prop_info->kind)) {
|
||||
prop_info->name = symbol;
|
||||
IsInRange(peek(), Token::GET, Token::SET)) {
|
||||
Token::Value token = Next();
|
||||
if (prop_info->ParsePropertyKindFromToken(peek())) {
|
||||
prop_info->name = impl()->GetSymbol();
|
||||
impl()->PushLiteralName(prop_info->name);
|
||||
return factory()->NewStringLiteral(prop_info->name, position());
|
||||
}
|
||||
if (V8_UNLIKELY(scanner()->literal_contains_escapes())) {
|
||||
impl()->ReportUnexpectedToken(Token::ESCAPED_KEYWORD);
|
||||
}
|
||||
if (token == Token::GET) {
|
||||
prop_info->kind = ParsePropertyKind::kAccessorGetter;
|
||||
} else if (token == Token::SET) {
|
||||
prop_info->kind = ParsePropertyKind::kAccessorSetter;
|
||||
}
|
||||
}
|
||||
|
||||
int pos = peek_position();
|
||||
@ -2682,6 +2693,9 @@ ParserBase<Impl>::ParseYieldExpression() {
|
||||
expression_scope()->RecordParameterInitializerError(
|
||||
scanner()->peek_location(), MessageTemplate::kYieldInParameter);
|
||||
Consume(Token::YIELD);
|
||||
if (V8_UNLIKELY(scanner()->literal_contains_escapes())) {
|
||||
impl()->ReportUnexpectedToken(Token::ESCAPED_KEYWORD);
|
||||
}
|
||||
|
||||
CheckStackOverflow();
|
||||
|
||||
@ -2906,6 +2920,9 @@ ParserBase<Impl>::ParseAwaitExpression() {
|
||||
MessageTemplate::kAwaitExpressionFormalParameter);
|
||||
int await_pos = peek_position();
|
||||
Consume(Token::AWAIT);
|
||||
if (V8_UNLIKELY(scanner()->literal_contains_escapes())) {
|
||||
impl()->ReportUnexpectedToken(Token::ESCAPED_KEYWORD);
|
||||
}
|
||||
|
||||
CheckStackOverflow();
|
||||
|
||||
@ -2987,7 +3004,8 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) {
|
||||
|
||||
if (V8_UNLIKELY(peek() == Token::LPAREN && impl()->IsIdentifier(result) &&
|
||||
scanner()->current_token() == Token::ASYNC &&
|
||||
!scanner()->HasLineTerminatorBeforeNext())) {
|
||||
!scanner()->HasLineTerminatorBeforeNext() &&
|
||||
!scanner()->literal_contains_escapes())) {
|
||||
DCHECK(impl()->IsAsync(impl()->AsIdentifier(result)));
|
||||
int pos = position();
|
||||
|
||||
@ -3249,8 +3267,9 @@ ParserBase<Impl>::ParseImportExpressions() {
|
||||
|
||||
Consume(Token::IMPORT);
|
||||
int pos = position();
|
||||
if (allow_harmony_import_meta() && peek() == Token::PERIOD) {
|
||||
ExpectMetaProperty(ast_value_factory()->meta_string(), "import.meta", pos);
|
||||
if (allow_harmony_import_meta() && Check(Token::PERIOD)) {
|
||||
ExpectContextualKeyword(ast_value_factory()->meta_string(), "import.meta",
|
||||
pos);
|
||||
if (!parsing_module_) {
|
||||
impl()->ReportMessageAt(scanner()->location(),
|
||||
MessageTemplate::kImportMetaOutsideModule);
|
||||
@ -3303,23 +3322,13 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression(
|
||||
return impl()->FailureExpression();
|
||||
}
|
||||
|
||||
template <typename Impl>
|
||||
void ParserBase<Impl>::ExpectMetaProperty(const AstRawString* property_name,
|
||||
const char* full_name, int pos) {
|
||||
Consume(Token::PERIOD);
|
||||
ExpectContextualKeyword(property_name);
|
||||
if (V8_UNLIKELY(scanner()->literal_contains_escapes())) {
|
||||
impl()->ReportMessageAt(Scanner::Location(pos, end_position()),
|
||||
MessageTemplate::kInvalidEscapedMetaProperty,
|
||||
full_name);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Impl>
|
||||
typename ParserBase<Impl>::ExpressionT
|
||||
ParserBase<Impl>::ParseNewTargetExpression() {
|
||||
int pos = position();
|
||||
ExpectMetaProperty(ast_value_factory()->target_string(), "new.target", pos);
|
||||
Consume(Token::PERIOD);
|
||||
ExpectContextualKeyword(ast_value_factory()->target_string(), "new.target",
|
||||
pos);
|
||||
|
||||
if (!GetReceiverScope()->is_function_scope()) {
|
||||
impl()->ReportMessageAt(scanner()->location(),
|
||||
@ -3801,6 +3810,9 @@ ParserBase<Impl>::ParseAsyncFunctionDeclaration(
|
||||
// async [no LineTerminator here] function BindingIdentifier[Await]
|
||||
// ( FormalParameters[Await] ) { AsyncFunctionBody }
|
||||
DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
|
||||
if (V8_UNLIKELY(scanner()->literal_contains_escapes())) {
|
||||
impl()->ReportUnexpectedToken(Token::ESCAPED_KEYWORD);
|
||||
}
|
||||
int pos = position();
|
||||
DCHECK(!scanner()->HasLineTerminatorBeforeNext());
|
||||
Consume(Token::FUNCTION);
|
||||
@ -3978,6 +3990,8 @@ bool ParserBase<Impl>::IsNextLetKeyword() {
|
||||
// tokens.
|
||||
case Token::YIELD:
|
||||
case Token::AWAIT:
|
||||
case Token::GET:
|
||||
case Token::SET:
|
||||
case Token::ASYNC:
|
||||
return true;
|
||||
case Token::FUTURE_STRICT_RESERVED_WORD:
|
||||
@ -4258,6 +4272,9 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral() {
|
||||
// async [no LineTerminator here] function BindingIdentifier[Await]
|
||||
// ( FormalParameters[Await] ) { AsyncFunctionBody }
|
||||
DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
|
||||
if (V8_UNLIKELY(scanner()->literal_contains_escapes())) {
|
||||
impl()->ReportUnexpectedToken(Token::ESCAPED_KEYWORD);
|
||||
}
|
||||
int pos = position();
|
||||
Consume(Token::FUNCTION);
|
||||
IdentifierT name = impl()->NullIdentifier();
|
||||
|
@ -42,6 +42,8 @@ namespace internal {
|
||||
KEYWORD("finally", Token::FINALLY) \
|
||||
KEYWORD("for", Token::FOR) \
|
||||
KEYWORD("function", Token::FUNCTION) \
|
||||
KEYWORD_GROUP('g') \
|
||||
KEYWORD("get", Token::GET) \
|
||||
KEYWORD_GROUP('i') \
|
||||
KEYWORD("if", Token::IF) \
|
||||
KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
|
||||
@ -62,6 +64,7 @@ namespace internal {
|
||||
KEYWORD_GROUP('r') \
|
||||
KEYWORD("return", Token::RETURN) \
|
||||
KEYWORD_GROUP('s') \
|
||||
KEYWORD("set", Token::SET) \
|
||||
KEYWORD("static", Token::STATIC) \
|
||||
KEYWORD("super", Token::SUPER) \
|
||||
KEYWORD("switch", Token::SWITCH) \
|
||||
|
@ -1007,16 +1007,17 @@ Token::Value Scanner::ScanIdentifierOrKeywordInnerSlow(bool escaped,
|
||||
Vector<const uint8_t> chars = next().literal_chars.one_byte_literal();
|
||||
Token::Value token =
|
||||
KeywordOrIdentifierToken(chars.start(), chars.length());
|
||||
/* TODO(adamk): YIELD should be handled specially. */
|
||||
if (IsInRange(token, Token::IDENTIFIER, Token::YIELD)) return token;
|
||||
|
||||
if (token == Token::FUTURE_STRICT_RESERVED_WORD) {
|
||||
if (escaped) return Token::ESCAPED_STRICT_RESERVED_WORD;
|
||||
return token;
|
||||
}
|
||||
if (token == Token::IDENTIFIER) return token;
|
||||
|
||||
if (!escaped) return token;
|
||||
|
||||
if (token == Token::LET || token == Token::STATIC) {
|
||||
STATIC_ASSERT(Token::LET + 1 == Token::STATIC);
|
||||
if (IsInRange(token, Token::LET, Token::STATIC)) {
|
||||
return Token::ESCAPED_STRICT_RESERVED_WORD;
|
||||
}
|
||||
return Token::ESCAPED_KEYWORD;
|
||||
|
@ -316,6 +316,10 @@ class Scanner {
|
||||
return LiteralContainsEscapes(current());
|
||||
}
|
||||
|
||||
bool next_literal_contains_escapes() const {
|
||||
return LiteralContainsEscapes(next());
|
||||
}
|
||||
|
||||
const AstRawString* CurrentSymbol(AstValueFactory* ast_value_factory) const;
|
||||
|
||||
const AstRawString* NextSymbol(AstValueFactory* ast_value_factory) const;
|
||||
@ -517,7 +521,6 @@ class Scanner {
|
||||
bool CanAccessLiteral() const {
|
||||
return token == Token::PRIVATE_NAME || token == Token::ILLEGAL ||
|
||||
token == Token::UNINITIALIZED || token == Token::REGEXP_LITERAL ||
|
||||
token == Token::ESCAPED_KEYWORD ||
|
||||
IsInRange(token, Token::NUMBER, Token::STRING) ||
|
||||
(Token::IsAnyIdentifier(token) && !Token::IsKeyword(token)) ||
|
||||
IsInRange(token, Token::TEMPLATE_SPAN, Token::TEMPLATE_TAIL);
|
||||
|
@ -34,8 +34,7 @@ const int8_t Token::precedence_[2][NUM_TOKENS] = {{TOKEN_LIST(T1, T1)},
|
||||
#undef T2
|
||||
#undef T1
|
||||
|
||||
#define KT(a, b, c) \
|
||||
IsPropertyNameBits::encode(Token::IsAnyIdentifier(a) || a == ESCAPED_KEYWORD),
|
||||
#define KT(a, b, c) IsPropertyNameBits::encode(Token::IsAnyIdentifier(a)),
|
||||
#define KK(a, b, c) \
|
||||
IsKeywordBits::encode(true) | IsPropertyNameBits::encode(true),
|
||||
const uint8_t Token::token_flags[] = {TOKEN_LIST(KT, KK)};
|
||||
|
@ -171,6 +171,8 @@ namespace internal {
|
||||
/* BEGIN AnyIdentifier */ \
|
||||
/* Identifiers (not keywords or future reserved words). */ \
|
||||
T(IDENTIFIER, nullptr, 0) \
|
||||
K(GET, "get", 0) \
|
||||
K(SET, "set", 0) \
|
||||
K(ASYNC, "async", 0) \
|
||||
/* `await` is a reserved word in module code only */ \
|
||||
K(AWAIT, "await", 0) \
|
||||
|
@ -92,6 +92,8 @@ TEST(AutoSemicolonToken) {
|
||||
bool TokenIsAnyIdentifier(Token::Value token) {
|
||||
switch (token) {
|
||||
case Token::IDENTIFIER:
|
||||
case Token::GET:
|
||||
case Token::SET:
|
||||
case Token::ASYNC:
|
||||
case Token::AWAIT:
|
||||
case Token::YIELD:
|
||||
@ -116,6 +118,8 @@ bool TokenIsCallable(Token::Value token) {
|
||||
switch (token) {
|
||||
case Token::SUPER:
|
||||
case Token::IDENTIFIER:
|
||||
case Token::GET:
|
||||
case Token::SET:
|
||||
case Token::ASYNC:
|
||||
case Token::AWAIT:
|
||||
case Token::YIELD:
|
||||
@ -140,6 +144,8 @@ bool TokenIsValidIdentifier(Token::Value token, LanguageMode language_mode,
|
||||
bool is_generator, bool disallow_await) {
|
||||
switch (token) {
|
||||
case Token::IDENTIFIER:
|
||||
case Token::GET:
|
||||
case Token::SET:
|
||||
case Token::ASYNC:
|
||||
return true;
|
||||
case Token::YIELD:
|
||||
@ -840,19 +846,9 @@ TEST(StreamScanner) {
|
||||
std::unique_ptr<i::Utf16CharacterStream> stream1(
|
||||
i::ScannerStream::ForTesting(str1));
|
||||
i::Token::Value expectations1[] = {
|
||||
i::Token::LBRACE,
|
||||
i::Token::IDENTIFIER,
|
||||
i::Token::IDENTIFIER,
|
||||
i::Token::FOR,
|
||||
i::Token::COLON,
|
||||
i::Token::MUL,
|
||||
i::Token::DIV,
|
||||
i::Token::LT,
|
||||
i::Token::SUB,
|
||||
i::Token::IDENTIFIER,
|
||||
i::Token::EOS,
|
||||
i::Token::ILLEGAL
|
||||
};
|
||||
i::Token::LBRACE, i::Token::IDENTIFIER, i::Token::GET, i::Token::FOR,
|
||||
i::Token::COLON, i::Token::MUL, i::Token::DIV, i::Token::LT,
|
||||
i::Token::SUB, i::Token::IDENTIFIER, i::Token::EOS, i::Token::ILLEGAL};
|
||||
TestStreamScanner(stream1.get(), expectations1, 0, 0);
|
||||
|
||||
const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
|
||||
@ -9379,11 +9375,10 @@ TEST(EscapedKeywords) {
|
||||
"class C { st\\u0061tic *bar() {} }",
|
||||
"class C { st\\u0061tic get bar() {} }",
|
||||
"class C { st\\u0061tic set bar() {} }",
|
||||
|
||||
// TODO(adamk): These should not be errors in sloppy mode.
|
||||
"(y\\u0069eld);",
|
||||
"var y\\u0069eld = 1;",
|
||||
"var { y\\u0069eld } = {};",
|
||||
"(async ()=>{\\u0061wait 100})()",
|
||||
"({\\u0067et get(){}})",
|
||||
"({\\u0073et set(){}})",
|
||||
"(async ()=>{var \\u0061wait = 100})()",
|
||||
nullptr
|
||||
};
|
||||
// clang-format on
|
||||
@ -9397,6 +9392,9 @@ TEST(EscapedKeywords) {
|
||||
"var l\\u0065t = 1;",
|
||||
"l\\u0065t = 1;",
|
||||
"(l\\u0065t === 1);",
|
||||
"(y\\u0069eld);",
|
||||
"var y\\u0069eld = 1;",
|
||||
"var { y\\u0069eld } = {};",
|
||||
nullptr
|
||||
};
|
||||
// clang-format on
|
||||
|
@ -591,24 +591,6 @@
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=6538
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=6541
|
||||
'language/export/escaped-as-export-specifier': [FAIL],
|
||||
'language/export/escaped-from': [FAIL],
|
||||
'language/expressions/object/method-definition/escaped-get': [FAIL],
|
||||
'language/expressions/object/method-definition/escaped-set': [FAIL],
|
||||
'language/import/escaped-as-import-specifier': [FAIL],
|
||||
'language/import/escaped-as-namespace-import': [FAIL],
|
||||
'language/import/escaped-from': [FAIL],
|
||||
'language/statements/for-await-of/escaped-of': [FAIL],
|
||||
'language/statements/for-of/escaped-of': [FAIL],
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=6543
|
||||
'language/statements/labeled/value-await-non-module-escaped': [FAIL],
|
||||
'language/statements/labeled/value-yield-non-strict-escaped': [FAIL],
|
||||
'language/expressions/async-arrow-function/escaped-async-line-terminator': [FAIL],
|
||||
'language/expressions/class/class-name-ident-await-escaped': [FAIL],
|
||||
'language/statements/class/class-name-ident-await-escaped': [FAIL],
|
||||
|
||||
############################ INVALID TESTS #############################
|
||||
|
||||
# Test makes unjustified assumptions about the number of calls to SortCompare.
|
||||
|
Loading…
Reference in New Issue
Block a user