Commit 23cbf27e authored by marja@chromium.org's avatar marja@chromium.org

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
parent 35354cb9
......@@ -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));
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment