Index: runtime/vm/parser.cc |
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
index a82fff7c43f308c942dce08fd5be3fd7181f61e1..d5b17108d374d0b8d70127057825e3a55d19c3b4 100644 |
--- a/runtime/vm/parser.cc |
+++ b/runtime/vm/parser.cc |
@@ -39,6 +39,7 @@ DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements."); |
DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks."); |
DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations."); |
DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef."); |
+DEFINE_FLAG(bool, enable_async, false, "Enable async operations."); |
DECLARE_FLAG(bool, error_on_bad_type); |
DECLARE_FLAG(bool, throw_on_javascript_int_overflow); |
DECLARE_FLAG(bool, warn_on_javascript_compatibility); |
@@ -2877,6 +2878,99 @@ SequenceNode* Parser::ParseConstructor(const Function& func, |
} |
+// TODO(mlippautz): Once we know where Future should come from, adjust how we |
+// get it's definition. |
hausner
2014/07/12 00:05:24
its
Michael Lippautz (Google)
2014/07/14 20:22:48
Done.
|
+RawClass* Parser::GetFutureClass() { |
+ const Class& cls = Class::Handle(library_.LookupClass(Symbols::Future())); |
+ if (cls.IsNull()) { |
+ ReportError("async modifier requires dart:async to be imported"); |
+ } |
+ return cls.raw(); |
+} |
+ |
+ |
+SequenceNode* Parser::BuildAsyncFuture(const Function& outer, |
+ SequenceNode* parsed_body, |
+ ParamList* params, |
+ intptr_t saved_pos) { |
+ const Class& future = Class::ZoneHandle(I, GetFutureClass()); |
+ ASSERT(!future.IsNull()); |
+ const Function& constructor = Function::ZoneHandle(I, |
+ future.LookupFunction(Symbols::FutureConstructor())); |
+ ASSERT(!constructor.IsNull()); |
+ // Create the closure containing the parsed_body of this function. |
+ Class& sig_cls = Class::ZoneHandle(I); |
+ Type& sig_type = Type::ZoneHandle(I); |
+ Function& closure = Function::ZoneHandle(I); |
+ String& sig = String::ZoneHandle(I); |
+ ParamList closure_params; |
+ closure_params.AddFinalParameter( |
+ saved_pos, |
+ &Symbols::ClosureParameter(), |
+ &Type::ZoneHandle(I, Type::DynamicType())); |
+ closure = Function::NewClosureFunction( |
+ Symbols::AnonymousClosure(), |
+ innermost_function(), |
+ saved_pos); |
+ AddFormalParamsToFunction(&closure_params, closure); |
+ closure.set_is_synthetic_container(true); |
+ // TODO(mlippautz): For an async outer function declared with Future<T> the |
+ // result type of the synthesized closure should be T. |
+ closure.set_result_type(AbstractType::Handle(Type::DynamicType())); |
+ sig = closure.Signature(); |
+ sig_cls = library_.LookupLocalClass(sig); |
+ if (sig_cls.IsNull()) { |
+ sig_cls = Class::NewSignatureClass(sig, closure, script_, saved_pos); |
+ library_.AddClass(sig_cls); |
+ } |
+ closure.set_signature_class(sig_cls); |
+ sig_type = sig_cls.SignatureType(); |
+ if (!sig_type.IsFinalized()) { |
+ ClassFinalizer::FinalizeType( |
+ sig_cls, sig_type, ClassFinalizer::kCanonicalize); |
+ } |
+ ASSERT(AbstractType::Handle(I, closure.result_type()).IsResolved()); |
+ ASSERT(closure.NumParameters() == closure_params.parameters->length()); |
+ OpenFunctionBlock(closure); |
+ AddFormalParamsToScope(&closure_params, current_block_->scope); |
+ LocalScope* cur_scope = current_block_->scope; |
+ String& var_name = String::ZoneHandle(I); |
+ bool var_captured = false; |
+ // Capture parameters of the enclosing function. |
+ for (intptr_t i = 0; i < params->parameters->length(); i++) { |
+ ParamDesc& param_desc = (*params->parameters)[i]; |
+ var_name = param_desc.var->name().raw(); |
+ // Ignore implicit closure parameter, but capture 'this' from any enclosing |
+ // methods. |
+ if (var_name.Equals(Symbols::ClosureParameter())) { |
+ continue; |
+ } |
+ var_captured = cur_scope->CaptureVariable(var_name); |
+ ASSERT(var_captured); |
+ } |
+ LocalScope* parsed_body_scope = parsed_body->scope(); |
+ // Capture all variables that have already been captured by the enclosing |
+ // function. |
+ for (intptr_t j = 0; j < parsed_body->scope()->num_variables(); j++) { |
+ if (parsed_body_scope->VariableAt(j)->is_captured()) { |
+ var_captured = |
+ cur_scope->CaptureVariable(parsed_body_scope->VariableAt(j)->name()); |
+ ASSERT(var_captured); |
+ } |
+ } |
+ ClosureNode* cn = new(I) ClosureNode( |
+ Scanner::kNoSourcePos, closure, NULL, cur_scope); |
+ ArgumentListNode* arguments = new (I) ArgumentListNode(saved_pos); |
+ arguments->Add(cn); |
+ ConstructorCallNode* ccn = new (I) ConstructorCallNode( |
+ Scanner::kNoSourcePos, TypeArguments::ZoneHandle(I), constructor, |
+ arguments); |
+ ReturnNode* rn = new (I) ReturnNode(Scanner::kNoSourcePos, ccn); |
+ current_block_->statements->Add(rn); |
+ return CloseBlock(); |
+} |
+ |
+ |
// Parser is at the opening parenthesis of the formal parameter |
// declaration of the function or constructor. |
// Parse the formal parameters and code. |
@@ -2891,6 +2985,7 @@ SequenceNode* Parser::ParseFunc(const Function& func, |
intptr_t saved_try_index = last_used_try_index_; |
last_used_try_index_ = 0; |
+ intptr_t formal_params_pos = TokenPos(); |
// TODO(12455) : Need better validation mechanism. |
if (func.IsConstructor()) { |
@@ -2925,12 +3020,24 @@ SequenceNode* Parser::ParseFunc(const Function& func, |
&Symbols::TypeArgumentsParameter(), |
&Type::ZoneHandle(I, Type::DynamicType())); |
} |
- ASSERT((CurrentToken() == Token::kLPAREN) || func.IsGetterFunction()); |
+ ASSERT((CurrentToken() == Token::kLPAREN) || func.IsGetterFunction() || |
+ func.is_synthetic_container()); |
const bool allow_explicit_default_values = true; |
if (func.IsGetterFunction()) { |
// Populate function scope with the formal parameters. Since in this case |
// we are compiling a getter this will at most populate the receiver. |
AddFormalParamsToScope(¶ms, current_block_->scope); |
+ } else if (func.is_synthetic_container() && Function::Handle( |
+ func.parent_function()).IsGetterFunction()) { |
+ AddFormalParamsToScope(¶ms, current_block_->scope); |
+ ASSERT(AbstractType::Handle(I, func.result_type()).IsResolved()); |
+ ASSERT(func.NumParameters() == params.parameters->length()); |
+ } else if (func.is_synthetic_container()) { |
+ AddFormalParamsToScope(¶ms, current_block_->scope); |
+ ASSERT(AbstractType::Handle(I, func.result_type()).IsResolved()); |
+ ASSERT(func.NumParameters() == params.parameters->length()); |
+ ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
+ // Parse them away. |
} else { |
ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
@@ -2971,6 +3078,9 @@ SequenceNode* Parser::ParseFunc(const Function& func, |
} |
} |
+ RawFunction::Modifier func_modifier = ParseFunctionModifier(); |
+ func.set_modifier(func_modifier); |
+ |
OpenBlock(); // Open a nested scope for the outermost function block. |
intptr_t end_token_pos = 0; |
if (CurrentToken() == Token::kLBRACE) { |
@@ -3032,6 +3142,9 @@ SequenceNode* Parser::ParseFunc(const Function& func, |
func.end_token_pos() == end_token_pos); |
func.set_end_token_pos(end_token_pos); |
SequenceNode* body = CloseBlock(); |
+ if (func.IsAsyncFunction() && !func.is_synthetic_container()) { |
+ body = BuildAsyncFuture(func, body, ¶ms, formal_params_pos); |
+ } |
current_block_->statements->Add(body); |
innermost_function_ = saved_innermost_function.raw(); |
last_used_try_index_ = saved_try_index; |
@@ -3345,6 +3458,8 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { |
method->name->ToCString()); |
} |
+ ParseFunctionModifier(); |
+ |
intptr_t method_end_pos = TokenPos(); |
if ((CurrentToken() == Token::kLBRACE) || |
(CurrentToken() == Token::kARROW)) { |
@@ -4779,6 +4894,17 @@ void Parser::ParseTopLevelVariable(TopLevel* top_level, |
} |
+RawFunction::Modifier Parser::ParseFunctionModifier() { |
+ if (FLAG_enable_async) { |
+ if (CurrentLiteral()->raw() == Symbols::Async().raw()) { |
+ ConsumeToken(); |
+ return RawFunction::kAsync; |
+ } |
+ } |
+ return RawFunction::kNoModifier; |
+} |
+ |
+ |
void Parser::ParseTopLevelFunction(TopLevel* top_level, |
intptr_t metadata_pos) { |
TRACE_PARSER("ParseTopLevelFunction"); |
@@ -4832,6 +4958,8 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level, |
const bool allow_explicit_default_values = true; |
ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
+ RawFunction::Modifier func_modifier = ParseFunctionModifier(); |
+ |
intptr_t function_end_pos = function_pos; |
bool is_native = false; |
if (is_external) { |
@@ -4866,6 +4994,7 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level, |
decl_begin_pos)); |
func.set_result_type(result_type); |
func.set_end_token_pos(function_end_pos); |
+ func.set_modifier(func_modifier); |
if (is_native && library_.is_dart_scheme() && library_.IsPrivate(func_name)) { |
func.set_is_visible(false); |
} |
@@ -4968,6 +5097,8 @@ void Parser::ParseTopLevelAccessor(TopLevel* top_level, |
field_name->ToCString()); |
} |
+ RawFunction::Modifier func_modifier = ParseFunctionModifier(); |
+ |
intptr_t accessor_end_pos = accessor_pos; |
bool is_native = false; |
if (is_external) { |
@@ -5003,6 +5134,7 @@ void Parser::ParseTopLevelAccessor(TopLevel* top_level, |
decl_begin_pos)); |
func.set_result_type(result_type); |
func.set_end_token_pos(accessor_end_pos); |
+ func.set_modifier(func_modifier); |
if (is_native && library_.is_dart_scheme() && |
library_.IsPrivate(accessor_name)) { |
func.set_is_visible(false); |
@@ -6207,7 +6339,9 @@ bool Parser::IsFunctionDeclaration() { |
if ((CurrentToken() == Token::kLBRACE) || |
(CurrentToken() == Token::kARROW) || |
(is_top_level_ && IsLiteral("native")) || |
- is_external) { |
+ is_external || |
+ (FLAG_enable_async && |
+ CurrentLiteral()->raw() == Symbols::Async().raw())) { |
SetPosition(saved_pos); |
return true; |
} |
@@ -10746,6 +10880,7 @@ void Parser::SkipFunctionLiteral() { |
params.skipped = true; |
ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
} |
+ ParseFunctionModifier(); |
if (CurrentToken() == Token::kLBRACE) { |
SkipBlock(); |
ExpectToken(Token::kRBRACE); |