| Index: src/parser.cc
|
| diff --git a/src/parser.cc b/src/parser.cc
|
| index 77c98b77e4c0cd6aadb003ec1965f82d879c30c8..597951c09325e4adbdf04bfc6797cc73ac914b73 100644
|
| --- a/src/parser.cc
|
| +++ b/src/parser.cc
|
| @@ -1819,13 +1819,23 @@ Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels,
|
| return ParseForStatement(labels, ok);
|
|
|
| case Token::CONTINUE:
|
| - return ParseContinueStatement(ok);
|
| -
|
| case Token::BREAK:
|
| - return ParseBreakStatement(labels, ok);
|
| -
|
| case Token::RETURN:
|
| - return ParseReturnStatement(ok);
|
| + case Token::THROW:
|
| + case Token::TRY: {
|
| + // These statements must have their labels preserved in an enclosing
|
| + // block
|
| + if (labels == NULL) {
|
| + return ParseStatementAsUnlabelled(labels, ok);
|
| + } else {
|
| + Block* result =
|
| + factory()->NewBlock(labels, 1, false, RelocInfo::kNoPosition);
|
| + Target target(&this->target_stack_, result);
|
| + Statement* statement = ParseStatementAsUnlabelled(labels, CHECK_OK);
|
| + if (result) result->AddStatement(statement, zone());
|
| + return result;
|
| + }
|
| + }
|
|
|
| case Token::WITH:
|
| return ParseWithStatement(labels, ok);
|
| @@ -1833,23 +1843,6 @@ Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels,
|
| case Token::SWITCH:
|
| return ParseSwitchStatement(labels, ok);
|
|
|
| - case Token::THROW:
|
| - return ParseThrowStatement(ok);
|
| -
|
| - case Token::TRY: {
|
| - // NOTE: It is somewhat complicated to have labels on
|
| - // try-statements. When breaking out of a try-finally statement,
|
| - // one must take great care not to treat it as a
|
| - // fall-through. It is much easier just to wrap the entire
|
| - // try-statement in a statement block and put the labels there
|
| - Block* result =
|
| - factory()->NewBlock(labels, 1, false, RelocInfo::kNoPosition);
|
| - Target target(&this->target_stack_, result);
|
| - TryStatement* statement = ParseTryStatement(CHECK_OK);
|
| - if (result) result->AddStatement(statement, zone());
|
| - return result;
|
| - }
|
| -
|
| case Token::FUNCTION: {
|
| // FunctionDeclaration is only allowed in the context of SourceElements
|
| // (Ecma 262 5th Edition, clause 14):
|
| @@ -1890,6 +1883,30 @@ Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels,
|
| }
|
| }
|
|
|
| +Statement* Parser::ParseStatementAsUnlabelled(
|
| + ZoneList<const AstRawString*>* labels, bool* ok) {
|
| + switch (peek()) {
|
| + case Token::CONTINUE:
|
| + return ParseContinueStatement(ok);
|
| +
|
| + case Token::BREAK:
|
| + return ParseBreakStatement(labels, ok);
|
| +
|
| + case Token::RETURN:
|
| + return ParseReturnStatement(ok);
|
| +
|
| + case Token::THROW:
|
| + return ParseThrowStatement(ok);
|
| +
|
| + case Token::TRY:
|
| + return ParseTryStatement(ok);
|
| +
|
| + default:
|
| + UNREACHABLE();
|
| + return NULL;
|
| + }
|
| +}
|
| +
|
|
|
| VariableProxy* Parser::NewUnresolved(const AstRawString* name,
|
| VariableMode mode) {
|
| @@ -2845,13 +2862,19 @@ CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
|
| int pos = position();
|
| ZoneList<Statement*>* statements =
|
| new(zone()) ZoneList<Statement*>(5, zone());
|
| + Statement* stat = NULL;
|
| while (peek() != Token::CASE &&
|
| peek() != Token::DEFAULT &&
|
| peek() != Token::RBRACE) {
|
| - Statement* stat = ParseStatementListItem(CHECK_OK);
|
| + stat = ParseStatementListItem(CHECK_OK);
|
| statements->Add(stat, zone());
|
| }
|
| -
|
| + if (is_strong(language_mode()) && stat != NULL && !stat->IsJump() &&
|
| + peek() != Token::RBRACE) {
|
| + ReportMessageAt(scanner()->location(), "strong_switch_fallthrough");
|
| + *ok = false;
|
| + return NULL;
|
| + }
|
| return factory()->NewCaseClause(label, statements, pos);
|
| }
|
|
|
| @@ -4468,7 +4491,6 @@ void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
|
| // ----------------------------------------------------------------------------
|
| // Parser support
|
|
|
| -
|
| bool Parser::TargetStackContainsLabel(const AstRawString* label) {
|
| for (Target* t = target_stack_; t != NULL; t = t->previous()) {
|
| if (ContainsLabel(t->statement()->labels(), label)) return true;
|
|
|