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

Unified Diff: src/parsing/parser.cc

Issue 2637403008: [async-iteration] add support for for-await-of loops in Async Functions (Closed)
Patch Set: Created 3 years, 11 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 dcb973da78ebc39f91b7f157621f37be41c66fad..8d9e4c72005eb856db68fc8ab70e2cca7f2f6145 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -553,6 +553,7 @@ Parser::Parser(ParseInfo* info)
set_allow_harmony_trailing_commas(FLAG_harmony_trailing_commas);
set_allow_harmony_class_fields(FLAG_harmony_class_fields);
set_allow_harmony_object_rest_spread(FLAG_harmony_object_rest_spread);
+ set_allow_harmony_async_iteration(FLAG_harmony_async_iteration);
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
use_counts_[feature] = 0;
@@ -1757,7 +1758,8 @@ Statement* Parser::RewriteTryStatement(Block* try_block, Block* catch_block,
// !%_IsJSReceiver(result = iterator.next()) &&
// %ThrowIteratorResultNotAnObject(result)
neis 2017/01/20 14:38:15 Comment needs an update.
Expression* Parser::BuildIteratorNextResult(Expression* iterator,
- Variable* result, int pos) {
+ Variable* result, IteratorType type,
+ int pos) {
Expression* next_literal = factory()->NewStringLiteral(
ast_value_factory()->next_string(), kNoSourcePosition);
Expression* next_property =
@@ -1766,6 +1768,9 @@ Expression* Parser::BuildIteratorNextResult(Expression* iterator,
new (zone()) ZoneList<Expression*>(0, zone());
Expression* next_call =
factory()->NewCall(next_property, next_arguments, pos);
+ if (type == IteratorType::kAsync) {
+ next_call = RewriteAwaitExpression(next_call, pos);
+ }
Expression* result_proxy = factory()->NewVariableProxy(result);
Expression* left =
factory()->NewAssignment(Token::ASSIGN, result_proxy, next_call, pos);
@@ -1977,7 +1982,8 @@ Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of,
{
assign_iterator = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(iterator),
- factory()->NewGetIterator(iterable, iterable->position()),
+ factory()->NewGetIterator(iterable, GetIterator::kNormal,
+ iterable->position()),
iterable->position());
}
@@ -1986,8 +1992,8 @@ Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of,
Expression* next_result;
{
Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
- next_result =
- BuildIteratorNextResult(iterator_proxy, result, next_result_pos);
+ next_result = BuildIteratorNextResult(
+ iterator_proxy, result, IteratorType::kNormal, next_result_pos);
}
// result.done
@@ -2075,7 +2081,139 @@ Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of,
for_of->Initialize(body, iterator, assign_iterator, next_result, result_done,
assign_each);
- return finalize ? FinalizeForOfStatement(for_of, completion, nopos) : for_of;
+ return finalize ? FinalizeForOfStatement(for_of, completion,
+ IteratorType::kNormal, nopos)
+ : for_of;
+}
+
+Statement* Parser::InitializeForAwaitOfStatement(ForEachStatement* for_each,
neis 2017/01/20 14:38:15 Can't you just parameterize the existing Initializ
caitp 2017/01/20 17:05:34 It's doable, but harder to read IMO . Whatever peo
caitp 2017/01/20 20:17:19 Eh, it actually gets pretty ugly to try to do it t
+ Expression* each,
+ Expression* iterable,
+ Statement* body, bool finalize,
+ int next_result_pos) {
+ // Create the auxiliary expressions needed for iterating over the iterable,
+ // and initialize the given ForOfStatement with them.
+ // If finalize is true, also instrument the loop with code that performs the
+ // proper ES6 iterator finalization. In that case, the result is not
+ // immediately a ForOfStatement.
+
+ ForOfStatement* for_of = for_each->AsForOfStatement();
+ DCHECK_NOT_NULL(for_of);
+
+ const int nopos = kNoSourcePosition;
+ auto avfactory = ast_value_factory();
+
+ Variable* iterator = NewTemporary(avfactory->dot_iterator_string());
+ Variable* result = NewTemporary(avfactory->dot_result_string());
+ Variable* completion = NewTemporary(avfactory->empty_string());
+
+ // iterator = GetIterator(iterable)
neis 2017/01/20 14:38:16 Comment needs an update.
+ Expression* assign_iterator;
+ {
+ assign_iterator = factory()->NewAssignment(
+ Token::ASSIGN, factory()->NewVariableProxy(iterator),
+ factory()->NewGetIterator(iterable, GetIterator::kAsync,
+ iterable->position()),
+ iterable->position());
+ }
+
+ // !%_IsJSReceiver(result = iterator.next()) &&
+ // %ThrowIteratorResultNotAnObject(result)
neis 2017/01/20 14:38:15 Comment needs an update.
+ Expression* next_result;
+ {
+ Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
+ next_result = BuildIteratorNextResult(
+ iterator_proxy, result, IteratorType::kAsync, next_result_pos);
+ }
+
+ // result.done
+ Expression* result_done;
+ {
+ Expression* done_literal = factory()->NewStringLiteral(
+ ast_value_factory()->done_string(), kNoSourcePosition);
+ Expression* result_proxy = factory()->NewVariableProxy(result);
+ result_done =
+ factory()->NewProperty(result_proxy, done_literal, kNoSourcePosition);
+ }
+
+ // result.value
+ Expression* result_value;
+ {
+ Expression* value_literal =
+ factory()->NewStringLiteral(avfactory->value_string(), nopos);
+ Expression* result_proxy = factory()->NewVariableProxy(result);
+ result_value = factory()->NewProperty(result_proxy, value_literal, nopos);
+ }
+
+ // {{completion = kAbruptCompletion;}}
+ Statement* set_completion_abrupt;
+ if (finalize) {
+ Expression* proxy = factory()->NewVariableProxy(completion);
+ Expression* assignment = factory()->NewAssignment(
+ Token::ASSIGN, proxy,
+ factory()->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
+
+ Block* block = factory()->NewBlock(nullptr, 1, true, nopos);
+ block->statements()->Add(
+ factory()->NewExpressionStatement(assignment, nopos), zone());
+ set_completion_abrupt = block;
+ }
+
+ // do { let tmp = #result_value; #set_completion_abrupt; tmp }
+ // Expression* result_value (gets overwritten)
+ if (finalize) {
+ Variable* var_tmp = NewTemporary(avfactory->empty_string());
+ Expression* tmp = factory()->NewVariableProxy(var_tmp);
+ Expression* assignment =
+ factory()->NewAssignment(Token::ASSIGN, tmp, result_value, nopos);
+
+ Block* block = factory()->NewBlock(nullptr, 2, false, nopos);
+ block->statements()->Add(
+ factory()->NewExpressionStatement(assignment, nopos), zone());
+ block->statements()->Add(set_completion_abrupt, zone());
+
+ result_value = factory()->NewDoExpression(block, var_tmp, nopos);
+ }
+
+ // each = #result_value;
+ Expression* assign_each;
+ {
+ assign_each =
+ factory()->NewAssignment(Token::ASSIGN, each, result_value, nopos);
+ if (each->IsArrayLiteral() || each->IsObjectLiteral()) {
+ assign_each = PatternRewriter::RewriteDestructuringAssignment(
+ this, assign_each->AsAssignment(), scope());
+ }
+ }
+
+ // {{completion = kNormalCompletion;}}
+ Statement* set_completion_normal;
+ if (finalize) {
+ Expression* proxy = factory()->NewVariableProxy(completion);
+ Expression* assignment = factory()->NewAssignment(
+ Token::ASSIGN, proxy,
+ factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
+
+ Block* block = factory()->NewBlock(nullptr, 1, true, nopos);
+ block->statements()->Add(
+ factory()->NewExpressionStatement(assignment, nopos), zone());
+ set_completion_normal = block;
+ }
+
+ // { #loop-body; #set_completion_normal }
+ // Statement* body (gets overwritten)
+ if (finalize) {
+ Block* block = factory()->NewBlock(nullptr, 2, false, nopos);
+ block->statements()->Add(body, zone());
+ block->statements()->Add(set_completion_normal, zone());
+ body = block;
+ }
+
+ for_of->Initialize(body, iterator, assign_iterator, next_result, result_done,
+ assign_each);
+ return finalize ? FinalizeForOfStatement(for_of, completion,
+ IteratorType::kAsync, nopos)
+ : for_of;
}
Statement* Parser::DesugarLexicalBindingsInForStatement(
@@ -2740,6 +2878,7 @@ Parser::LazyParsingResult Parser::SkipFunction(
SET_ALLOW(harmony_trailing_commas);
SET_ALLOW(harmony_class_fields);
SET_ALLOW(harmony_object_rest_spread);
+ SET_ALLOW(harmony_async_iteration);
#undef SET_ALLOW
}
// Aborting inner function preparsing would leave scopes in an inconsistent
@@ -4345,7 +4484,8 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
Variable* var_iterator = NewTemporary(ast_value_factory()->empty_string());
Statement* get_iterator;
{
- Expression* iterator = factory()->NewGetIterator(iterable, nopos);
+ Expression* iterator =
+ factory()->NewGetIterator(iterable, GetIterator::kNormal, nopos);
Expression* iterator_proxy = factory()->NewVariableProxy(var_iterator);
Expression* assignment = factory()->NewAssignment(
Token::ASSIGN, iterator_proxy, iterator, nopos);
@@ -4427,7 +4567,8 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
Block* then = factory()->NewBlock(nullptr, 4 + 1, false, nopos);
BuildIteratorCloseForCompletion(
scope(), then->statements(), var_iterator,
- factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos));
+ factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos),
+ IteratorType::kNormal);
then->statements()->Add(throw_call, zone());
check_throw = factory()->NewIfStatement(
condition, then, factory()->NewEmptyStatement(nopos), nopos);
@@ -4613,7 +4754,8 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
case_next->Add(factory()->NewBreakStatement(switch_mode, nopos), zone());
auto case_return = new (zone()) ZoneList<Statement*>(5, zone());
- BuildIteratorClose(case_return, var_iterator, var_input, var_output);
+ BuildIteratorClose(case_return, var_iterator, var_input, var_output,
+ IteratorType::kNormal);
case_return->Add(factory()->NewBreakStatement(switch_mode, nopos), zone());
auto case_throw = new (zone()) ZoneList<Statement*>(5, zone());
@@ -4697,7 +4839,7 @@ Statement* Parser::CheckCallable(Variable* var, Expression* error, int pos) {
void Parser::BuildIteratorClose(ZoneList<Statement*>* statements,
Variable* iterator, Variable* input,
- Variable* var_output) {
+ Variable* var_output, IteratorType type) {
//
neis 2017/01/20 14:38:15 This function is only used in RewriteYieldStar and
caitp 2017/01/20 17:05:34 That may be a bug then. You're supposed to Iterato
// This function adds four statements to [statements], corresponding to the
// following code:
@@ -4706,7 +4848,13 @@ void Parser::BuildIteratorClose(ZoneList<Statement*>* statements,
// if (IS_NULL_OR_UNDEFINED(iteratorReturn) {
// return {value: input, done: true};
// }
- // output = %_Call(iteratorReturn, iterator, input);
+ //
+ // [if (IteratorType == kAsync)]
+ // output = Await(%_Call(iteratorReturn, iterator, input));
+ // [else]
+ // output = %_Call(iteratorReturn, iterator, input);
+ // [endif]
+ //
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
//
@@ -4755,6 +4903,10 @@ void Parser::BuildIteratorClose(ZoneList<Statement*>* statements,
Expression* call =
factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+ if (type == IteratorType::kAsync) {
+ call = RewriteAwaitExpression(call, nopos);
+ }
+
Expression* output_proxy = factory()->NewVariableProxy(var_output);
Expression* assignment =
factory()->NewAssignment(Token::ASSIGN, output_proxy, call, nopos);
@@ -4794,7 +4946,8 @@ void Parser::BuildIteratorClose(ZoneList<Statement*>* statements,
void Parser::FinalizeIteratorUse(Scope* use_scope, Variable* completion,
Expression* condition, Variable* iter,
- Block* iterator_use, Block* target) {
+ Block* iterator_use, Block* target,
+ IteratorType type) {
//
// This function adds two statements to [target], corresponding to the
// following code:
@@ -4850,8 +5003,8 @@ void Parser::FinalizeIteratorUse(Scope* use_scope, Variable* completion,
{
Block* block = factory()->NewBlock(nullptr, 2, true, nopos);
Expression* proxy = factory()->NewVariableProxy(completion);
- BuildIteratorCloseForCompletion(use_scope, block->statements(), iter,
- proxy);
+ BuildIteratorCloseForCompletion(use_scope, block->statements(), iter, proxy,
+ type);
DCHECK(block->statements()->length() == 2);
maybe_close = factory()->NewBlock(nullptr, 1, true, nopos);
@@ -4910,7 +5063,8 @@ void Parser::FinalizeIteratorUse(Scope* use_scope, Variable* completion,
void Parser::BuildIteratorCloseForCompletion(Scope* scope,
ZoneList<Statement*>* statements,
Variable* iterator,
- Expression* completion) {
+ Expression* completion,
+ IteratorType type) {
//
// This function adds two statements to [statements], corresponding to the
// following code:
@@ -4968,6 +5122,10 @@ void Parser::BuildIteratorCloseForCompletion(Scope* scope,
Expression* call =
factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+ if (type == IteratorType::kAsync) {
+ call = RewriteAwaitExpression(call, nopos);
+ }
+
Block* try_block = factory()->NewBlock(nullptr, 1, false, nopos);
try_block->statements()->Add(factory()->NewExpressionStatement(call, nopos),
zone());
@@ -5067,7 +5225,8 @@ void Parser::BuildIteratorCloseForCompletion(Scope* scope,
}
Statement* Parser::FinalizeForOfStatement(ForOfStatement* loop,
- Variable* var_completion, int pos) {
+ Variable* var_completion,
+ IteratorType type, int pos) {
//
// This function replaces the loop with the following wrapping:
//
@@ -5111,7 +5270,7 @@ Statement* Parser::FinalizeForOfStatement(ForOfStatement* loop,
DCHECK_EQ(scope()->scope_type(), BLOCK_SCOPE);
FinalizeIteratorUse(loop_scope, var_completion, closing_condition,
- loop->iterator(), try_block, final_loop);
+ loop->iterator(), try_block, final_loop, type);
}
return final_loop;

Powered by Google App Engine
This is Rietveld 408576698