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);
|
"unexpected_token_identifier", NULL);
|
||||||
case Token::FUTURE_RESERVED_WORD:
|
case Token::FUTURE_RESERVED_WORD:
|
||||||
return ReportMessageAt(source_location, "unexpected_reserved", NULL);
|
return ReportMessageAt(source_location, "unexpected_reserved", NULL);
|
||||||
|
case Token::YIELD:
|
||||||
case Token::FUTURE_STRICT_RESERVED_WORD:
|
case Token::FUTURE_STRICT_RESERVED_WORD:
|
||||||
return ReportMessageAt(source_location,
|
return ReportMessageAt(source_location,
|
||||||
is_classic_mode() ? "unexpected_token_identifier"
|
is_classic_mode() ? "unexpected_token_identifier"
|
||||||
@ -1183,7 +1184,8 @@ PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
Next();
|
Token::Value next = Next();
|
||||||
|
ReportUnexpectedToken(next);
|
||||||
*ok = false;
|
*ok = false;
|
||||||
return Expression::Default();
|
return Expression::Default();
|
||||||
}
|
}
|
||||||
@ -1493,35 +1495,15 @@ PreParser::Identifier PreParser::GetIdentifierSymbol() {
|
|||||||
|
|
||||||
PreParser::Identifier PreParser::ParseIdentifier(bool* ok) {
|
PreParser::Identifier PreParser::ParseIdentifier(bool* ok) {
|
||||||
Token::Value next = Next();
|
Token::Value next = Next();
|
||||||
switch (next) {
|
if (next == Token::IDENTIFIER ||
|
||||||
case Token::FUTURE_RESERVED_WORD: {
|
(is_classic_mode() &&
|
||||||
Scanner::Location location = scanner()->location();
|
(next == Token::FUTURE_STRICT_RESERVED_WORD ||
|
||||||
ReportMessageAt(location.beg_pos, location.end_pos,
|
(next == Token::YIELD && !scope_->is_generator())))) {
|
||||||
"unexpected_reserved", NULL);
|
return GetIdentifierSymbol();
|
||||||
*ok = false;
|
} else {
|
||||||
return GetIdentifierSymbol();
|
ReportUnexpectedToken(next);
|
||||||
}
|
*ok = false;
|
||||||
case Token::YIELD:
|
return Identifier::Default();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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