Index: runtime/vm/parser.cc |
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
index 4d0e741c47c372fae22fc0e384917383cc8aa14e..8897907f38ba1750af61971318da6c80a273e54e 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" |
@@ -2971,6 +2972,15 @@ 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++; |
hausner
2014/08/07 21:48:43
Why is this parameter optional? The caller will al
Michael Lippautz (Google)
2014/08/08 18:12:18
Maybe I am missing something, but the first time w
|
+ 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()); |
@@ -3027,6 +3037,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; |
@@ -5508,6 +5520,12 @@ void Parser::OpenFunctionBlock(const Function& func) { |
} |
+void 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) { |
// Create the closure containing the old body of this function. |
Class& sig_cls = Class::ZoneHandle(I); |
@@ -5519,12 +5537,20 @@ 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(), |
formal_param_pos); |
AddFormalParamsToFunction(&closure_params, closure); |
closure.set_is_async_closure(true); |
+ closure.set_is_inlinable(false); |
closure.set_result_type(AbstractType::Handle(Type::DynamicType())); |
sig = closure.Signature(); |
sig_cls = library_.LookupLocalClass(sig); |
@@ -5891,7 +5917,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) { |
@@ -7768,7 +7794,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; |
@@ -8424,6 +8450,40 @@ static AstNode* LiteralIfStaticConst(Isolate* iso, AstNode* expr) { |
} |
+AstNode* Parser::ParseAwaitableExpr(bool require_compiletime_const, |
hausner
2014/08/07 21:48:43
As discussed offline, I believe all expressions ar
Michael Lippautz (Google)
2014/08/08 18:12:18
Again discussed offline :)
Example:
var x = ((
|
+ bool consume_cascades) { |
+ TRACE_PARSER("ParseAwaitableExpr"); |
+ parsed_function()->reset_seen_await(); |
+ AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades); |
+ if (parsed_function()->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_seen_await(); |
+ return at.Result(); |
+ } |
+ return expr; |
+} |
+ |
+ |
+AstNode* Parser::ParseAwaitExpr() { |
hausner
2014/08/07 21:48:43
Could maybe inline this code in ParsePrimary.
Michael Lippautz (Google)
2014/08/08 18:12:18
Done.
|
+ TRACE_PARSER("ParseAwaitExpr"); |
+ ConsumeToken(); |
+ parsed_function()->record_await(); |
+ return new (I) AwaitNode( |
+ TokenPos(), ParseExpr(kAllowConst, kConsumeCascades)); |
+} |
+ |
+ |
AstNode* Parser::ParseExpr(bool require_compiletime_const, |
bool consume_cascades) { |
TRACE_PARSER("ParseExpr"); |
@@ -10792,6 +10852,8 @@ AstNode* Parser::ParsePrimary() { |
OpenBlock(); |
primary = ParseFunctionStatement(true); |
CloseBlock(); |
+ } else if (IsLiteral("await")) { |
+ primary = ParseAwaitExpr(); |
} else if (IsIdentifier()) { |
intptr_t qual_ident_pos = TokenPos(); |
const LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(I, ParsePrefix()); |