Chromium Code Reviews| Index: runtime/vm/parser.cc |
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
| index f87763f6ab7837facb37d5cbb296405a2b844b09..14215d14cc623499b8c059b5caacfe2f731e36b8 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. |
|
hausner
2014/08/15 18:09:31
Why is the parameter optional? When would the cont
Michael Lippautz (Google)
2014/08/18 18:39:30
As discussed offline: The first invocation of this
|
| + 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(kAllowConst, kConsumeCascades); |
| + 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()); |
| + at.Transform(expr); |
| + current_block_->statements->Add(intermediates_block); |
| + parsed_function()->reset_have_seen_await(); |
| + return at.Result(); |
| + } |
| + return expr; |
| +} |
| + |
| + |
| AstNode* Parser::ParseExpr(bool require_compiletime_const, |
| bool consume_cascades) { |
| TRACE_PARSER("ParseExpr"); |
| @@ -10775,6 +10832,12 @@ AstNode* Parser::ParsePrimary() { |
| OpenBlock(); |
| primary = ParseFunctionStatement(true); |
| CloseBlock(); |
| + } else if (IsLiteral("await")) { |
|
hausner
2014/08/15 18:09:31
I think Gilad mentioned that await is only recogni
Michael Lippautz (Google)
2014/08/18 18:39:30
Done. Also added a test.
|
| + 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()); |