| Index: src/parsing/parser.cc
|
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
|
| index c6cf5dfcd2bb03d997a3593c632d2547e05776ca..e9659a2112ac526be9a39f721af84b4d9cc6244b 100644
|
| --- a/src/parsing/parser.cc
|
| +++ b/src/parsing/parser.cc
|
| @@ -1785,199 +1785,103 @@ Statement* Parser::RewriteSwitchStatement(Expression* tag,
|
| return switch_block;
|
| }
|
|
|
| -TryStatement* Parser::ParseTryStatement(bool* ok) {
|
| - // TryStatement ::
|
| - // 'try' Block Catch
|
| - // 'try' Block Finally
|
| - // 'try' Block Catch Finally
|
| - //
|
| - // Catch ::
|
| - // 'catch' '(' Identifier ')' Block
|
| - //
|
| - // Finally ::
|
| - // 'finally' Block
|
| -
|
| - Expect(Token::TRY, CHECK_OK);
|
| - int pos = position();
|
| -
|
| - Block* try_block;
|
| - {
|
| - ReturnExprScope no_tail_calls(function_state_,
|
| - ReturnExprContext::kInsideTryBlock);
|
| - try_block = ParseBlock(NULL, CHECK_OK);
|
| - }
|
| +void Parser::RewriteCatchPattern(CatchInfo* catch_info, bool* ok) {
|
| + if (catch_info->name == nullptr) {
|
| + DCHECK_NOT_NULL(catch_info->pattern);
|
| + catch_info->name = ast_value_factory()->dot_catch_string();
|
| + }
|
| + catch_info->variable = catch_info->scope->DeclareLocal(
|
| + catch_info->name, VAR, kCreatedInitialized, NORMAL_VARIABLE);
|
| + if (catch_info->pattern != nullptr) {
|
| + DeclarationDescriptor descriptor;
|
| + descriptor.declaration_kind = DeclarationDescriptor::NORMAL;
|
| + descriptor.scope = scope();
|
| + descriptor.hoist_scope = nullptr;
|
| + descriptor.mode = LET;
|
| + descriptor.declaration_pos = catch_info->pattern->position();
|
| + descriptor.initialization_pos = catch_info->pattern->position();
|
|
|
| - Token::Value tok = peek();
|
| + // Initializer position for variables declared by the pattern.
|
| + const int initializer_position = position();
|
|
|
| - bool catch_for_promise_reject = false;
|
| - if (allow_natives() && tok == Token::MOD) {
|
| - Consume(Token::MOD);
|
| - catch_for_promise_reject = true;
|
| - tok = peek();
|
| - }
|
| + DeclarationParsingResult::Declaration decl(
|
| + catch_info->pattern, initializer_position,
|
| + factory()->NewVariableProxy(catch_info->variable));
|
|
|
| - if (tok != Token::CATCH && tok != Token::FINALLY) {
|
| - ReportMessage(MessageTemplate::kNoCatchOrFinally);
|
| - *ok = false;
|
| - return NULL;
|
| + catch_info->init_block =
|
| + factory()->NewBlock(nullptr, 8, true, kNoSourcePosition);
|
| + PatternRewriter::DeclareAndInitializeVariables(
|
| + this, catch_info->init_block, &descriptor, &decl,
|
| + &catch_info->bound_names, ok);
|
| + } else {
|
| + catch_info->bound_names.Add(catch_info->name, zone());
|
| }
|
| +}
|
|
|
| - Scope* catch_scope = NULL;
|
| - Variable* catch_variable = NULL;
|
| - Block* catch_block = NULL;
|
| - TailCallExpressionList tail_call_expressions_in_catch_block(zone());
|
| - if (tok == Token::CATCH) {
|
| - Consume(Token::CATCH);
|
| -
|
| - Expect(Token::LPAREN, CHECK_OK);
|
| - catch_scope = NewScope(CATCH_SCOPE);
|
| - catch_scope->set_start_position(scanner()->location().beg_pos);
|
| -
|
| - {
|
| - CollectExpressionsInTailPositionToListScope
|
| - collect_tail_call_expressions_scope(
|
| - function_state_, &tail_call_expressions_in_catch_block);
|
| - BlockState block_state(&scope_state_, catch_scope);
|
| -
|
| - catch_block = factory()->NewBlock(nullptr, 16, false, kNoSourcePosition);
|
| -
|
| - // Create a block scope to hold any lexical declarations created
|
| - // as part of destructuring the catch parameter.
|
| - {
|
| - BlockState block_state(&scope_state_);
|
| - block_state.set_start_position(scanner()->location().beg_pos);
|
| - ParserTarget target(this, catch_block);
|
| -
|
| - const AstRawString* name = ast_value_factory()->dot_catch_string();
|
| - Expression* pattern = nullptr;
|
| - if (peek_any_identifier()) {
|
| - name = ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
|
| - } else {
|
| - ExpressionClassifier pattern_classifier(this);
|
| - pattern = ParsePrimaryExpression(CHECK_OK);
|
| - ValidateBindingPattern(CHECK_OK);
|
| - }
|
| - catch_variable = catch_scope->DeclareLocal(
|
| - name, VAR, kCreatedInitialized, NORMAL_VARIABLE);
|
| -
|
| - Expect(Token::RPAREN, CHECK_OK);
|
| -
|
| - ZoneList<const AstRawString*> bound_names(1, zone());
|
| - if (pattern != nullptr) {
|
| - DeclarationDescriptor descriptor;
|
| - descriptor.declaration_kind = DeclarationDescriptor::NORMAL;
|
| - descriptor.scope = scope();
|
| - descriptor.hoist_scope = nullptr;
|
| - descriptor.mode = LET;
|
| - descriptor.declaration_pos = pattern->position();
|
| - descriptor.initialization_pos = pattern->position();
|
| -
|
| - // Initializer position for variables declared by the pattern.
|
| - const int initializer_position = position();
|
| -
|
| - DeclarationParsingResult::Declaration decl(
|
| - pattern, initializer_position,
|
| - factory()->NewVariableProxy(catch_variable));
|
| -
|
| - Block* init_block =
|
| - factory()->NewBlock(nullptr, 8, true, kNoSourcePosition);
|
| - PatternRewriter::DeclareAndInitializeVariables(
|
| - this, init_block, &descriptor, &decl, &bound_names, CHECK_OK);
|
| - catch_block->statements()->Add(init_block, zone());
|
| - } else {
|
| - bound_names.Add(name, zone());
|
| - }
|
| -
|
| - Block* inner_block = ParseBlock(nullptr, CHECK_OK);
|
| - catch_block->statements()->Add(inner_block, zone());
|
| -
|
| - // Check for `catch(e) { let e; }` and similar errors.
|
| - Scope* inner_block_scope = inner_block->scope();
|
| - if (inner_block_scope != nullptr) {
|
| - Declaration* decl =
|
| - inner_block_scope->CheckLexDeclarationsConflictingWith(
|
| - bound_names);
|
| - if (decl != nullptr) {
|
| - const AstRawString* name = decl->proxy()->raw_name();
|
| - int position = decl->proxy()->position();
|
| - Scanner::Location location =
|
| - position == kNoSourcePosition
|
| - ? Scanner::Location::invalid()
|
| - : Scanner::Location(position, position + 1);
|
| - ReportMessageAt(location, MessageTemplate::kVarRedeclaration, name);
|
| - *ok = false;
|
| - return nullptr;
|
| - }
|
| - }
|
| - block_state.set_end_position(scanner()->location().end_pos);
|
| - catch_block->set_scope(block_state.FinalizedBlockScope());
|
| - }
|
| +void Parser::ValidateCatchBlock(const CatchInfo& catch_info, bool* ok) {
|
| + // Check for `catch(e) { let e; }` and similar errors.
|
| + Scope* inner_block_scope = catch_info.inner_block->scope();
|
| + if (inner_block_scope != nullptr) {
|
| + Declaration* decl = inner_block_scope->CheckLexDeclarationsConflictingWith(
|
| + catch_info.bound_names);
|
| + if (decl != nullptr) {
|
| + const AstRawString* name = decl->proxy()->raw_name();
|
| + int position = decl->proxy()->position();
|
| + Scanner::Location location =
|
| + position == kNoSourcePosition
|
| + ? Scanner::Location::invalid()
|
| + : Scanner::Location(position, position + 1);
|
| + ReportMessageAt(location, MessageTemplate::kVarRedeclaration, name);
|
| + *ok = false;
|
| }
|
| -
|
| - catch_scope->set_end_position(scanner()->location().end_pos);
|
| - tok = peek();
|
| - }
|
| -
|
| - Block* finally_block = NULL;
|
| - DCHECK(tok == Token::FINALLY || catch_block != NULL);
|
| - if (tok == Token::FINALLY) {
|
| - Consume(Token::FINALLY);
|
| - finally_block = ParseBlock(NULL, CHECK_OK);
|
| }
|
| +}
|
|
|
| +Statement* Parser::RewriteTryStatement(Block* try_block, Block* catch_block,
|
| + Block* finally_block,
|
| + const CatchInfo& catch_info, int pos) {
|
| // Simplify the AST nodes by converting:
|
| // 'try B0 catch B1 finally B2'
|
| // to:
|
| // 'try { try B0 catch B1 } finally B2'
|
|
|
| - if (catch_block != NULL && finally_block != NULL) {
|
| + if (catch_block != nullptr && finally_block != nullptr) {
|
| // If we have both, create an inner try/catch.
|
| - DCHECK(catch_scope != NULL && catch_variable != NULL);
|
| + DCHECK_NOT_NULL(catch_info.scope);
|
| + DCHECK_NOT_NULL(catch_info.variable);
|
| TryCatchStatement* statement;
|
| - if (catch_for_promise_reject) {
|
| + if (catch_info.for_promise_reject) {
|
| statement = factory()->NewTryCatchStatementForPromiseReject(
|
| - try_block, catch_scope, catch_variable, catch_block,
|
| + try_block, catch_info.scope, catch_info.variable, catch_block,
|
| kNoSourcePosition);
|
| } else {
|
| - statement = factory()->NewTryCatchStatement(try_block, catch_scope,
|
| - catch_variable, catch_block,
|
| - kNoSourcePosition);
|
| + statement = factory()->NewTryCatchStatement(
|
| + try_block, catch_info.scope, catch_info.variable, catch_block,
|
| + kNoSourcePosition);
|
| }
|
|
|
| - try_block = factory()->NewBlock(NULL, 1, false, kNoSourcePosition);
|
| + try_block = factory()->NewBlock(nullptr, 1, false, kNoSourcePosition);
|
| try_block->statements()->Add(statement, zone());
|
| - catch_block = NULL; // Clear to indicate it's been handled.
|
| + catch_block = nullptr; // Clear to indicate it's been handled.
|
| }
|
|
|
| - TryStatement* result = NULL;
|
| - if (catch_block != NULL) {
|
| + if (catch_block != nullptr) {
|
| // For a try-catch construct append return expressions from the catch block
|
| // to the list of return expressions.
|
| function_state_->tail_call_expressions().Append(
|
| - tail_call_expressions_in_catch_block);
|
| + catch_info.tail_call_expressions);
|
|
|
| - DCHECK(finally_block == NULL);
|
| - DCHECK(catch_scope != NULL && catch_variable != NULL);
|
| - result = factory()->NewTryCatchStatement(try_block, catch_scope,
|
| - catch_variable, catch_block, pos);
|
| + DCHECK_NULL(finally_block);
|
| + DCHECK_NOT_NULL(catch_info.scope);
|
| + DCHECK_NOT_NULL(catch_info.variable);
|
| + return factory()->NewTryCatchStatement(
|
| + try_block, catch_info.scope, catch_info.variable, catch_block, pos);
|
| } else {
|
| - if (FLAG_harmony_explicit_tailcalls &&
|
| - tail_call_expressions_in_catch_block.has_explicit_tail_calls()) {
|
| - // TODO(ishell): update chapter number.
|
| - // ES8 XX.YY.ZZ
|
| - ReportMessageAt(tail_call_expressions_in_catch_block.location(),
|
| - MessageTemplate::kUnexpectedTailCallInCatchBlock);
|
| - *ok = false;
|
| - return NULL;
|
| - }
|
| - DCHECK(finally_block != NULL);
|
| - result = factory()->NewTryFinallyStatement(try_block, finally_block, pos);
|
| + DCHECK_NOT_NULL(finally_block);
|
| + return factory()->NewTryFinallyStatement(try_block, finally_block, pos);
|
| }
|
| -
|
| - return result;
|
| }
|
|
|
| -
|
| // !%_IsJSReceiver(result = iterator.next()) &&
|
| // %ThrowIteratorResultNotAnObject(result)
|
| Expression* Parser::BuildIteratorNextResult(Expression* iterator,
|
|
|