| Index: src/parsing/parser.cc
|
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
|
| index 444b20cbf87352cdd4b214938e837c2a7b3b2b52..85a29eec502058633ad756d077b36fa9a5ada280 100644
|
| --- a/src/parsing/parser.cc
|
| +++ b/src/parsing/parser.cc
|
| @@ -3336,6 +3336,7 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
|
| }
|
|
|
| for_of->Initialize(each, subject, body,
|
| + iterator,
|
| assign_iterator,
|
| next_result,
|
| result_done,
|
| @@ -3613,9 +3614,6 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
|
|
|
| Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
| bool* ok) {
|
| - // ForStatement ::
|
| - // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
|
| -
|
| int stmt_pos = peek_position();
|
| Statement* init = NULL;
|
| ZoneList<const AstRawString*> lexical_bindings(1, zone());
|
| @@ -3752,39 +3750,44 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
| }
|
| body_scope->set_end_position(scanner()->location().end_pos);
|
| body_scope = body_scope->FinalizeBlockScope();
|
| - body_block->set_scope(body_scope);
|
| -
|
| - // Create a TDZ for any lexically-bound names.
|
| - if (IsLexicalVariableMode(parsing_result.descriptor.mode)) {
|
| - DCHECK_NULL(init_block);
|
| -
|
| - init_block =
|
| - factory()->NewBlock(nullptr, 1, false, RelocInfo::kNoPosition);
|
| -
|
| - for (int i = 0; i < lexical_bindings.length(); ++i) {
|
| - // TODO(adamk): This needs to be some sort of special
|
| - // INTERNAL variable that's invisible to the debugger
|
| - // but visible to everything else.
|
| - VariableProxy* tdz_proxy =
|
| - NewUnresolved(lexical_bindings[i], LET);
|
| - Declaration* tdz_decl = factory()->NewVariableDeclaration(
|
| - tdz_proxy, LET, scope_, RelocInfo::kNoPosition);
|
| - Variable* tdz_var = Declare(
|
| - tdz_decl, DeclarationDescriptor::NORMAL, true, CHECK_OK);
|
| - tdz_var->set_initializer_position(position());
|
| - }
|
| + body_block->set_scope(body_scope);
|
| +
|
| + // Create a TDZ for any lexically-bound names.
|
| + if (IsLexicalVariableMode(parsing_result.descriptor.mode)) {
|
| + DCHECK_NULL(init_block);
|
| +
|
| + init_block =
|
| + factory()->NewBlock(nullptr, 1, false, RelocInfo::kNoPosition);
|
| +
|
| + for (int i = 0; i < lexical_bindings.length(); ++i) {
|
| + // TODO(adamk): This needs to be some sort of special
|
| + // INTERNAL variable that's invisible to the debugger
|
| + // but visible to everything else.
|
| + VariableProxy* tdz_proxy =
|
| + NewUnresolved(lexical_bindings[i], LET);
|
| + Declaration* tdz_decl = factory()->NewVariableDeclaration(
|
| + tdz_proxy, LET, scope_, RelocInfo::kNoPosition);
|
| + Variable* tdz_var = Declare(
|
| + tdz_decl, DeclarationDescriptor::NORMAL, true, CHECK_OK);
|
| + tdz_var->set_initializer_position(position());
|
| }
|
| + }
|
| +
|
| + Statement* final_loop = loop->IsForOfStatement()
|
| + ? FinalizeForOfStatement(
|
| + loop->AsForOfStatement(), RelocInfo::kNoPosition)
|
| + : loop;
|
|
|
| for_scope->set_end_position(scanner()->location().end_pos);
|
| for_scope = for_scope->FinalizeBlockScope();
|
| // Parsed for-in loop w/ variable declarations.
|
| if (init_block != nullptr) {
|
| - init_block->statements()->Add(loop, zone());
|
| + init_block->statements()->Add(final_loop, zone());
|
| init_block->set_scope(for_scope);
|
| return init_block;
|
| } else {
|
| DCHECK_NULL(for_scope);
|
| - return loop;
|
| + return final_loop;
|
| }
|
| } else {
|
| init = parsing_result.BuildInitializationBlock(
|
| @@ -3847,21 +3850,28 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
|
| // expressions in head of the loop should actually have variables
|
| // resolved in the outer scope.
|
| Scope* body_scope = NewScope(for_scope, BLOCK_SCOPE);
|
| - BlockState block_state(&scope_, body_scope);
|
| - Block* block =
|
| - factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
|
| - Statement* body = ParseSubStatement(NULL, CHECK_OK);
|
| - block->statements()->Add(body, zone());
|
| - InitializeForEachStatement(loop, expression, enumerable, block,
|
| - is_destructuring);
|
| - body_scope->set_end_position(scanner()->location().end_pos);
|
| - body_scope = body_scope->FinalizeBlockScope();
|
| - block->set_scope(body_scope);
|
| + {
|
| + BlockState block_state(&scope_, body_scope);
|
| + Block* block =
|
| + factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
|
| + Statement* body = ParseSubStatement(NULL, CHECK_OK);
|
| + block->statements()->Add(body, zone());
|
| + InitializeForEachStatement(loop, expression, enumerable, block,
|
| + is_destructuring);
|
| + body_scope->set_end_position(scanner()->location().end_pos);
|
| + body_scope = body_scope->FinalizeBlockScope();
|
| + block->set_scope(body_scope);
|
| + }
|
| +
|
| + Statement* final_loop = loop->IsForOfStatement()
|
| + ? FinalizeForOfStatement(
|
| + loop->AsForOfStatement(), RelocInfo::kNoPosition)
|
| + : loop;
|
| +
|
| for_scope->set_end_position(scanner()->location().end_pos);
|
| for_scope = for_scope->FinalizeBlockScope();
|
| DCHECK(for_scope == nullptr);
|
| - // Parsed for-in loop.
|
| - return loop;
|
| + return final_loop;
|
|
|
| } else {
|
| init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
|
| @@ -5741,7 +5751,7 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) {
|
| ForEachStatement::ITERATE, nullptr, RelocInfo::kNoPosition);
|
| ForOfStatement* for_of = loop->AsForOfStatement();
|
| for_of->Initialize(factory()->NewVariableProxy(each), subject,
|
| - append_body, assign_iterator, next_element,
|
| + append_body, iterator, assign_iterator, next_element,
|
| element_done, assign_each);
|
| do_block->statements()->Add(for_of, zone());
|
| }
|
| @@ -5899,7 +5909,6 @@ Expression* ParserTraits::RewriteYieldStar(
|
| auto scope = parser_->scope_;
|
| auto zone = parser_->zone();
|
|
|
| - Statement* skip = factory->NewEmptyStatement(nopos);
|
|
|
| // Forward definition for break/continue statements.
|
| WhileStatement* loop = factory->NewWhileStatement(nullptr, nopos);
|
| @@ -5971,8 +5980,8 @@ Expression* ParserTraits::RewriteYieldStar(
|
| throw_call = factory->NewExpressionStatement(call, nopos);
|
| }
|
|
|
| - validate_iterator =
|
| - factory->NewIfStatement(is_receiver_call, skip, throw_call, nopos);
|
| + validate_iterator = factory->NewIfStatement(
|
| + is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
|
| }
|
|
|
|
|
| @@ -6015,8 +6024,8 @@ Expression* ParserTraits::RewriteYieldStar(
|
| throw_call = factory->NewExpressionStatement(call, nopos);
|
| }
|
|
|
| - validate_next_output =
|
| - factory->NewIfStatement(is_receiver_call, skip, throw_call, nopos);
|
| + validate_next_output = factory->NewIfStatement(
|
| + is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
|
| }
|
|
|
|
|
| @@ -6052,11 +6061,13 @@ Expression* ParserTraits::RewriteYieldStar(
|
| Statement* throw_call = factory->NewExpressionStatement(call, nopos);
|
|
|
| Block* then = factory->NewBlock(nullptr, 4+1, false, nopos);
|
| - BuildIteratorClose(then->statements(), var_iterator, Nothing<Variable*>(),
|
| - Nothing<Variable*>());
|
| + Variable* var_tmp = scope->NewTemporary(avfactory->empty_string());
|
| + BuildIteratorClose(
|
| + then->statements(), var_iterator, factory->NewUndefinedLiteral(nopos),
|
| + var_tmp);
|
| then->statements()->Add(throw_call, zone);
|
| - check_throw =
|
| - factory->NewIfStatement(condition, then, skip, nopos);
|
| + check_throw = factory->NewIfStatement(
|
| + condition, then, factory->NewEmptyStatement(nopos), nopos);
|
| }
|
|
|
|
|
| @@ -6095,8 +6106,8 @@ Expression* ParserTraits::RewriteYieldStar(
|
| throw_call = factory->NewExpressionStatement(call, nopos);
|
| }
|
|
|
| - validate_throw_output =
|
| - factory->NewIfStatement(is_receiver_call, skip, throw_call, nopos);
|
| + validate_throw_output = factory->NewIfStatement(
|
| + is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
|
| }
|
|
|
|
|
| @@ -6108,7 +6119,8 @@ Expression* ParserTraits::RewriteYieldStar(
|
| factory->NewStringLiteral(avfactory->done_string(), nopos);
|
| Expression* property = factory->NewProperty(output_proxy, literal, nopos);
|
| BreakStatement* break_loop = factory->NewBreakStatement(loop, nopos);
|
| - if_done = factory->NewIfStatement(property, break_loop, skip, nopos);
|
| + if_done = factory->NewIfStatement(
|
| + property, break_loop, factory->NewEmptyStatement(nopos), nopos);
|
| }
|
|
|
|
|
| @@ -6227,8 +6239,8 @@ Expression* ParserTraits::RewriteYieldStar(
|
| case_next->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
|
|
|
| auto case_return = new (zone) ZoneList<Statement*>(5, zone);
|
| - BuildIteratorClose(
|
| - case_return, var_iterator, Just(var_input), Just(var_output));
|
| + BuildIteratorClose(case_return, var_iterator,
|
| + factory->NewVariableProxy(var_input, nopos), var_output);
|
| case_return->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
|
|
|
| auto case_throw = new (zone) ZoneList<Statement*>(5, zone);
|
| @@ -6294,17 +6306,25 @@ Expression* ParserTraits::RewriteYieldStar(
|
|
|
| void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
|
| Variable* iterator,
|
| - Maybe<Variable*> input,
|
| - Maybe<Variable*> output) {
|
| + Expression* input,
|
| + Variable* var_output) {
|
| + //
|
| + // This function adds four statements to [statements], corresponding to the
|
| + // following code:
|
| + //
|
| + // let iteratorReturn = iterator.return;
|
| + // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return input;
|
| + // output = %_Call(iteratorReturn, iterator);
|
| + // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
|
| + //
|
| +
|
| const int nopos = RelocInfo::kNoPosition;
|
| auto factory = parser_->factory();
|
| auto avfactory = parser_->ast_value_factory();
|
| - auto scope = parser_->scope_;
|
| auto zone = parser_->zone();
|
| - Statement* skip = factory->NewEmptyStatement(nopos);
|
|
|
| // let iteratorReturn = iterator.return;
|
| - Variable* var = scope->NewTemporary(avfactory->empty_string());
|
| + Variable* var_return = var_output; // Reusing the output variable.
|
| Statement* get_return;
|
| {
|
| Expression* iterator_proxy = factory->NewVariableProxy(iterator);
|
| @@ -6312,57 +6332,47 @@ void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
|
| factory->NewStringLiteral(avfactory->return_string(), nopos);
|
| Expression* property =
|
| factory->NewProperty(iterator_proxy, literal, nopos);
|
| - Expression* return_proxy = factory->NewVariableProxy(var);
|
| + Expression* return_proxy = factory->NewVariableProxy(var_return);
|
| Expression* assignment = factory->NewAssignment(
|
| Token::ASSIGN, return_proxy, property, nopos);
|
| get_return = factory->NewExpressionStatement(assignment, nopos);
|
| }
|
|
|
| - // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return; OR
|
| // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return input;
|
| Statement* check_return;
|
| {
|
| Expression* condition = factory->NewCompareOperation(
|
| - Token::EQ, factory->NewVariableProxy(var),
|
| + Token::EQ, factory->NewVariableProxy(var_return),
|
| factory->NewNullLiteral(nopos), nopos);
|
|
|
| - Expression* value = input.IsJust() ?
|
| - static_cast<Expression*>(factory->NewVariableProxy(input.FromJust())) :
|
| - factory->NewUndefinedLiteral(nopos);
|
| + Statement* return_input = factory->NewReturnStatement(input, nopos);
|
|
|
| - Statement* return_undefined = factory->NewReturnStatement(value, nopos);
|
| -
|
| - check_return =
|
| - factory->NewIfStatement(condition, return_undefined, skip, nopos);
|
| + check_return = factory->NewIfStatement(
|
| + condition, return_input, factory->NewEmptyStatement(nopos), nopos);
|
| }
|
|
|
| - // let output = %_Call(iteratorReturn, iterator); OR
|
| - // output = %_Call(iteratorReturn, iterator, input);
|
| + // output = %_Call(iteratorReturn, iterator);
|
| Statement* call_return;
|
| {
|
| auto args = new (zone) ZoneList<Expression*>(3, zone);
|
| - args->Add(factory->NewVariableProxy(var), zone);
|
| + args->Add(factory->NewVariableProxy(var_return), zone);
|
| args->Add(factory->NewVariableProxy(iterator), zone);
|
| - if (input.IsJust()) {
|
| - args->Add(factory->NewVariableProxy(input.FromJust()), zone);
|
| - }
|
|
|
| Expression* call =
|
| factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
|
| - Expression* output_proxy = factory->NewVariableProxy(
|
| - output.IsJust() ? output.FromJust() : var);
|
| + Expression* output_proxy = factory->NewVariableProxy(var_output);
|
| Expression* assignment = factory->NewAssignment(
|
| Token::ASSIGN, output_proxy, call, nopos);
|
| call_return = factory->NewExpressionStatement(assignment, nopos);
|
| }
|
|
|
| - // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
|
| + // if (!IS_RECEIVER(output)) %ThrowIteratorResultNotAnObject(output);
|
| Statement* validate_output;
|
| {
|
| Expression* is_receiver_call;
|
| {
|
| auto args = new (zone) ZoneList<Expression*>(1, zone);
|
| - args->Add(factory->NewVariableProxy(var), zone);
|
| + args->Add(factory->NewVariableProxy(var_output), zone);
|
| is_receiver_call =
|
| factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
|
| }
|
| @@ -6370,14 +6380,14 @@ void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
|
| Statement* throw_call;
|
| {
|
| auto args = new (zone) ZoneList<Expression*>(1, zone);
|
| - args->Add(factory->NewVariableProxy(var), zone);
|
| + args->Add(factory->NewVariableProxy(var_output), zone);
|
| Expression* call = factory->NewCallRuntime(
|
| Runtime::kThrowIteratorResultNotAnObject, args, nopos);
|
| throw_call = factory->NewExpressionStatement(call, nopos);
|
| }
|
|
|
| - validate_output =
|
| - factory->NewIfStatement(is_receiver_call, skip, throw_call, nopos);
|
| + validate_output = factory->NewIfStatement(
|
| + is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
|
| }
|
|
|
| statements->Add(get_return, zone);
|
| @@ -6387,5 +6397,355 @@ void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
|
| }
|
|
|
|
|
| +// Runtime encoding of different completion modes.
|
| +enum ForOfLoopBodyCompletion { BODY_COMPLETED, BODY_ABORTED, BODY_THREW };
|
| +
|
| +void ParserTraits::BuildIteratorCloseForCompletion(
|
| + ZoneList<Statement*>* statements, Variable* iterator,
|
| + Variable* completion) {
|
| + //
|
| + // This function adds two statements to [statements], corresponding to the
|
| + // following code:
|
| + //
|
| + // let iteratorReturn = iterator.return;
|
| + // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) {
|
| + // let output;
|
| + // if (completion === BODY_THREW) {
|
| + // if (!IS_CALLABLE(iteratorReturn)) {
|
| + // throw MakeTypeError(kReturnMethodNotCallable);
|
| + // }
|
| + // try { output = %_Call(iteratorReturn, iterator) } catch (_) { }
|
| + // } else {
|
| + // output = %_Call(iteratorReturn, iterator);
|
| + // }
|
| + // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
|
| + // }
|
| + //
|
| +
|
| + const int nopos = RelocInfo::kNoPosition;
|
| + auto factory = parser_->factory();
|
| + auto avfactory = parser_->ast_value_factory();
|
| + auto scope = parser_->scope_;
|
| + auto zone = parser_->zone();
|
| +
|
| + // let output;
|
| + Variable* var_output = scope->NewTemporary(avfactory->empty_string());
|
| +
|
| + // let iteratorReturn = iterator.return;
|
| + Variable* var_return = var_output; // Reusing the output variable.
|
| + Statement* get_return;
|
| + {
|
| + Expression* iterator_proxy = factory->NewVariableProxy(iterator);
|
| + Expression* literal =
|
| + factory->NewStringLiteral(avfactory->return_string(), nopos);
|
| + Expression* property =
|
| + factory->NewProperty(iterator_proxy, literal, nopos);
|
| + Expression* return_proxy = factory->NewVariableProxy(var_return);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, return_proxy, property, nopos);
|
| + get_return = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| + // if (!IS_CALLABLE(iteratorReturn)) {
|
| + // throw MakeTypeError(kReturnMethodNotCallable);
|
| + // }
|
| + Statement* check_return_callable;
|
| + {
|
| + Expression* type_of = factory->NewUnaryOperation(
|
| + Token::TYPEOF, factory->NewVariableProxy(var_return), nopos);
|
| + Expression* function_literal = factory->NewStringLiteral(
|
| + avfactory->function_string(), nopos);
|
| + Expression* condition = factory->NewCompareOperation(
|
| + Token::EQ_STRICT, type_of, function_literal, nopos);
|
| +
|
| + Expression* call = NewThrowTypeError(
|
| + MessageTemplate::kReturnMethodNotCallable,
|
| + avfactory->empty_string(), nopos);
|
| + Statement* throw_call = factory->NewExpressionStatement(call, nopos);
|
| +
|
| + check_return_callable = factory->NewIfStatement(
|
| + condition, factory->NewEmptyStatement(nopos), throw_call, nopos);
|
| + }
|
| +
|
| + // output = %_Call(iteratorReturn, iterator);
|
| + Statement* call_return;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(2, zone);
|
| + args->Add(factory->NewVariableProxy(var_return), zone);
|
| + args->Add(factory->NewVariableProxy(iterator), zone);
|
| + Expression* call =
|
| + factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
|
| +
|
| + Expression* output_proxy = factory->NewVariableProxy(var_output);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, output_proxy, call, nopos);
|
| + call_return = factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| + // try { output = %_Call(iteratorReturn, iterator) } catch (_) { }
|
| + Statement* try_call_return;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(2, zone);
|
| + args->Add(factory->NewVariableProxy(var_return), zone);
|
| + args->Add(factory->NewVariableProxy(iterator), zone);
|
| +
|
| + Expression* call =
|
| + factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, factory->NewVariableProxy(var_output), call, nopos);
|
| +
|
| + Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
|
| + try_block->statements()->Add(
|
| + factory->NewExpressionStatement(assignment, nopos), zone);
|
| +
|
| + Block* catch_block = factory->NewBlock(nullptr, 0, false, nopos);
|
| +
|
| + Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
|
| + Variable* catch_variable = catch_scope->DeclareLocal(
|
| + avfactory->dot_catch_string(), VAR, kCreatedInitialized,
|
| + Variable::NORMAL);
|
| +
|
| + try_call_return = factory->NewTryCatchStatement(
|
| + try_block, catch_scope, catch_variable, catch_block, nopos);
|
| + }
|
| +
|
| + // if (completion === ABRUPT_THROW) {
|
| + // #check_return_callable;
|
| + // #try_call_return;
|
| + // } else {
|
| + // #call_return;
|
| + // }
|
| + Statement* call_return_carefully;
|
| + {
|
| + Expression* condition = factory->NewCompareOperation(
|
| + Token::EQ_STRICT, factory->NewVariableProxy(completion),
|
| + factory->NewSmiLiteral(BODY_THREW, nopos), nopos);
|
| +
|
| + Block* then_block = factory->NewBlock(nullptr, 2, false, nopos);
|
| + then_block->statements()->Add(check_return_callable, zone);
|
| + then_block->statements()->Add(try_call_return, zone);
|
| +
|
| + call_return_carefully =
|
| + factory->NewIfStatement(condition, then_block, call_return, nopos);
|
| + }
|
| +
|
| + // if (!IS_RECEIVER(output)) %ThrowIteratorResultNotAnObject(output);
|
| + Statement* validate_output;
|
| + {
|
| + Expression* is_receiver_call;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(1, zone);
|
| + args->Add(factory->NewVariableProxy(var_output), zone);
|
| + is_receiver_call =
|
| + factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
|
| + }
|
| +
|
| + Statement* throw_call;
|
| + {
|
| + auto args = new (zone) ZoneList<Expression*>(1, zone);
|
| + args->Add(factory->NewVariableProxy(var_output), zone);
|
| + Expression* call = factory->NewCallRuntime(
|
| + Runtime::kThrowIteratorResultNotAnObject, args, nopos);
|
| + throw_call = factory->NewExpressionStatement(call, nopos);
|
| + }
|
| +
|
| + validate_output = factory->NewIfStatement(
|
| + is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
|
| + }
|
| +
|
| + // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) { ... }
|
| + Statement* maybe_call_return;
|
| + {
|
| + Expression* condition = factory->NewCompareOperation(
|
| + Token::EQ, factory->NewVariableProxy(var_return),
|
| + factory->NewNullLiteral(nopos), nopos);
|
| +
|
| + Block* block = factory->NewBlock(nullptr, 2, false, nopos);
|
| + block->statements()->Add(call_return_carefully, zone);
|
| + block->statements()->Add(validate_output, zone);
|
| +
|
| + maybe_call_return = factory->NewIfStatement(
|
| + condition, factory->NewEmptyStatement(nopos), block, nopos);
|
| + }
|
| +
|
| +
|
| + statements->Add(get_return, zone);
|
| + statements->Add(maybe_call_return, zone);
|
| +}
|
| +
|
| +
|
| +Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) {
|
| + if (!FLAG_harmony_iterator_close) return loop;
|
| +
|
| + //
|
| + // This function replaces the loop with the following wrapping:
|
| + //
|
| + // let completion = BODY_COMPLETED;
|
| + // try {
|
| + // #loop;
|
| + // } catch(e) {
|
| + // if (completion === BODY_ABORTED) completion = BODY_THREW;
|
| + // throw e;
|
| + // } finally {
|
| + // if (!(completion === BODY_COMPLETED || IS_UNDEFINED(#iterator))) {
|
| + // #BuildIteratorClose(#iterator, completion) // See above.
|
| + // }
|
| + // }
|
| + //
|
| + // where the loop's body is wrapped as follows:
|
| + //
|
| + // {
|
| + // {{completion = BODY_ABORTED;}}
|
| + // #loop-body
|
| + // {{completion = BODY_COMPLETED;}}
|
| + // }
|
| +
|
| + const int nopos = RelocInfo::kNoPosition;
|
| + auto factory = parser_->factory();
|
| + auto avfactory = parser_->ast_value_factory();
|
| + auto scope = parser_->scope_;
|
| + auto zone = parser_->zone();
|
| +
|
| + // let completion = BODY_COMPLETED;
|
| + Variable* var_completion = scope->NewTemporary(avfactory->empty_string());
|
| + Statement* initialize_completion;
|
| + {
|
| + Expression* proxy = factory->NewVariableProxy(var_completion);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, proxy,
|
| + factory->NewSmiLiteral(BODY_COMPLETED, nopos), nopos);
|
| + initialize_completion =
|
| + factory->NewExpressionStatement(assignment, nopos);
|
| + }
|
| +
|
| + // if (completion === BODY_ABORTED) completion = BODY_THREW;
|
| + Statement* set_completion_throw;
|
| + {
|
| + Expression* condition = factory->NewCompareOperation(
|
| + Token::EQ_STRICT, factory->NewVariableProxy(var_completion),
|
| + factory->NewSmiLiteral(BODY_ABORTED, nopos), nopos);
|
| +
|
| + Expression* proxy = factory->NewVariableProxy(var_completion);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, proxy, factory->NewSmiLiteral(BODY_THREW, nopos),
|
| + nopos);
|
| + Statement* statement = factory->NewExpressionStatement(assignment, nopos);
|
| + set_completion_throw = factory->NewIfStatement(
|
| + condition, statement, factory->NewEmptyStatement(nopos), nopos);
|
| + }
|
| +
|
| + // if (!(completion === BODY_COMPLETED || IS_UNDEFINED(#iterator))) {
|
| + // #BuildIteratorClose(#iterator, completion)
|
| + // }
|
| + Block* maybe_close;
|
| + {
|
| + Expression* condition1 = factory->NewCompareOperation(
|
| + Token::EQ_STRICT, factory->NewVariableProxy(var_completion),
|
| + factory->NewSmiLiteral(BODY_COMPLETED, nopos), nopos);
|
| + Expression* condition2 = factory->NewCompareOperation(
|
| + Token::EQ_STRICT, factory->NewVariableProxy(loop->iterator()),
|
| + factory->NewUndefinedLiteral(nopos), nopos);
|
| + Expression* condition = factory->NewBinaryOperation(
|
| + Token::OR, condition1, condition2, nopos);
|
| +
|
| + Block* block = factory->NewBlock(nullptr, 2, false, nopos);
|
| + BuildIteratorCloseForCompletion(
|
| + block->statements(), loop->iterator(), var_completion);
|
| + DCHECK(block->statements()->length() == 2);
|
| +
|
| + maybe_close = factory->NewBlock(nullptr, 1, false, nopos);
|
| + maybe_close->statements()->Add(factory->NewIfStatement(
|
| + condition, factory->NewEmptyStatement(nopos), block, nopos), zone);
|
| + }
|
| +
|
| + // try { #try_block }
|
| + // catch(e) {
|
| + // #set_completion_throw;
|
| + // throw e;
|
| + // }
|
| + Statement* try_catch;
|
| + {
|
| + Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
|
| + Variable* catch_variable = catch_scope->DeclareLocal(
|
| + avfactory->dot_catch_string(), VAR, kCreatedInitialized,
|
| + Variable::NORMAL);
|
| +
|
| + Statement* rethrow;
|
| + {
|
| + Expression* proxy = factory->NewVariableProxy(catch_variable);
|
| + rethrow = factory->NewExpressionStatement(
|
| + factory->NewThrow(proxy, nopos), nopos);
|
| + }
|
| +
|
| + Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
|
| + try_block->statements()->Add(loop, zone);
|
| +
|
| + Block* catch_block = factory->NewBlock(nullptr, 2, false, nopos);
|
| + catch_block->statements()->Add(set_completion_throw, zone);
|
| + catch_block->statements()->Add(rethrow, zone);
|
| +
|
| + try_catch = factory->NewTryCatchStatement(
|
| + try_block, catch_scope, catch_variable, catch_block, nopos);
|
| + }
|
| +
|
| + // try { #try_catch } finally { #maybe_close }
|
| + Statement* try_finally;
|
| + {
|
| + Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
|
| + try_block->statements()->Add(try_catch, zone);
|
| +
|
| + try_finally =
|
| + factory->NewTryFinallyStatement(try_block, maybe_close, nopos);
|
| + }
|
| +
|
| + // #initialize_completion;
|
| + // #try_finally;
|
| + Statement* final_loop;
|
| + {
|
| + Block* block = factory->NewBlock(nullptr, 2, false, nopos);
|
| + block->statements()->Add(initialize_completion, zone);
|
| + block->statements()->Add(try_finally, zone);
|
| + final_loop = block;
|
| + }
|
| +
|
| + // {{completion = BODY_ABORTED;}}
|
| + Statement* set_completion_break;
|
| + {
|
| + Expression* proxy = factory->NewVariableProxy(var_completion);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, proxy,
|
| + factory->NewSmiLiteral(BODY_ABORTED, nopos), nopos);
|
| +
|
| + Block* block = factory->NewBlock(nullptr, 1, true, nopos);
|
| + block->statements()->Add(
|
| + factory->NewExpressionStatement(assignment, nopos), zone);
|
| + set_completion_break = block;
|
| + }
|
| +
|
| + // {{completion = BODY_COMPLETED;}}
|
| + Statement* set_completion_normal;
|
| + {
|
| + Expression* proxy = factory->NewVariableProxy(var_completion);
|
| + Expression* assignment = factory->NewAssignment(
|
| + Token::ASSIGN, proxy, factory->NewSmiLiteral(BODY_COMPLETED, nopos),
|
| + nopos);
|
| +
|
| + Block* block = factory->NewBlock(nullptr, 1, true, nopos);
|
| + block->statements()->Add(
|
| + factory->NewExpressionStatement(assignment, nopos), zone);
|
| + set_completion_normal = block;
|
| + }
|
| +
|
| + // { #set_completion_break; #loop-body; #set_completion_normal }
|
| + Block* new_body = factory->NewBlock(nullptr, 2, false, nopos);
|
| + new_body->statements()->Add(set_completion_break, zone);
|
| + new_body->statements()->Add(loop->body(), zone);
|
| + new_body->statements()->Add(set_completion_normal, zone);
|
| +
|
| + loop->set_body(new_body);
|
| + return final_loop;
|
| +}
|
| +
|
| +
|
| } // namespace internal
|
| } // namespace v8
|
|
|