From: marja@chromium.org Date: Tue, 4 Feb 2014 18:16:45 +0000 (+0000) Subject: Tests for (pre)parse errors when "yield" is found in inappropriate places. X-Git-Tag: upstream/4.7.83~10879 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=23cbf27e12106b21630fd29d3614554dba1f2663;p=platform%2Fupstream%2Fv8.git 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 --- diff --git a/src/preparser.cc b/src/preparser.cc index b3a271a..c14d141 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -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(); } } diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index acd0771..ad8b8f9 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -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 context = v8::Context::New(CcTest::isolate()); + v8::Context::Scope context_scope(context); + + int marker; + CcTest::i_isolate()->stack_guard()->SetStackLimit( + reinterpret_cast(&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 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)); + } + } +}