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()); |