Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(835)

Unified Diff: src/parsing/parser.cc

Issue 1895603002: [esnext] prototype runtime implementation for async functions (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@AsyncFunction
Patch Set: properly rebase Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 {

Powered by Google App Engine
This is Rietveld 408576698