| Index: runtime/vm/parser.cc
|
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
|
| index f87763f6ab7837facb37d5cbb296405a2b844b09..28fc9b486ddbb31cfd6ddf7f7bcb014ad6c23974 100644
|
| --- a/runtime/vm/parser.cc
|
| +++ b/runtime/vm/parser.cc
|
| @@ -6,6 +6,7 @@
|
|
|
| #include "lib/invocation_mirror.h"
|
| #include "platform/utils.h"
|
| +#include "vm/ast_transformer.h"
|
| #include "vm/bootstrap.h"
|
| #include "vm/class_finalizer.h"
|
| #include "vm/compiler.h"
|
| @@ -2988,13 +2989,25 @@ SequenceNode* Parser::ParseFunc(const Function& func,
|
| // we are compiling a getter this will at most populate the receiver.
|
| AddFormalParamsToScope(¶ms, current_block_->scope);
|
| } else if (func.is_async_closure()) {
|
| + // Async closures have one optional parameter for continuation results.
|
| + ParamDesc result_param;
|
| + result_param.name = &Symbols::AsyncOperationParam();
|
| + result_param.default_value = &Object::null_instance();
|
| + result_param.type = &Type::ZoneHandle(I, Type::DynamicType());
|
| + params.parameters->Add(result_param);
|
| + params.num_optional_parameters++;
|
| + params.has_optional_positional_parameters = true;
|
| + SetupDefaultsForOptionalParams(¶ms, default_parameter_values);
|
| AddFormalParamsToScope(¶ms, current_block_->scope);
|
| ASSERT(AbstractType::Handle(I, func.result_type()).IsResolved());
|
| ASSERT(func.NumParameters() == params.parameters->length());
|
| if (!Function::Handle(func.parent_function()).IsGetterFunction()) {
|
| // Parse away any formal parameters, as they are accessed as as context
|
| // variables.
|
| - ParseFormalParameterList(allow_explicit_default_values, false, ¶ms);
|
| + ParamList parse_away;
|
| + ParseFormalParameterList(allow_explicit_default_values,
|
| + false,
|
| + &parse_away);
|
| }
|
| } else {
|
| ParseFormalParameterList(allow_explicit_default_values, false, ¶ms);
|
| @@ -3044,6 +3057,8 @@ SequenceNode* Parser::ParseFunc(const Function& func,
|
| Function& async_closure = Function::ZoneHandle(I);
|
| if (func.IsAsyncFunction() && !func.is_async_closure()) {
|
| async_closure = OpenAsyncFunction(formal_params_pos);
|
| + } else if (func.is_async_closure()) {
|
| + OpenAsyncClosure();
|
| }
|
|
|
| intptr_t end_token_pos = 0;
|
| @@ -5526,7 +5541,15 @@ void Parser::OpenFunctionBlock(const Function& func) {
|
| }
|
|
|
|
|
| +void Parser::OpenAsyncClosure() {
|
| + TRACE_PARSER("OpenAsyncClosure");
|
| + parsed_function()->set_await_temps_scope(current_block_->scope);
|
| + // TODO(mlippautz): Set up explicit jump table for await continuations.
|
| +}
|
| +
|
| +
|
| RawFunction* Parser::OpenAsyncFunction(intptr_t formal_param_pos) {
|
| + TRACE_PARSER("OpenAsyncFunction");
|
| // Create the closure containing the old body of this function.
|
| Class& sig_cls = Class::ZoneHandle(I);
|
| Type& sig_type = Type::ZoneHandle(I);
|
| @@ -5537,6 +5560,13 @@ RawFunction* Parser::OpenAsyncFunction(intptr_t formal_param_pos) {
|
| formal_param_pos,
|
| &Symbols::ClosureParameter(),
|
| &Type::ZoneHandle(I, Type::DynamicType()));
|
| + ParamDesc result_param;
|
| + result_param.name = &Symbols::AsyncOperationParam();
|
| + result_param.default_value = &Object::null_instance();
|
| + result_param.type = &Type::ZoneHandle(I, Type::DynamicType());
|
| + closure_params.parameters->Add(result_param);
|
| + closure_params.has_optional_positional_parameters = true;
|
| + closure_params.num_optional_parameters++;
|
| closure = Function::NewClosureFunction(
|
| Symbols::AnonymousClosure(),
|
| innermost_function(),
|
| @@ -5580,6 +5610,7 @@ SequenceNode* Parser::CloseBlock() {
|
|
|
| SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
|
| SequenceNode* closure_body) {
|
| + TRACE_PARSER("CloseAsyncFunction");
|
| ASSERT(!closure.IsNull());
|
| ASSERT(closure_body != NULL);
|
| // The block for the async closure body has already been closed. Close the
|
| @@ -5676,6 +5707,7 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
|
|
|
|
|
| void Parser::CloseAsyncClosure(SequenceNode* body) {
|
| + TRACE_PARSER("CloseAsyncClosure");
|
| // We need a temporary expression to store intermediate return values.
|
| parsed_function()->EnsureExpressionTemp();
|
| }
|
| @@ -5878,7 +5910,7 @@ AstNode* Parser::ParseVariableDeclaration(const AbstractType& type,
|
| // Variable initialization.
|
| const intptr_t assign_pos = TokenPos();
|
| ConsumeToken();
|
| - AstNode* expr = ParseExpr(is_const, kConsumeCascades);
|
| + AstNode* expr = ParseAwaitableExpr(is_const, kConsumeCascades);
|
| initialization = new(I) StoreLocalNode(
|
| assign_pos, variable, expr);
|
| if (is_const) {
|
| @@ -7751,7 +7783,7 @@ AstNode* Parser::ParseStatement() {
|
| new(I) LoadLocalNode(statement_pos, excp_var),
|
| new(I) LoadLocalNode(statement_pos, trace_var));
|
| } else {
|
| - statement = ParseExpr(kAllowConst, kConsumeCascades);
|
| + statement = ParseAwaitableExpr(kAllowConst, kConsumeCascades);
|
| ExpectSemicolon();
|
| }
|
| return statement;
|
| @@ -8407,6 +8439,31 @@ static AstNode* LiteralIfStaticConst(Isolate* iso, AstNode* expr) {
|
| }
|
|
|
|
|
| +AstNode* Parser::ParseAwaitableExpr(bool require_compiletime_const,
|
| + bool consume_cascades) {
|
| + TRACE_PARSER("ParseAwaitableExpr");
|
| + parsed_function()->reset_have_seen_await();
|
| + AstNode* expr = ParseExpr(require_compiletime_const, consume_cascades);
|
| + if (parsed_function()->have_seen_await()) {
|
| + if (!current_block_->scope->LookupVariable(
|
| + Symbols::AsyncOperation(), true)) {
|
| + // Async operations are always encapsulated into a local function. We only
|
| + // need to transform the expression when generating code for this inner
|
| + // function.
|
| + return expr;
|
| + }
|
| + SequenceNode* intermediates_block = new(I) SequenceNode(
|
| + Scanner::kNoSourcePos, current_block_->scope);
|
| + AwaitTransformer at(intermediates_block, library_, parsed_function());
|
| + AstNode* result = at.Transform(expr);
|
| + current_block_->statements->Add(intermediates_block);
|
| + parsed_function()->reset_have_seen_await();
|
| + return result;
|
| + }
|
| + return expr;
|
| +}
|
| +
|
| +
|
| AstNode* Parser::ParseExpr(bool require_compiletime_const,
|
| bool consume_cascades) {
|
| TRACE_PARSER("ParseExpr");
|
| @@ -10775,6 +10832,18 @@ AstNode* Parser::ParsePrimary() {
|
| OpenBlock();
|
| primary = ParseFunctionStatement(true);
|
| CloseBlock();
|
| + } else if (IsLiteral("await") &&
|
| + (parsed_function()->function().IsAsyncFunction() ||
|
| + parsed_function()->function().is_async_closure())) {
|
| + // The body of an async function is parsed multiple times. The first time
|
| + // when setting up an AsyncFunction() for generating relevant scope
|
| + // information. The second time the body is parsed for actually generating
|
| + // code.
|
| + TRACE_PARSER("ParseAwaitExpr");
|
| + ConsumeToken();
|
| + parsed_function()->record_await();
|
| + primary = new(I) AwaitNode(
|
| + TokenPos(), ParseExpr(kAllowConst, kConsumeCascades));
|
| } else if (IsIdentifier()) {
|
| intptr_t qual_ident_pos = TokenPos();
|
| const LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(I, ParsePrefix());
|
|
|