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

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: remove weird arrow-generator thing 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 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 {

Powered by Google App Engine
This is Rietveld 408576698