Chromium Code Reviews| Index: src/parsing/parser.cc |
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
| index f804a84368bd69da3548103d4bea113c108fd455..76eaf2f4a6f856ea0466313f9b46ed6519e3bfc8 100644 |
| --- a/src/parsing/parser.cc |
| +++ b/src/parsing/parser.cc |
| @@ -1110,6 +1110,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info, |
| // NewUnresolved references in current scope. Entrer arrow function |
| // scope for formal parameter parsing. |
| BlockState block_state(&scope_, scope); |
| + function_state.set_parse_phase(FunctionParsePhase::FormalParameters); |
| if (Check(Token::LPAREN)) { |
| // '(' StrictFormalParameters ')' |
| ParseFormalParameterList(&formals, &formals_classifier, &ok); |
| @@ -1125,6 +1126,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info, |
| } |
| if (ok) { |
| + function_state.set_parse_phase(FunctionParsePhase::FunctionBody); |
| checkpoint.Restore(&formals.materialized_literals_count); |
| // Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should |
| // not be observable, or else the preparser would have failed. |
| @@ -2720,6 +2722,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()); |
|
neis
2016/05/11 09:45:16
Can you call these functions Build* rather than Em
|
| } |
| result = factory()->NewReturnStatement(return_value, loc.beg_pos); |
| @@ -3960,6 +3964,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) { |
|
neis
2016/05/11 09:45:16
Please add a comment here on what the desugaring i
caitp (gmail)
2016/05/11 13:42:23
Done.
|
| + scope->ForceContextAllocation(); |
| + // Calling a generator returns a generator object. That object is |
| + // stored |
|
neis
2016/05/11 09:45:16
format (but not sure it's worth to duplicate this
caitp (gmail)
2016/05/11 13:42:23
Removed it
|
| + // 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 = |
|
neis
2016/05/11 09:45:16
assign_yield is a very misleading name.
caitp (gmail)
2016/05/11 13:42:23
Renamed to `init_generator_variable`
|
| + factory()->NewAssignment(Token::INIT, factory()->NewVariableProxy(temp), |
| + allocation, RelocInfo::kNoPosition); |
| + |
| + body->Add( |
| + factory()->NewExpressionStatement(assign_yield, RelocInfo::kNoPosition), |
| + zone()); |
| + |
|
neis
2016/05/11 09:45:16
I would rewrite this as follows:
// Create genera
|
| + 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); |
|
neis
2016/05/11 09:45:17
Calling this catch_block is confusing, as it's the
|
| + |
| + body->Add(catch_block, zone()); |
| + |
| + scope->set_end_position(scanner()->location().end_pos); |
| +} |
| DoExpression* Parser::ParseDoExpression(bool* ok) { |
| // AssignmentExpression :: |
| @@ -4096,6 +4160,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
| int start_position = scanner()->location().beg_pos; |
| scope_->set_start_position(start_position); |
| ParserFormalParameters formals(scope); |
| + function_state.set_parse_phase(FunctionParsePhase::FormalParameters); |
| ParseFormalParameterList(&formals, &formals_classifier, CHECK_OK); |
| arity = formals.Arity(); |
| Expect(Token::RPAREN, CHECK_OK); |
| @@ -4104,7 +4169,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
| CheckArityRestrictions(arity, kind, formals.has_rest, start_position, |
| formals_end_position, CHECK_OK); |
| Expect(Token::LBRACE, CHECK_OK); |
| - |
| + function_state.set_parse_phase(FunctionParsePhase::FunctionBody); |
| // Don't include the rest parameter into the function's formal parameter |
| // count (esp. the SharedFunctionInfo::internal_formal_parameter_count, |
| // which says whether we need to create an arguments adaptor frame). |
| @@ -4508,6 +4573,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 +4674,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( |
| @@ -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); |
| } 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); |
| + } |
| + |
| DCHECK_NOT_NULL(init_block); |
| inner_scope->set_end_position(scanner()->location().end_pos); |
| @@ -5430,9 +5545,26 @@ void ParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier, |
| } |
| Expression* ParserTraits::RewriteAwaitExpression(Expression* value, int pos) { |
|
neis
2016/05/11 09:45:17
Also add a comment here please.
|
| - // TODO(caitp): Implement AsyncFunctionAwait() |
| - // per tc39.github.io/ecmascript-asyncawait/#abstract-ops-async-function-await |
| - return value; |
| + Variable* generator_object_variable = |
| + parser_->function_state_->generator_object_variable(); |
| + |
| + DCHECK_NOT_NULL(generator_object_variable); |
| + |
| + Expression* generator_object = |
| + parser_->factory()->NewVariableProxy(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(generator_object_variable); |
| + return parser_->factory()->NewYield(generator_object, async_function_await, |
| + pos); |
| } |
| Zone* ParserTraits::zone() const { |