Chromium Code Reviews| Index: src/parsing/parser.cc | 
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc | 
| index b8a50bda2448add2726e748ac22e680c6f59689b..2c17fb2ecce4a700d07d301bc4944037407ae2bb 100644 | 
| --- a/src/parsing/parser.cc | 
| +++ b/src/parsing/parser.cc | 
| @@ -2720,6 +2720,8 @@ Statement* Parser::ParseReturnStatement(bool* ok) { | 
| if (is_generator()) { | 
| return_value = BuildIteratorResult(return_value, true); | 
| + } else if (is_async_function()) { | 
| + return_value = EmitPromiseResolve(return_value, return_value->position()); | 
| } | 
| result = factory()->NewReturnStatement(return_value, loc.beg_pos); | 
| @@ -3960,6 +3962,66 @@ void ParserTraits::ParseArrowFunctionFormalParameters( | 
| AddFormalParameter(parameters, expr, initializer, end_pos, is_rest); | 
| } | 
| +void ParserTraits::ParseAsyncArrowSingleExpressionBody( | 
| + ZoneList<Statement*>* body, bool accept_IN, | 
| + Type::ExpressionClassifier* classifier, int pos, bool* ok) { | 
| + parser_->DesugarAsyncFunctionBody( | 
| + parser_->ast_value_factory()->empty_string(), parser_->scope_, body, | 
| + classifier, kAsyncArrowFunction, FunctionBody::ArrowConcise, accept_IN, | 
| + pos, ok); | 
| +} | 
| + | 
| +void Parser::DesugarAsyncFunctionBody(const AstRawString* function_name, | 
| + Scope* scope, ZoneList<Statement*>* body, | 
| + ExpressionClassifier* classifier, | 
| + FunctionKind kind, FunctionBody body_type, | 
| + bool accept_IN, int pos, bool* ok) { | 
| + scope->ForceContextAllocation(); | 
| + // Calling a generator returns a generator object. That object is | 
| + // stored | 
| + // in a temporary variable, a definition that is used by "yield" | 
| + // expressions. This also marks the FunctionState as a generator. | 
| + Variable* temp = | 
| + scope_->NewTemporary(ast_value_factory()->dot_generator_object_string()); | 
| + function_state_->set_generator_object_variable(temp); | 
| + | 
| + // Create generator, but do not yield. | 
| + Expression* allocation = EmitCreateJSGeneratorObject(pos); | 
| + Expression* assign_yield = | 
| + factory()->NewAssignment(Token::INIT, factory()->NewVariableProxy(temp), | 
| + allocation, RelocInfo::kNoPosition); | 
| + | 
| + body->Add( | 
| + factory()->NewExpressionStatement(assign_yield, RelocInfo::kNoPosition), | 
| + zone()); | 
| + | 
| + Block* try_block = factory()->NewBlock(NULL, 8, true, RelocInfo::kNoPosition); | 
| + | 
| + ZoneList<Statement*>* inner_body = try_block->statements(); | 
| + | 
| + Expression* return_value = nullptr; | 
| + if (body_type == FunctionBody::Normal) { | 
| + ParseStatementList(inner_body, Token::RBRACE, ok); | 
| + if (!*ok) return; | 
| + return_value = factory()->NewUndefinedLiteral(RelocInfo::kNoPosition); | 
| + } else { | 
| + return_value = ParseAssignmentExpression(accept_IN, classifier, ok); | 
| + if (!*ok) return; | 
| + ParserTraits::RewriteNonPattern(classifier, ok); | 
| + if (!*ok) return; | 
| + } | 
| + | 
| + return_value = EmitPromiseResolve(return_value, return_value->position()); | 
| + inner_body->Add( | 
| + factory()->NewReturnStatement(return_value, return_value->position()), | 
| + zone()); | 
| + | 
| + Block* catch_block = BuildRejectPromiseOnException(try_block); | 
| + | 
| + body->Add(catch_block, zone()); | 
| + | 
| + scope->set_end_position(scanner()->location().end_pos); | 
| +} | 
| DoExpression* Parser::ParseDoExpression(bool* ok) { | 
| // AssignmentExpression :: | 
| @@ -4087,9 +4149,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral( | 
| // Calling a generator returns a generator object. That object is stored | 
| // in a temporary variable, a definition that is used by "yield" | 
| // expressions. This also marks the FunctionState as a generator. | 
| - Variable* temp = scope_->NewTemporary( | 
| - ast_value_factory()->dot_generator_object_string()); | 
| - function_state.set_generator_object_variable(temp); | 
| + if (is_generator) { | 
| + Variable* temp = scope_->NewTemporary( | 
| + ast_value_factory()->dot_generator_object_string()); | 
| + function_state.set_generator_object_variable(temp); | 
| 
 
Dan Ehrenberg
2016/05/04 22:52:36
This conditional is redundant--you just checked is
 
caitp (gmail)
2016/05/06 18:45:26
It complicates things to do that --- because for A
 
 | 
| + } | 
| } | 
| Expect(Token::LPAREN, CHECK_OK); | 
| @@ -4508,6 +4572,54 @@ Block* Parser::BuildParameterInitializationBlock( | 
| return init_block; | 
| } | 
| +Block* Parser::BuildRejectPromiseOnException(Block* block) { | 
| + // try { <block> } catch (error) { return Promise.reject(error); } | 
| + Block* try_block = block; | 
| + Scope* catch_scope = NewScope(scope_, CATCH_SCOPE); | 
| + catch_scope->set_is_hidden(); | 
| + Variable* catch_variable = | 
| + catch_scope->DeclareLocal(ast_value_factory()->dot_catch_string(), VAR, | 
| + kCreatedInitialized, Variable::NORMAL); | 
| + Block* catch_block = | 
| + factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition); | 
| + | 
| + Expression* promise_reject = EmitPromiseReject( | 
| + factory()->NewVariableProxy(catch_variable), RelocInfo::kNoPosition); | 
| + | 
| + ReturnStatement* return_promise_reject = | 
| + factory()->NewReturnStatement(promise_reject, RelocInfo::kNoPosition); | 
| + catch_block->statements()->Add(return_promise_reject, zone()); | 
| + TryStatement* try_catch_statement = | 
| + factory()->NewTryCatchStatement(try_block, catch_scope, catch_variable, | 
| + catch_block, RelocInfo::kNoPosition); | 
| + | 
| + block = factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition); | 
| + block->statements()->Add(try_catch_statement, zone()); | 
| + return block; | 
| +} | 
| + | 
| +Expression* Parser::EmitCreateJSGeneratorObject(int pos) { | 
| + DCHECK_NOT_NULL(function_state_->generator_object_variable()); | 
| + ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); | 
| + args->Add(factory()->NewThisFunction(pos), zone()); | 
| + args->Add(ThisExpression(scope_, factory(), RelocInfo::kNoPosition), zone()); | 
| + return factory()->NewCallRuntime(Runtime::kCreateJSGeneratorObject, args, | 
| + pos); | 
| +} | 
| + | 
| +Expression* Parser::EmitPromiseResolve(Expression* value, int pos) { | 
| + ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone()); | 
| + args->Add(value, zone()); | 
| + return factory()->NewCallRuntime(Context::PROMISE_CREATE_RESOLVED_INDEX, args, | 
| + pos); | 
| +} | 
| + | 
| +Expression* Parser::EmitPromiseReject(Expression* value, int pos) { | 
| + ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone()); | 
| + args->Add(value, zone()); | 
| + return factory()->NewCallRuntime(Context::PROMISE_CREATE_REJECTED_INDEX, args, | 
| + pos); | 
| +} | 
| ZoneList<Statement*>* Parser::ParseEagerFunctionBody( | 
| const AstRawString* function_name, int pos, | 
| @@ -4561,14 +4673,7 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( | 
| factory()->NewBlock(nullptr, 3, false, RelocInfo::kNoPosition); | 
| { | 
| - ZoneList<Expression*>* arguments = | 
| - new (zone()) ZoneList<Expression*>(2, zone()); | 
| - arguments->Add(factory()->NewThisFunction(pos), zone()); | 
| - arguments->Add( | 
| - ThisExpression(scope_, factory(), RelocInfo::kNoPosition), zone()); | 
| - CallRuntime* allocation = factory()->NewCallRuntime( | 
| - Runtime::kCreateJSGeneratorObject, arguments, pos); | 
| - | 
| + Expression* allocation = EmitCreateJSGeneratorObject(pos); | 
| VariableProxy* init_proxy = factory()->NewVariableProxy( | 
| function_state_->generator_object_variable()); | 
| Assignment* assignment = factory()->NewAssignment( | 
| @@ -4577,6 +4682,7 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( | 
| function_state_->generator_object_variable()); | 
| Yield* yield = | 
| factory()->NewYield(get_proxy, assignment, RelocInfo::kNoPosition); | 
| + | 
| 
 
Dan Ehrenberg
2016/05/04 22:52:36
No need for the extra newline
 
 | 
| try_block->statements()->Add( | 
| factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition), | 
| zone()); | 
| @@ -4604,6 +4710,10 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( | 
| body->Add(factory()->NewTryFinallyStatement(try_block, finally_block, | 
| RelocInfo::kNoPosition), | 
| zone()); | 
| + } else if (IsAsyncFunction(kind)) { | 
| + const bool accept_IN = true; | 
| + DesugarAsyncFunctionBody(function_name, inner_scope, body, nullptr, kind, | 
| + FunctionBody::Normal, accept_IN, pos, CHECK_OK); | 
| 
 
Dan Ehrenberg
2016/05/04 22:52:36
I like how you factored out DesugarAsyncFunctionBo
 
caitp (gmail)
2016/05/06 18:45:26
Sure --- but lets do that in a separate CL
 
 | 
| } else { | 
| ParseStatementList(body, Token::RBRACE, CHECK_OK); | 
| } | 
| @@ -4625,6 +4735,11 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( | 
| DCHECK_EQ(body, inner_block->statements()); | 
| SetLanguageMode(scope_, inner_scope->language_mode()); | 
| Block* init_block = BuildParameterInitializationBlock(parameters, CHECK_OK); | 
| + | 
| + if (IsAsyncFunction(kind)) { | 
| + init_block = BuildRejectPromiseOnException(init_block); | 
| 
 
Dan Ehrenberg
2016/05/04 22:52:36
Rather than adding a second call to BuildRejectPro
 
caitp (gmail)
2016/05/06 18:45:26
You mean like
```
if (IsAsyncFunction(kind)) {
 
 | 
| + } | 
| + | 
| DCHECK_NOT_NULL(init_block); | 
| inner_scope->set_end_position(scanner()->location().end_pos); | 
| @@ -5426,9 +5541,21 @@ void ParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier, | 
| } | 
| Expression* ParserTraits::RewriteAwaitExpression(Expression* value, int pos) { | 
| - // TODO(caitp): Implement AsyncFunctionAwait() | 
| - // per tc39.github.io/ecmascript-asyncawait/#abstract-ops-async-function-await | 
| - return value; | 
| + Expression* generator_object = parser_->factory()->NewVariableProxy( | 
| + parser_->function_state_->generator_object_variable()); | 
| + | 
| + ZoneList<Expression*>* async_function_await_args = | 
| + new (zone()) ZoneList<Expression*>(2, zone()); | 
| + async_function_await_args->Add(generator_object, zone()); | 
| + async_function_await_args->Add(value, zone()); | 
| + Expression* async_function_await = parser_->factory()->NewCallRuntime( | 
| + Context::ASYNC_FUNCTION_AWAIT_INDEX, async_function_await_args, | 
| + RelocInfo::kNoPosition); | 
| + | 
| + generator_object = parser_->factory()->NewVariableProxy( | 
| + parser_->function_state_->generator_object_variable()); | 
| + return parser_->factory()->NewYield(generator_object, async_function_await, | 
| + pos); | 
| } | 
| Zone* ParserTraits::zone() const { |