Classes: static should still be treated as a strict reserved word

When --harmony-classes is enabled we did not treat static as a
strict reserved word.

BUG=v8:3642
LOG=Y
R=rossberg@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#25087}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25087 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
arv@chromium.org 2014-11-03 19:53:36 +00:00
parent e525e76f21
commit 7a63c74caf
5 changed files with 98 additions and 48 deletions

View File

@ -853,8 +853,7 @@ class Parser : public ParserBase<ParserTraits> {
bool ParserTraits::IsFutureStrictReserved(
const AstRawString* identifier) const {
return identifier->IsOneByteEqualTo("yield") ||
parser_->scanner()->IdentifierIsFutureStrictReserved(identifier);
return parser_->scanner()->IdentifierIsFutureStrictReserved(identifier);
}

View File

@ -50,6 +50,8 @@ PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) {
return PreParserIdentifier::FutureStrictReserved();
} else if (scanner->current_token() == Token::LET) {
return PreParserIdentifier::Let();
} else if (scanner->current_token() == Token::STATIC) {
return PreParserIdentifier::Static();
} else if (scanner->current_token() == Token::YIELD) {
return PreParserIdentifier::Yield();
}
@ -491,8 +493,7 @@ PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(bool* ok) {
// identifier.
DCHECK(!expr.AsIdentifier().IsFutureReserved());
DCHECK(strict_mode() == SLOPPY ||
(!expr.AsIdentifier().IsFutureStrictReserved() &&
!expr.AsIdentifier().IsYield()));
!IsFutureStrictReserved(expr.AsIdentifier()));
Consume(Token::COLON);
return ParseStatement(ok);
// Preparsing is disabled for extensions (because the extension details

View File

@ -336,11 +336,9 @@ class ParserBase : public Traits {
bool peek_any_identifier() {
Token::Value next = peek();
return next == Token::IDENTIFIER ||
next == Token::FUTURE_RESERVED_WORD ||
next == Token::FUTURE_STRICT_RESERVED_WORD ||
next == Token::LET ||
next == Token::YIELD;
return next == Token::IDENTIFIER || next == Token::FUTURE_RESERVED_WORD ||
next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
next == Token::STATIC || next == Token::YIELD;
}
bool CheckContextualKeyword(Vector<const char> keyword) {
@ -606,6 +604,9 @@ class PreParserIdentifier {
static PreParserIdentifier Let() {
return PreParserIdentifier(kLetIdentifier);
}
static PreParserIdentifier Static() {
return PreParserIdentifier(kStaticIdentifier);
}
static PreParserIdentifier Yield() {
return PreParserIdentifier(kYieldIdentifier);
}
@ -619,6 +620,8 @@ class PreParserIdentifier {
bool IsArguments(const AstValueFactory* = NULL) const {
return type_ == kArgumentsIdentifier;
}
bool IsLet() const { return type_ == kLetIdentifier; }
bool IsStatic() const { return type_ == kStaticIdentifier; }
bool IsYield() const { return type_ == kYieldIdentifier; }
bool IsPrototype() const { return type_ == kPrototypeIdentifier; }
bool IsConstructor() const { return type_ == kConstructorIdentifier; }
@ -627,14 +630,15 @@ class PreParserIdentifier {
}
bool IsFutureReserved() const { return type_ == kFutureReservedIdentifier; }
bool IsFutureStrictReserved() const {
return type_ == kFutureStrictReservedIdentifier;
return type_ == kFutureStrictReservedIdentifier ||
type_ == kLetIdentifier || type_ == kStaticIdentifier ||
type_ == kYieldIdentifier;
}
bool IsValidStrictVariable() const { return type_ == kUnknownIdentifier; }
V8_INLINE bool IsValidArrowParam() const {
// A valid identifier can be an arrow function parameter
// except for eval, arguments, yield, and reserved keywords.
return !(IsEval() || IsArguments() || IsYield() ||
IsFutureStrictReserved());
return !(IsEval() || IsArguments() || IsFutureStrictReserved());
}
// Allow identifier->name()[->length()] to work. The preparser
@ -651,6 +655,7 @@ class PreParserIdentifier {
kFutureReservedIdentifier,
kFutureStrictReservedIdentifier,
kLetIdentifier,
kStaticIdentifier,
kYieldIdentifier,
kEvalIdentifier,
kArgumentsIdentifier,
@ -1172,7 +1177,7 @@ class PreParserTraits {
}
static bool IsFutureStrictReserved(PreParserIdentifier identifier) {
return identifier.IsYield() || identifier.IsFutureStrictReserved();
return identifier.IsFutureStrictReserved();
}
static bool IsBoilerplateProperty(PreParserExpression property) {
@ -1593,6 +1598,7 @@ void ParserBase<Traits>::ReportUnexpectedToken(Token::Value token) {
case Token::FUTURE_RESERVED_WORD:
return ReportMessageAt(source_location, "unexpected_reserved");
case Token::LET:
case Token::STATIC:
case Token::YIELD:
case Token::FUTURE_STRICT_RESERVED_WORD:
return ReportMessageAt(source_location, strict_mode() == SLOPPY
@ -1622,8 +1628,8 @@ typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParseIdentifier(
return name;
} else if (strict_mode() == SLOPPY &&
(next == Token::FUTURE_STRICT_RESERVED_WORD ||
(next == Token::LET) ||
(next == Token::YIELD && !is_generator()))) {
next == Token::LET || next == Token::STATIC ||
(next == Token::YIELD && !is_generator()))) {
return this->GetSymbol(scanner());
} else {
this->ReportUnexpectedToken(next);
@ -1640,8 +1646,8 @@ typename ParserBase<Traits>::IdentifierT ParserBase<
Token::Value next = Next();
if (next == Token::IDENTIFIER) {
*is_strict_reserved = false;
} else if (next == Token::FUTURE_STRICT_RESERVED_WORD ||
next == Token::LET ||
} else if (next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
next == Token::STATIC ||
(next == Token::YIELD && !this->is_generator())) {
*is_strict_reserved = true;
} else {
@ -1662,7 +1668,7 @@ typename ParserBase<Traits>::IdentifierT
ParserBase<Traits>::ParseIdentifierName(bool* ok) {
Token::Value next = Next();
if (next != Token::IDENTIFIER && next != Token::FUTURE_RESERVED_WORD &&
next != Token::LET && next != Token::YIELD &&
next != Token::LET && next != Token::STATIC && next != Token::YIELD &&
next != Token::FUTURE_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
this->ReportUnexpectedToken(next);
*ok = false;
@ -1765,6 +1771,7 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) {
case Token::IDENTIFIER:
case Token::LET:
case Token::STATIC:
case Token::YIELD:
case Token::FUTURE_STRICT_RESERVED_WORD: {
// Using eval or arguments in this context is OK even in strict mode.

View File

@ -1006,11 +1006,15 @@ static Token::Value KeywordOrIdentifierToken(const uint8_t* input,
bool Scanner::IdentifierIsFutureStrictReserved(
const AstRawString* string) const {
// Keywords are always 1-byte strings.
return string->is_one_byte() &&
Token::FUTURE_STRICT_RESERVED_WORD ==
KeywordOrIdentifierToken(string->raw_data(), string->length(),
harmony_scoping_, harmony_modules_,
harmony_classes_);
if (!string->is_one_byte()) return false;
if (string->IsOneByteEqualTo("let") || string->IsOneByteEqualTo("static") ||
string->IsOneByteEqualTo("yield")) {
return true;
}
return Token::FUTURE_STRICT_RESERVED_WORD ==
KeywordOrIdentifierToken(string->raw_data(), string->length(),
harmony_scoping_, harmony_modules_,
harmony_classes_);
}

View File

@ -1814,6 +1814,33 @@ TEST(NoErrorsEvalAndArgumentsStrict) {
}
#define FUTURE_STRICT_RESERVED_WORDS(V) \
V(implements) \
V(interface) \
V(let) \
V(package) \
V(private) \
V(protected) \
V(public) \
V(static) \
V(yield)
#define FUTURE_STRICT_RESERVED_STATEMENTS(NAME) \
"var " #NAME ";", \
"var foo, " #NAME ";", \
"try { } catch (" #NAME ") { }", \
"function " #NAME "() { }", \
"(function " #NAME "() { })", \
"function foo(" #NAME ") { }", \
"function foo(bar, " #NAME ") { }", \
#NAME " = 1;", \
#NAME " += 1;", \
"var foo = " #NAME " = 1;", \
"++" #NAME ";", \
#NAME " ++;",
TEST(ErrorsFutureStrictReservedWords) {
// Tests that both preparsing and parsing produce the right kind of errors for
// using future strict reserved words as identifiers. Without the strict mode,
@ -1826,24 +1853,19 @@ TEST(ErrorsFutureStrictReservedWords) {
{ NULL, NULL }
};
const char* statement_data[] = {
"var interface;",
"var foo, interface;",
"try { } catch (interface) { }",
"function interface() { }",
"function foo(interface) { }",
"function foo(bar, interface) { }",
"interface = 1;",
"var foo = interface = 1;",
"++interface;",
"interface++;",
"var yield = 13;",
const char* statement_data[] {
FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
NULL
};
static const ParserFlag always_flags[] = {kAllowArrowFunctions};
RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
arraysize(always_flags));
static const ParserFlag classes_flags[] = {
kAllowArrowFunctions, kAllowClasses, kAllowHarmonyScoping};
RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
classes_flags, arraysize(classes_flags));
}
@ -1856,23 +1878,18 @@ TEST(NoErrorsFutureStrictReservedWords) {
};
const char* statement_data[] = {
"var interface;",
"var foo, interface;",
"try { } catch (interface) { }",
"function interface() { }",
"function foo(interface) { }",
"function foo(bar, interface) { }",
"interface = 1;",
"var foo = interface = 1;",
"++interface;",
"interface++;",
"var yield = 13;",
FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
NULL
};
static const ParserFlag always_flags[] = {kAllowArrowFunctions};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
static const ParserFlag classes_flags[] = {
kAllowArrowFunctions, kAllowClasses, kAllowHarmonyScoping};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
classes_flags, arraysize(classes_flags));
}
@ -2252,12 +2269,13 @@ TEST(ErrorsIllegalWordsAsLabelsStrict) {
{ NULL, NULL }
};
#define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
const char* statement_data[] = {
"super: while(true) { break super; }",
"interface: while(true) { break interface; }",
"yield: while(true) { break yield; }",
FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
NULL
};
#undef LABELLED_WHILE
RunParserSyncTest(context_data, statement_data, kError);
}
@ -2288,6 +2306,27 @@ TEST(NoErrorsIllegalWordsAsLabels) {
}
TEST(NoErrorsFutureStrictReservedAsLabelsSloppy) {
const char* context_data[][2] = {
{ "", ""},
{ "function test_func() {", "}" },
{ "() => {", "}" },
{ NULL, NULL }
};
#define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
const char* statement_data[] {
FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
NULL
};
#undef LABELLED_WHILE
static const ParserFlag always_flags[] = {kAllowArrowFunctions};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
TEST(ErrorsParenthesizedLabels) {
// Parenthesized identifiers shouldn't be recognized as labels.
const char* context_data[][2] = {