"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"
break;
default: {
- Next();
+ Token::Value next = Next();
+ ReportUnexpectedToken(next);
*ok = false;
return Expression::Default();
}
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();
}
}
}
}
}
+
+
+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));
+ }
+ }
+}