Tests for (pre)parse errors when "yield" is found in inappropriate places.
In addition: - Fix: PreParser used to report an unexpected token one token too late when ParsePrimaryExpression failed. - Unified identifier handling (PreParser::GetIdentifier is now like Parser::GetIdentifier). - Fix: PreParser used to produce "unexpected_token YIELD" errors when Parser produced "unexpected_token_identifier"; fixed PreParser to match Parser. BUG=3126 LOG=N R=ulan@chromium.org Review URL: https://codereview.chromium.org/151103006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19082 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
35354cb9b7
commit
23cbf27e12
@ -119,6 +119,7 @@ void PreParser::ReportUnexpectedToken(Token::Value token) {
|
||||
"unexpected_token_identifier", NULL);
|
||||
case Token::FUTURE_RESERVED_WORD:
|
||||
return ReportMessageAt(source_location, "unexpected_reserved", NULL);
|
||||
case Token::YIELD:
|
||||
case Token::FUTURE_STRICT_RESERVED_WORD:
|
||||
return ReportMessageAt(source_location,
|
||||
is_classic_mode() ? "unexpected_token_identifier"
|
||||
@ -1183,7 +1184,8 @@ PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) {
|
||||
break;
|
||||
|
||||
default: {
|
||||
Next();
|
||||
Token::Value next = Next();
|
||||
ReportUnexpectedToken(next);
|
||||
*ok = false;
|
||||
return Expression::Default();
|
||||
}
|
||||
@ -1493,35 +1495,15 @@ PreParser::Identifier PreParser::GetIdentifierSymbol() {
|
||||
|
||||
PreParser::Identifier PreParser::ParseIdentifier(bool* ok) {
|
||||
Token::Value next = Next();
|
||||
switch (next) {
|
||||
case Token::FUTURE_RESERVED_WORD: {
|
||||
Scanner::Location location = scanner()->location();
|
||||
ReportMessageAt(location.beg_pos, location.end_pos,
|
||||
"unexpected_reserved", NULL);
|
||||
*ok = false;
|
||||
return GetIdentifierSymbol();
|
||||
}
|
||||
case Token::YIELD:
|
||||
if (scope_->is_generator()) {
|
||||
// 'yield' in a generator is only valid as part of a YieldExpression.
|
||||
ReportMessageAt(scanner()->location(), "unexpected_token", "yield");
|
||||
*ok = false;
|
||||
return Identifier::Yield();
|
||||
}
|
||||
// FALLTHROUGH
|
||||
case Token::FUTURE_STRICT_RESERVED_WORD:
|
||||
if (!is_classic_mode()) {
|
||||
Scanner::Location location = scanner()->location();
|
||||
ReportMessageAt(location.beg_pos, location.end_pos,
|
||||
"unexpected_strict_reserved", NULL);
|
||||
*ok = false;
|
||||
}
|
||||
// FALLTHROUGH
|
||||
case Token::IDENTIFIER:
|
||||
return GetIdentifierSymbol();
|
||||
default:
|
||||
*ok = false;
|
||||
return Identifier::Default();
|
||||
if (next == Token::IDENTIFIER ||
|
||||
(is_classic_mode() &&
|
||||
(next == Token::FUTURE_STRICT_RESERVED_WORD ||
|
||||
(next == Token::YIELD && !scope_->is_generator())))) {
|
||||
return GetIdentifierSymbol();
|
||||
} else {
|
||||
ReportUnexpectedToken(next);
|
||||
*ok = false;
|
||||
return Identifier::Default();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1531,3 +1531,68 @@ TEST(ErrorsReservedWords) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ErrorsYield) {
|
||||
// Tests that both preparsing and parsing produce the right kind of errors for
|
||||
// using yield as identifier. In non-strict mode, it's okay to use "yield" as
|
||||
// an identifier, *except* inside a generator function. In strict mode, it's
|
||||
// never okay.
|
||||
const char* context_data[][2] = {
|
||||
{ "", "" },
|
||||
{ "\"use strict\";", "}" },
|
||||
{ "var eval; function test_func() {", "}"},
|
||||
{ "var eval; function test_func() {\"use strict\"; ", "}"},
|
||||
{ "function is_not_gen() {", "}" },
|
||||
{ "function * is_gen() {", "}" },
|
||||
{ "\"use strict\"; function is_not_gen() {", "}" },
|
||||
{ "\"use strict\"; function * is_gen() {", "}" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
const char* statement_data[] = {
|
||||
"var yield;",
|
||||
"var foo, yield;",
|
||||
"try { } catch (yield) { }",
|
||||
"function yield() { }",
|
||||
"function foo(yield) { }",
|
||||
"function foo(bar, yield) { }",
|
||||
"yield = 1;",
|
||||
"++yield;",
|
||||
"yield++;",
|
||||
"yield 2;", // this is legal inside generator
|
||||
"yield * 2;", // this is legal inside generator
|
||||
NULL
|
||||
};
|
||||
|
||||
v8::HandleScope handles(CcTest::isolate());
|
||||
v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
int marker;
|
||||
CcTest::i_isolate()->stack_guard()->SetStackLimit(
|
||||
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
|
||||
|
||||
static const ParserFlag flags[] = {
|
||||
kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators,
|
||||
kAllowForOf
|
||||
};
|
||||
for (int i = 0; context_data[i][0] != NULL; ++i) {
|
||||
for (int j = 0; statement_data[j] != NULL; ++j) {
|
||||
int kPrefixLen = i::StrLength(context_data[i][0]);
|
||||
int kStatementLen = i::StrLength(statement_data[j]);
|
||||
int kSuffixLen = i::StrLength(context_data[i][1]);
|
||||
int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen;
|
||||
|
||||
// Plug the source code pieces together.
|
||||
i::ScopedVector<char> program(kProgramSize + 1);
|
||||
int length = i::OS::SNPrintF(program,
|
||||
"%s%s%s",
|
||||
context_data[i][0],
|
||||
statement_data[j],
|
||||
context_data[i][1]);
|
||||
CHECK(length == kProgramSize);
|
||||
TestParserSync(program.start(), flags, ARRAY_SIZE(flags));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user