[es6] early error when Identifier is an escaped reserved word

Per http://tc39.github.io/ecma262/#sec-identifiers-static-semantics-early-errors (13.2.2),
make it a SyntaxError if an Identifier has the same StringValue as a ReservedWord.

BUG=v8:2222, v8:1972
LOG=N
R=adamk@chromium.org, rossberg@chromium.org, wingo@chromium.org

Review URL: https://codereview.chromium.org/1429983002

Cr-Commit-Position: refs/heads/master@{#32052}
This commit is contained in:
caitpotter88 2015-11-17 07:59:45 -08:00 committed by Commit bot
parent cf9957eeb6
commit 5bf360ef57
8 changed files with 309 additions and 149 deletions

View File

@ -312,6 +312,7 @@ class CallSite {
T(IllegalLanguageModeDirective, \
"Illegal '%' directive in function with non-simple parameter list") \
T(IllegalReturn, "Illegal return statement") \
T(InvalidEscapedReservedWord, "Keyword must not contain escaped characters") \
T(InvalidLhsInAssignment, "Invalid left-hand side in assignment") \
T(InvalidLhsInFor, "Invalid left-hand side in for-loop") \
T(InvalidLhsInPostfixOp, \

View File

@ -684,6 +684,7 @@ class ParserBase : public Traits {
ExpressionT ParseArrayLiteral(ExpressionClassifier* classifier, bool* ok);
ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set,
bool* is_static, bool* is_computed_name,
bool* is_identifier, bool* is_escaped_keyword,
ExpressionClassifier* classifier, bool* ok);
ExpressionT ParseObjectLiteral(ExpressionClassifier* classifier, bool* ok);
ObjectLiteralPropertyT ParsePropertyDefinition(
@ -2016,6 +2017,11 @@ void ParserBase<Traits>::GetUnexpectedTokenMessage(
*message = MessageTemplate::kUnexpectedTemplateString;
*arg = nullptr;
break;
case Token::ESCAPED_STRICT_RESERVED_WORD:
case Token::ESCAPED_KEYWORD:
*message = MessageTemplate::kInvalidEscapedReservedWord;
*arg = nullptr;
break;
default:
const char* name = Token::String(token);
DCHECK(name != NULL);
@ -2115,10 +2121,17 @@ ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
return name;
} else if (is_sloppy(language_mode()) &&
(next == Token::FUTURE_STRICT_RESERVED_WORD ||
next == Token::ESCAPED_STRICT_RESERVED_WORD ||
next == Token::LET || next == Token::STATIC ||
(next == Token::YIELD && !is_generator()))) {
classifier->RecordStrictModeFormalParameterError(
scanner()->location(), MessageTemplate::kUnexpectedStrictReserved);
if (next == Token::ESCAPED_STRICT_RESERVED_WORD &&
is_strict(language_mode())) {
ReportUnexpectedToken(next);
*ok = false;
return Traits::EmptyIdentifier();
}
if (next == Token::LET) {
classifier->RecordLetPatternError(scanner()->location(),
MessageTemplate::kLetInLexicalBinding);
@ -2161,7 +2174,9 @@ ParserBase<Traits>::ParseIdentifierName(bool* ok) {
Token::Value next = Next();
if (next != Token::IDENTIFIER && next != Token::FUTURE_RESERVED_WORD &&
next != Token::LET && next != Token::STATIC && next != Token::YIELD &&
next != Token::FUTURE_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
next != Token::FUTURE_STRICT_RESERVED_WORD &&
next != Token::ESCAPED_KEYWORD &&
next != Token::ESCAPED_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
this->ReportUnexpectedToken(next);
*ok = false;
return Traits::EmptyIdentifier();
@ -2278,6 +2293,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
case Token::LET:
case Token::STATIC:
case Token::YIELD:
case Token::ESCAPED_STRICT_RESERVED_WORD:
case Token::FUTURE_STRICT_RESERVED_WORD: {
// Using eval or arguments in this context is OK even in strict mode.
IdentifierT name = ParseAndClassifyIdentifier(classifier, CHECK_OK);
@ -2542,7 +2558,8 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
template <class Traits>
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
IdentifierT* name, bool* is_get, bool* is_set, bool* is_static,
bool* is_computed_name, ExpressionClassifier* classifier, bool* ok) {
bool* is_computed_name, bool* is_identifier, bool* is_escaped_keyword,
ExpressionClassifier* classifier, bool* ok) {
Token::Value token = peek();
int pos = peek_position();
@ -2583,11 +2600,17 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
return expression;
}
case Token::ESCAPED_KEYWORD:
*is_escaped_keyword = true;
*name = ParseIdentifierNameOrGetOrSet(is_get, is_set, CHECK_OK);
break;
case Token::STATIC:
*is_static = true;
// Fall through.
default:
*is_identifier = true;
*name = ParseIdentifierNameOrGetOrSet(is_get, is_set, CHECK_OK);
break;
}
@ -2616,14 +2639,21 @@ ParserBase<Traits>::ParsePropertyDefinition(
Token::Value name_token = peek();
int next_beg_pos = scanner()->peek_location().beg_pos;
int next_end_pos = scanner()->peek_location().end_pos;
bool is_identifier = false;
bool is_escaped_keyword = false;
ExpressionT name_expression = ParsePropertyName(
&name, &is_get, &is_set, &name_is_static, is_computed_name, classifier,
&name, &is_get, &is_set, &name_is_static, is_computed_name,
&is_identifier, &is_escaped_keyword, classifier,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
if (fni_ != nullptr && !*is_computed_name) {
this->PushLiteralName(fni_, name);
}
bool escaped_static =
is_escaped_keyword &&
scanner()->is_literal_contextual_keyword(CStrVector("static"));
if (!in_class && !is_generator) {
DCHECK(!is_static);
@ -2641,8 +2671,7 @@ ParserBase<Traits>::ParsePropertyDefinition(
*is_computed_name);
}
if (Token::IsIdentifier(name_token, language_mode(),
this->is_generator()) &&
if ((is_identifier || is_escaped_keyword) &&
(peek() == Token::COMMA || peek() == Token::RBRACE ||
peek() == Token::ASSIGN)) {
// PropertyDefinition
@ -2651,6 +2680,14 @@ ParserBase<Traits>::ParsePropertyDefinition(
//
// CoverInitializedName
// IdentifierReference Initializer?
if (!Token::IsIdentifier(name_token, language_mode(),
this->is_generator())) {
if (!escaped_static) {
ReportUnexpectedTokenAt(scanner()->location(), name_token);
*ok = false;
return this->EmptyObjectLiteralProperty();
}
}
if (classifier->duplicate_finder() != nullptr &&
scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
classifier->RecordDuplicateFormalParameterError(scanner()->location());
@ -2683,6 +2720,11 @@ ParserBase<Traits>::ParsePropertyDefinition(
}
}
if (in_class && escaped_static && !is_static) {
ReportUnexpectedTokenAt(scanner()->location(), name_token);
*ok = false;
return this->EmptyObjectLiteralProperty();
}
if (is_generator || peek() == Token::LPAREN) {
// MethodDefinition
@ -2732,8 +2774,8 @@ ParserBase<Traits>::ParsePropertyDefinition(
name_token = peek();
name_expression = ParsePropertyName(
&name, &dont_care, &dont_care, &dont_care, is_computed_name, classifier,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
&name, &dont_care, &dont_care, &dont_care, is_computed_name, &dont_care,
&dont_care, classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
if (!*is_computed_name) {
checker->CheckProperty(name_token, kAccessorProperty, is_static,

View File

@ -1177,7 +1177,7 @@ uc32 Scanner::ScanUnicodeEscape() {
static Token::Value KeywordOrIdentifierToken(const uint8_t* input,
int input_length) {
int input_length, bool escaped) {
DCHECK(input_length >= 1);
const int kMinLength = 2;
const int kMaxLength = 10;
@ -1189,26 +1189,30 @@ static Token::Value KeywordOrIdentifierToken(const uint8_t* input,
#define KEYWORD_GROUP_CASE(ch) \
break; \
case ch:
#define KEYWORD(keyword, token) \
{ \
/* 'keyword' is a char array, so sizeof(keyword) is */ \
/* strlen(keyword) plus 1 for the NUL char. */ \
const int keyword_length = sizeof(keyword) - 1; \
STATIC_ASSERT(keyword_length >= kMinLength); \
STATIC_ASSERT(keyword_length <= kMaxLength); \
if (input_length == keyword_length && \
input[1] == keyword[1] && \
(keyword_length <= 2 || input[2] == keyword[2]) && \
(keyword_length <= 3 || input[3] == keyword[3]) && \
(keyword_length <= 4 || input[4] == keyword[4]) && \
(keyword_length <= 5 || input[5] == keyword[5]) && \
(keyword_length <= 6 || input[6] == keyword[6]) && \
(keyword_length <= 7 || input[7] == keyword[7]) && \
(keyword_length <= 8 || input[8] == keyword[8]) && \
(keyword_length <= 9 || input[9] == keyword[9])) { \
return token; \
} \
}
#define KEYWORD(keyword, token) \
{ \
/* 'keyword' is a char array, so sizeof(keyword) is */ \
/* strlen(keyword) plus 1 for the NUL char. */ \
const int keyword_length = sizeof(keyword) - 1; \
STATIC_ASSERT(keyword_length >= kMinLength); \
STATIC_ASSERT(keyword_length <= kMaxLength); \
if (input_length == keyword_length && input[1] == keyword[1] && \
(keyword_length <= 2 || input[2] == keyword[2]) && \
(keyword_length <= 3 || input[3] == keyword[3]) && \
(keyword_length <= 4 || input[4] == keyword[4]) && \
(keyword_length <= 5 || input[5] == keyword[5]) && \
(keyword_length <= 6 || input[6] == keyword[6]) && \
(keyword_length <= 7 || input[7] == keyword[7]) && \
(keyword_length <= 8 || input[8] == keyword[8]) && \
(keyword_length <= 9 || input[9] == keyword[9])) { \
if (escaped) { \
return token == Token::FUTURE_STRICT_RESERVED_WORD \
? Token::ESCAPED_STRICT_RESERVED_WORD \
: Token::ESCAPED_KEYWORD; \
} \
return token; \
} \
}
KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
}
return Token::IDENTIFIER;
@ -1224,7 +1228,7 @@ bool Scanner::IdentifierIsFutureStrictReserved(
return true;
}
return Token::FUTURE_STRICT_RESERVED_WORD ==
KeywordOrIdentifierToken(string->raw_data(), string->length());
KeywordOrIdentifierToken(string->raw_data(), string->length(), false);
}
@ -1257,7 +1261,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
// Only a-z+: could be a keyword or identifier.
literal.Complete();
Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal();
return KeywordOrIdentifierToken(chars.start(), chars.length());
return KeywordOrIdentifierToken(chars.start(), chars.length(), false);
}
HandleLeadSurrogate();
@ -1284,7 +1288,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
return Token::ILLEGAL;
}
AddLiteralChar(c);
return ScanIdentifierSuffix(&literal);
return ScanIdentifierSuffix(&literal, true);
} else {
uc32 first_char = c0_;
Advance();
@ -1300,24 +1304,26 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
continue;
}
// Fallthrough if no longer able to complete keyword.
return ScanIdentifierSuffix(&literal);
return ScanIdentifierSuffix(&literal, false);
}
literal.Complete();
if (next_.literal_chars->is_one_byte()) {
Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal();
return KeywordOrIdentifierToken(chars.start(), chars.length());
return KeywordOrIdentifierToken(chars.start(), chars.length(), false);
}
return Token::IDENTIFIER;
}
Token::Value Scanner::ScanIdentifierSuffix(LiteralScope* literal) {
Token::Value Scanner::ScanIdentifierSuffix(LiteralScope* literal,
bool escaped) {
// Scan the rest of the identifier characters.
while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) {
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
escaped = true;
// Only allow legal identifier part characters.
if (c < 0 ||
c == '\\' ||
@ -1332,6 +1338,10 @@ Token::Value Scanner::ScanIdentifierSuffix(LiteralScope* literal) {
}
literal->Complete();
if (escaped && next_.literal_chars->is_one_byte()) {
Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal();
return KeywordOrIdentifierToken(chars.start(), chars.length(), true);
}
return Token::IDENTIFIER;
}

View File

@ -373,13 +373,10 @@ class Scanner {
Location peek_location() const { return next_.location; }
bool literal_contains_escapes() const {
Location location = current_.location;
int source_length = (location.end_pos - location.beg_pos);
if (current_.token == Token::STRING) {
// Subtract delimiters.
source_length -= 2;
}
return current_.literal_chars->length() != source_length;
return LiteralContainsEscapes(current_);
}
bool next_literal_contains_escapes() const {
return LiteralContainsEscapes(next_);
}
bool is_literal_contextual_keyword(Vector<const char> keyword) {
DCHECK_NOT_NULL(current_.literal_chars);
@ -665,7 +662,7 @@ class Scanner {
void ScanDecimalDigits();
Token::Value ScanNumber(bool seen_period);
Token::Value ScanIdentifierOrKeyword();
Token::Value ScanIdentifierSuffix(LiteralScope* literal);
Token::Value ScanIdentifierSuffix(LiteralScope* literal, bool escaped);
Token::Value ScanString();
@ -689,6 +686,16 @@ class Scanner {
return static_cast<int>(source_->pos()) - kCharacterLookaheadBufferSize;
}
static bool LiteralContainsEscapes(const TokenDesc& token) {
Location location = token.location;
int source_length = (location.end_pos - location.beg_pos);
if (token.token == Token::STRING) {
// Subtract delimiters.
source_length -= 2;
}
return token.literal_chars->length() != source_length;
}
UnicodeCache* unicode_cache_;
// Buffers collecting literal strings, numbers, etc.

View File

@ -160,6 +160,8 @@ namespace internal {
\
/* Illegal token - not able to scan. */ \
T(ILLEGAL, "ILLEGAL", 0) \
T(ESCAPED_KEYWORD, NULL, 0) \
T(ESCAPED_STRICT_RESERVED_WORD, NULL, 0) \
\
/* Scanner-internal use only. */ \
T(WHITESPACE, NULL, 0) \
@ -197,6 +199,7 @@ class Token {
switch (tok) {
case IDENTIFIER:
return true;
case ESCAPED_STRICT_RESERVED_WORD:
case FUTURE_STRICT_RESERVED_WORD:
case LET:
case STATIC:

View File

@ -1532,17 +1532,19 @@ void SetParserFlags(i::ParserBase<Traits>* parser,
void TestParserSyncWithFlags(i::Handle<i::String> source,
i::EnumSet<ParserFlag> flags,
ParserSyncTestResult result) {
ParserSyncTestResult result,
bool is_module = false) {
i::Isolate* isolate = CcTest::i_isolate();
i::Factory* factory = isolate->factory();
uintptr_t stack_limit = isolate->stack_guard()->real_climit();
int preparser_materialized_literals = -1;
int parser_materialized_literals = -2;
bool test_preparser = !is_module;
// Preparse the data.
i::CompleteParserRecorder log;
{
if (test_preparser) {
i::Scanner scanner(isolate->unicode_cache());
i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
i::Zone zone;
@ -1556,7 +1558,6 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
&preparser_materialized_literals);
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
}
bool preparse_error = log.HasError();
// Parse the data
@ -1567,7 +1568,11 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
i::ParseInfo info(&zone, script);
i::Parser parser(&info);
SetParserFlags(&parser, flags);
info.set_global();
if (is_module) {
info.set_module();
} else {
info.set_global();
}
parser.Parse(&info);
function = info.literal();
if (function) {
@ -1596,7 +1601,7 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
CHECK(false);
}
if (!preparse_error) {
if (test_preparser && !preparse_error) {
v8::base::OS::Print(
"Parser failed on:\n"
"\t%s\n"
@ -1607,21 +1612,22 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
CHECK(false);
}
// Check that preparser and parser produce the same error.
i::Handle<i::String> preparser_message =
FormatMessage(log.ErrorMessageData());
if (!i::String::Equals(message_string, preparser_message)) {
v8::base::OS::Print(
"Expected parser and preparser to produce the same error on:\n"
"\t%s\n"
"However, found the following error messages\n"
"\tparser: %s\n"
"\tpreparser: %s\n",
source->ToCString().get(),
message_string->ToCString().get(),
preparser_message->ToCString().get());
CHECK(false);
if (test_preparser) {
i::Handle<i::String> preparser_message =
FormatMessage(log.ErrorMessageData());
if (!i::String::Equals(message_string, preparser_message)) {
v8::base::OS::Print(
"Expected parser and preparser to produce the same error on:\n"
"\t%s\n"
"However, found the following error messages\n"
"\tparser: %s\n"
"\tpreparser: %s\n",
source->ToCString().get(), message_string->ToCString().get(),
preparser_message->ToCString().get());
CHECK(false);
}
}
} else if (preparse_error) {
} else if (test_preparser && preparse_error) {
v8::base::OS::Print(
"Preparser failed on:\n"
"\t%s\n"
@ -1638,7 +1644,8 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
"However, parser and preparser succeeded",
source->ToCString().get());
CHECK(false);
} else if (preparser_materialized_literals != parser_materialized_literals) {
} else if (test_preparser &&
preparser_materialized_literals != parser_materialized_literals) {
v8::base::OS::Print(
"Preparser materialized literals (%d) differ from Parser materialized "
"literals (%d) on:\n"
@ -1651,14 +1658,14 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
}
void TestParserSync(const char* source,
const ParserFlag* varying_flags,
void TestParserSync(const char* source, const ParserFlag* varying_flags,
size_t varying_flags_length,
ParserSyncTestResult result = kSuccessOrError,
const ParserFlag* always_true_flags = NULL,
size_t always_true_flags_length = 0,
const ParserFlag* always_false_flags = NULL,
size_t always_false_flags_length = 0) {
size_t always_false_flags_length = 0,
bool is_module = false) {
i::Handle<i::String> str =
CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source);
for (int bits = 0; bits < (1 << varying_flags_length); bits++) {
@ -1675,7 +1682,7 @@ void TestParserSync(const char* source,
++flag_index) {
flags.Remove(always_false_flags[flag_index]);
}
TestParserSyncWithFlags(str, flags, result);
TestParserSyncWithFlags(str, flags, result, is_module);
}
}
@ -1819,12 +1826,11 @@ TEST(StrictOctal) {
void RunParserSyncTest(const char* context_data[][2],
const char* statement_data[],
ParserSyncTestResult result,
const ParserFlag* flags = NULL,
int flags_len = 0,
const ParserFlag* flags = NULL, int flags_len = 0,
const ParserFlag* always_true_flags = NULL,
int always_true_len = 0,
const ParserFlag* always_false_flags = NULL,
int always_false_len = 0) {
int always_false_len = 0, bool is_module = false) {
v8::HandleScope handles(CcTest::isolate());
v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
v8::Context::Scope context_scope(context);
@ -1877,20 +1883,32 @@ void RunParserSyncTest(const char* context_data[][2],
statement_data[j],
context_data[i][1]);
CHECK(length == kProgramSize);
TestParserSync(program.start(),
flags,
flags_len,
result,
always_true_flags,
always_true_len,
always_false_flags,
always_false_len);
TestParserSync(program.start(), flags, flags_len, result,
always_true_flags, always_true_len, always_false_flags,
always_false_len, is_module);
}
}
delete[] generated_flags;
}
void RunModuleParserSyncTest(const char* context_data[][2],
const char* statement_data[],
ParserSyncTestResult result,
const ParserFlag* flags = NULL, int flags_len = 0,
const ParserFlag* always_true_flags = NULL,
int always_true_len = 0,
const ParserFlag* always_false_flags = NULL,
int always_false_len = 0) {
bool flag = i::FLAG_harmony_modules;
i::FLAG_harmony_modules = true;
RunParserSyncTest(context_data, statement_data, result, flags, flags_len,
always_true_flags, always_true_len, always_false_flags,
always_false_len, true);
i::FLAG_harmony_modules = flag;
}
TEST(ErrorsEvalAndArguments) {
// Tests that both preparsing and parsing produce the right kind of errors for
// using "eval" and "arguments" as identifiers. Without the strict mode, it's
@ -7305,3 +7323,151 @@ TEST(LetSloppyOnly) {
RunParserSyncTest(context_data, fail_data, kError, NULL, 0, fail_flags,
arraysize(fail_flags));
}
TEST(EscapedKeywords) {
// clang-format off
const char* sloppy_context_data[][2] = {
{"", ""},
{NULL, NULL}
};
const char* strict_context_data[][2] = {
{"'use strict';", ""},
{NULL, NULL}
};
const char* fail_data[] = {
"for (var i = 0; i < 100; ++i) { br\\u0065ak; }",
"cl\\u0061ss Foo {}",
"var x = cl\\u0061ss {}",
"\\u0063onst foo = 1;",
"while (i < 10) { if (i++ & 1) c\\u006fntinue; this.x++; }",
"d\\u0065bugger;",
"d\\u0065lete this.a;",
"\\u0063o { } while(0)",
"if (d\\u006f { true }) {}",
"if (false) { this.a = 1; } \\u0065lse { this.b = 1; }",
"e\\u0078port var foo;",
"try { } catch (e) {} f\\u0069nally { }",
"f\\u006fr (var i = 0; i < 10; ++i);",
"f\\u0075nction fn() {}",
"var f = f\\u0075nction() {}",
"\\u0069f (true) { }",
"\\u0069mport blah from './foo.js';",
"n\\u0065w function f() {}",
"(function() { r\\u0065turn; })()",
"class C extends function() {} { constructor() { sup\\u0065r() } }",
"class C extends function() {} { constructor() { sup\\u0065r.a = 1 } }",
"sw\\u0069tch (this.a) {}",
"var x = th\\u0069s;",
"th\\u0069s.a = 1;",
"thr\\u006fw 'boo';",
"t\\u0072y { true } catch (e) {}",
"var x = typ\\u0065of 'blah'",
"v\\u0061r a = true",
"var v\\u0061r = true",
"(function() { return v\\u006fid 0; })()",
"wh\\u0069le (true) { }",
"w\\u0069th (this.scope) { }",
"(function*() { y\\u0069eld 1; })()",
"var \\u0065num = 1;",
"var { \\u0065num } = {}",
"(\\u0065num = 1);",
// Null / Boolean literals
"(x === n\\u0075ll);",
"var x = n\\u0075ll;",
"var n\\u0075ll = 1;",
"var { n\\u0075ll } = { 1 };",
"n\\u0075ll = 1;",
"(x === tr\\u0075e);",
"var x = tr\\u0075e;",
"var tr\\u0075e = 1;",
"var { tr\\u0075e } = {};",
"tr\\u0075e = 1;",
"(x === f\\u0061lse);",
"var x = f\\u0061lse;",
"var f\\u0061lse = 1;",
"var { f\\u0061lse } = {};",
"f\\u0061lse = 1;",
// TODO(caitp): consistent error messages for labeled statements and
// expressions
"switch (this.a) { c\\u0061se 6: break; }",
"try { } c\\u0061tch (e) {}",
"switch (this.a) { d\\u0065fault: break; }",
"class C \\u0065xtends function B() {} {}",
"for (var a i\\u006e this) {}",
"if ('foo' \\u0069n this) {}",
"if (this \\u0069nstanceof Array) {}",
"(n\\u0065w function f() {})",
"(typ\\u0065of 123)",
"(v\\u006fid 0)",
"do { ; } wh\\u0069le (true) { }",
"(function*() { return (n++, y\\u0069eld 1); })()",
"class C { st\\u0061tic bar() {} }",
"(y\\u0069eld);",
"var y\\u0069eld = 1;",
"var { y\\u0069eld } = {};",
NULL
};
// clang-format on
static const ParserFlag always_flags[] = {kAllowHarmonySloppy,
kAllowHarmonyDestructuring};
RunParserSyncTest(sloppy_context_data, fail_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
RunParserSyncTest(strict_context_data, fail_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
RunModuleParserSyncTest(sloppy_context_data, fail_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
// clang-format off
const char* let_data[] = {
"var l\\u0065t = 1;",
"l\\u0065t = 1;",
"(l\\u0065t === 1);",
NULL
};
// clang-format on
RunParserSyncTest(sloppy_context_data, let_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
RunParserSyncTest(strict_context_data, let_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
static const ParserFlag sloppy_let_flags[] = {
kAllowHarmonySloppy, kAllowHarmonySloppyLet, kAllowHarmonyDestructuring};
RunParserSyncTest(sloppy_context_data, let_data, kError, NULL, 0,
sloppy_let_flags, arraysize(sloppy_let_flags));
// Non-errors in sloppy mode
const char* valid_data[] = {"(\\u0069mplements = 1);",
"var impl\\u0065ments = 1;",
"var { impl\\u0065ments } = {};",
"(\\u0069nterface = 1);",
"var int\\u0065rface = 1;",
"var { int\\u0065rface } = {};",
"(p\\u0061ckage = 1);",
"var packa\\u0067e = 1;",
"var { packa\\u0067e } = {};",
"(p\\u0072ivate = 1);",
"var p\\u0072ivate;",
"var { p\\u0072ivate } = {};",
"(prot\\u0065cted);",
"var prot\\u0065cted = 1;",
"var { prot\\u0065cted } = {};",
"(publ\\u0069c);",
"var publ\\u0069c = 1;",
"var { publ\\u0069c } = {};",
NULL};
RunParserSyncTest(sloppy_context_data, valid_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
RunParserSyncTest(strict_context_data, valid_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
RunModuleParserSyncTest(strict_context_data, valid_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
}

View File

@ -90,6 +90,9 @@
# ES2015 ToLength semantics
'ecma_3/RegExp/15.10.6.2-2': [FAIL],
# Escaped keywords are early errors in ES6
'ecma_3/Unicode/uc-003': [FAIL],
# RegExp.multiline is not part of any ECMAScript specification, and is
# slated for deprecation in Mozilla
# (https://bugzilla.mozilla.org/show_bug.cgi?id=1220457)

View File

@ -374,78 +374,6 @@
# https://code.google.com/p/v8/issues/detail?id=4361
'intl402/Collator/10.1.1_a': [FAIL],
# https://code.google.com/p/v8/issues/detail?id=1972
'language/identifiers/val-break-via-escape-hex': [FAIL],
'language/identifiers/val-break-via-escape-hex4': [FAIL],
'language/identifiers/val-case-via-escape-hex': [FAIL],
'language/identifiers/val-case-via-escape-hex4': [FAIL],
'language/identifiers/val-catch-via-escape-hex': [FAIL],
'language/identifiers/val-catch-via-escape-hex4': [FAIL],
'language/identifiers/val-class-via-escape-hex': [FAIL],
'language/identifiers/val-class-via-escape-hex4': [FAIL],
'language/identifiers/val-const-via-escape-hex': [FAIL],
'language/identifiers/val-const-via-escape-hex4': [FAIL],
'language/identifiers/val-continue-via-escape-hex': [FAIL],
'language/identifiers/val-continue-via-escape-hex4': [FAIL],
'language/identifiers/val-debugger-via-escape-hex': [FAIL],
'language/identifiers/val-debugger-via-escape-hex4': [FAIL],
'language/identifiers/val-default-via-escape-hex': [FAIL],
'language/identifiers/val-default-via-escape-hex4': [FAIL],
'language/identifiers/val-delete-via-escape-hex': [FAIL],
'language/identifiers/val-delete-via-escape-hex4': [FAIL],
'language/identifiers/val-do-via-escape-hex': [FAIL],
'language/identifiers/val-do-via-escape-hex4': [FAIL],
'language/identifiers/val-else-via-escape-hex': [FAIL],
'language/identifiers/val-else-via-escape-hex4': [FAIL],
'language/identifiers/val-enum-via-escape-hex': [FAIL],
'language/identifiers/val-enum-via-escape-hex4': [FAIL],
'language/identifiers/val-export-via-escape-hex': [FAIL],
'language/identifiers/val-export-via-escape-hex4': [FAIL],
'language/identifiers/val-extends-via-escape-hex': [FAIL],
'language/identifiers/val-extends-via-escape-hex4': [FAIL],
'language/identifiers/val-false-via-escape-hex': [FAIL],
'language/identifiers/val-false-via-escape-hex4': [FAIL],
'language/identifiers/val-finally-via-escape-hex': [FAIL],
'language/identifiers/val-finally-via-escape-hex4': [FAIL],
'language/identifiers/val-for-via-escape-hex': [FAIL],
'language/identifiers/val-for-via-escape-hex4': [FAIL],
'language/identifiers/val-function-via-escape-hex': [FAIL],
'language/identifiers/val-function-via-escape-hex4': [FAIL],
'language/identifiers/val-if-via-escape-hex': [FAIL],
'language/identifiers/val-if-via-escape-hex4': [FAIL],
'language/identifiers/val-import-via-escape-hex': [FAIL],
'language/identifiers/val-import-via-escape-hex4': [FAIL],
'language/identifiers/val-in-via-escape-hex': [FAIL],
'language/identifiers/val-in-via-escape-hex4': [FAIL],
'language/identifiers/val-instanceof-via-escape-hex': [FAIL],
'language/identifiers/val-instanceof-via-escape-hex4': [FAIL],
'language/identifiers/val-new-via-escape-hex': [FAIL],
'language/identifiers/val-new-via-escape-hex4': [FAIL],
'language/identifiers/val-null-via-escape-hex': [FAIL],
'language/identifiers/val-null-via-escape-hex4': [FAIL],
'language/identifiers/val-return-via-escape-hex': [FAIL],
'language/identifiers/val-return-via-escape-hex4': [FAIL],
'language/identifiers/val-super-via-escape-hex': [FAIL],
'language/identifiers/val-super-via-escape-hex4': [FAIL],
'language/identifiers/val-switch-via-escape-hex': [FAIL],
'language/identifiers/val-switch-via-escape-hex4': [FAIL],
'language/identifiers/val-throw-via-escape-hex': [FAIL],
'language/identifiers/val-throw-via-escape-hex4': [FAIL],
'language/identifiers/val-true-via-escape-hex': [FAIL],
'language/identifiers/val-true-via-escape-hex4': [FAIL],
'language/identifiers/val-try-via-escape-hex': [FAIL],
'language/identifiers/val-try-via-escape-hex4': [FAIL],
'language/identifiers/val-typeof-via-escape-hex': [FAIL],
'language/identifiers/val-typeof-via-escape-hex4': [FAIL],
'language/identifiers/val-var-via-escape-hex': [FAIL],
'language/identifiers/val-var-via-escape-hex4': [FAIL],
'language/identifiers/val-void-via-escape-hex': [FAIL],
'language/identifiers/val-void-via-escape-hex4': [FAIL],
'language/identifiers/val-while-via-escape-hex': [FAIL],
'language/identifiers/val-while-via-escape-hex4': [FAIL],
'language/identifiers/val-with-via-escape-hex': [FAIL],
'language/identifiers/val-with-via-escape-hex4': [FAIL],
# https://code.google.com/p/v8/issues/detail?id=4362
'built-ins/String/prototype/repeat/empty-string-returns-empty': [PASS, FAIL],