[parser] Token-range-check for callable identifier tokens
This also fixes the tokens that are identified as called identifiers. Change-Id: I4a2179b98214f9018c8c07c0ab27f878cdae13cf Bug: v8:6513 Reviewed-on: https://chromium-review.googlesource.com/c/1286338 Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Commit-Queue: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/master@{#56719}
This commit is contained in:
parent
e19dc9f604
commit
e1c6fa8878
@ -3245,9 +3245,7 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result, bool* ok) {
|
||||
|
||||
case Token::LPAREN: {
|
||||
int pos;
|
||||
if (scanner()->current_token() == Token::IDENTIFIER ||
|
||||
scanner()->current_token() == Token::SUPER ||
|
||||
scanner()->current_token() == Token::ASYNC) {
|
||||
if (Token::IsCallable(scanner()->current_token())) {
|
||||
// For call of an identifier we want to report position of
|
||||
// the identifier as position of the call in the stack trace.
|
||||
pos = position();
|
||||
|
@ -155,6 +155,8 @@ namespace internal {
|
||||
T(BIGINT, nullptr, 0) \
|
||||
T(STRING, nullptr, 0) \
|
||||
\
|
||||
/* BEGIN Callable */ \
|
||||
K(SUPER, "super", 0) \
|
||||
/* BEGIN AnyIdentifier */ \
|
||||
/* Identifiers (not keywords or future reserved words). */ \
|
||||
T(IDENTIFIER, nullptr, 0) \
|
||||
@ -168,13 +170,13 @@ namespace internal {
|
||||
T(FUTURE_STRICT_RESERVED_WORD, nullptr, 0) \
|
||||
T(ESCAPED_STRICT_RESERVED_WORD, nullptr, 0) \
|
||||
K(ENUM, "enum", 0) \
|
||||
/* END Callable */ \
|
||||
/* END AnyIdentifier */ \
|
||||
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. */ \
|
||||
@ -237,6 +239,8 @@ class Token {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsCallable(Value token) { return IsInRange(token, SUPER, ENUM); }
|
||||
|
||||
static bool IsAnyIdentifier(Value token) {
|
||||
return IsInRange(token, IDENTIFIER, ENUM);
|
||||
}
|
||||
@ -287,10 +291,6 @@ class Token {
|
||||
|
||||
static bool IsShiftOp(Value op) { return IsInRange(op, SHL, SHR); }
|
||||
|
||||
static bool IsTrivialExpressionToken(Value op) {
|
||||
return IsInRange(op, THIS, IDENTIFIER);
|
||||
}
|
||||
|
||||
// Returns a string corresponding to the JS token string
|
||||
// (.e., "<" for the token LT) or nullptr if the token doesn't
|
||||
// have a (unique) string (e.g. an IDENTIFIER).
|
||||
|
@ -103,6 +103,31 @@ TEST(AnyIdentifierToken) {
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenIsCallable(Token::Value token) {
|
||||
switch (token) {
|
||||
case Token::SUPER:
|
||||
case Token::IDENTIFIER:
|
||||
case Token::ASYNC:
|
||||
case Token::AWAIT:
|
||||
case Token::YIELD:
|
||||
case Token::LET:
|
||||
case Token::STATIC:
|
||||
case Token::FUTURE_STRICT_RESERVED_WORD:
|
||||
case Token::ESCAPED_STRICT_RESERVED_WORD:
|
||||
case Token::ENUM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CallableToken) {
|
||||
for (int i = 0; i < Token::NUM_TOKENS; i++) {
|
||||
Token::Value token = static_cast<Token::Value>(i);
|
||||
CHECK_EQ(TokenIsCallable(token), Token::IsCallable(token));
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenIsIdentifier(Token::Value token, LanguageMode language_mode,
|
||||
bool is_generator, bool disallow_await) {
|
||||
switch (token) {
|
||||
@ -386,31 +411,6 @@ TEST(IsShiftOp) {
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenIsTrivialExpressionToken(Token::Value token) {
|
||||
switch (token) {
|
||||
case Token::SMI:
|
||||
case Token::NUMBER:
|
||||
case Token::BIGINT:
|
||||
case Token::NULL_LITERAL:
|
||||
case Token::TRUE_LITERAL:
|
||||
case Token::FALSE_LITERAL:
|
||||
case Token::STRING:
|
||||
case Token::IDENTIFIER:
|
||||
case Token::THIS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IsTrivialExpressionToken) {
|
||||
for (int i = 0; i < Token::NUM_TOKENS; i++) {
|
||||
Token::Value token = static_cast<Token::Value>(i);
|
||||
CHECK_EQ(TokenIsTrivialExpressionToken(token),
|
||||
Token::IsTrivialExpressionToken(token));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ScanKeywords) {
|
||||
struct KeywordToken {
|
||||
const char* keyword;
|
||||
|
8
test/message/fail/call-async.js
Normal file
8
test/message/fail/call-async.js
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
function f(async) {
|
||||
async()
|
||||
}
|
||||
f()
|
6
test/message/fail/call-async.out
Normal file
6
test/message/fail/call-async.out
Normal file
@ -0,0 +1,6 @@
|
||||
*%(basename)s:6: TypeError: async is not a function
|
||||
async()
|
||||
^
|
||||
TypeError: async is not a function
|
||||
at f (*%(basename)s:6:3)
|
||||
at *%(basename)s:8:1
|
8
test/message/fail/call-await.js
Normal file
8
test/message/fail/call-await.js
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
function f(await) {
|
||||
await()
|
||||
}
|
||||
f()
|
7
test/message/fail/call-await.out
Normal file
7
test/message/fail/call-await.out
Normal file
@ -0,0 +1,7 @@
|
||||
*%(basename)s:6: TypeError: await is not a function
|
||||
await()
|
||||
^
|
||||
TypeError: await is not a function
|
||||
at f (*%(basename)s:6:3)
|
||||
at *%(basename)s:8:1
|
||||
|
8
test/message/fail/call-let.js
Normal file
8
test/message/fail/call-let.js
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
function f(let) {
|
||||
let()
|
||||
}
|
||||
f()
|
6
test/message/fail/call-let.out
Normal file
6
test/message/fail/call-let.out
Normal file
@ -0,0 +1,6 @@
|
||||
*%(basename)s:6: TypeError: let is not a function
|
||||
let()
|
||||
^
|
||||
TypeError: let is not a function
|
||||
at f (*%(basename)s:6:3)
|
||||
at *%(basename)s:8:1
|
8
test/message/fail/call-static.js
Normal file
8
test/message/fail/call-static.js
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
function f(static) {
|
||||
static()
|
||||
}
|
||||
f()
|
6
test/message/fail/call-static.out
Normal file
6
test/message/fail/call-static.out
Normal file
@ -0,0 +1,6 @@
|
||||
*%(basename)s:6: TypeError: static is not a function
|
||||
static()
|
||||
^
|
||||
TypeError: static is not a function
|
||||
at f (*%(basename)s:6:3)
|
||||
at *%(basename)s:8:1
|
8
test/message/fail/call-yield.js
Normal file
8
test/message/fail/call-yield.js
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
function f(yield) {
|
||||
yield()
|
||||
}
|
||||
f()
|
6
test/message/fail/call-yield.out
Normal file
6
test/message/fail/call-yield.out
Normal file
@ -0,0 +1,6 @@
|
||||
*%(basename)s:6: TypeError: yield is not a function
|
||||
yield()
|
||||
^
|
||||
TypeError: yield is not a function
|
||||
at f (*%(basename)s:6:3)
|
||||
at *%(basename)s:8:1
|
Loading…
Reference in New Issue
Block a user