Chromium Code Reviews| Index: runtime/vm/parser.cc |
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
| index a82fff7c43f308c942dce08fd5be3fd7181f61e1..b2ac0c80c2ba5521a07ebdda760e542f31d2ae3e 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,84 @@ SequenceNode* Parser::ParseConstructor(const Function& func, |
| } |
| +SequenceNode* Parser::BuildAsyncFuture( |
| + SequenceNode* body, ParamList* params, intptr_t saved_pos) { |
| + const Class& future = Class::ZoneHandle(I, |
| + library_.LookupClass(String::Handle(String::New("Future")))); |
|
hausner
2014/07/11 20:18:40
As mentioned in another place, we need to make sur
Michael Lippautz (Google)
2014/07/11 23:40:45
Done.
|
| + ASSERT(!future.IsNull()); |
| + const Function& constructor = Function::ZoneHandle(I, |
| + future.LookupFunction(String::Handle(String::New("Future.")))); |
| + ASSERT(!constructor.IsNull()); |
| + // Create the closure containing the 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); |
|
hausner
2014/07/11 20:18:40
Thinking about how to name things: isn't the "oute
Michael Lippautz (Google)
2014/07/11 23:40:45
The outer function contains the synthesized body,
hausner
2014/07/12 00:05:24
I can't think of a better name, don't like skip_pa
Michael Lippautz (Google)
2014/07/14 20:22:48
async_closure() it is
|
| + // TODO(mlippautz): Result type should be the originally declared result type. |
|
hausner
2014/07/11 20:18:40
Not sure what the result type really should be. Th
Michael Lippautz (Google)
2014/07/11 23:40:45
Clarified the TODO a bit. Leaving for now as we ne
|
| + 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* body_scope = body->scope(); |
| + // Capture all variables that have already been captured by the enclosing |
|
hausner
2014/07/11 20:18:40
Captured _by_ the enclosing function, or variables
Michael Lippautz (Google)
2014/07/11 23:40:45
We re-capture variables (into the scope of the clo
|
| + // function. |
| + for (intptr_t j = 0; j < body->scope()->num_variables(); j++) { |
| + if (body_scope->VariableAt(j)->is_captured()) { |
| + var_captured = |
| + cur_scope->CaptureVariable(body_scope->VariableAt(j)->name()); |
| + ASSERT(var_captured); |
| + } |
| + } |
| + ClosureNode* cn = new(I) ClosureNode(saved_pos, closure, NULL, cur_scope); |
| + ArgumentListNode* arguments = new (I) ArgumentListNode(saved_pos); |
| + arguments->Add(cn); |
| + ConstructorCallNode* ccn = new (I) ConstructorCallNode( |
| + saved_pos, TypeArguments::ZoneHandle(I), constructor, arguments); |
| + ReturnNode* rn = new (I) ReturnNode(saved_pos, ccn); |
|
hausner
2014/07/11 20:18:40
You should use Scanner::kNoSourcePos for synthesiz
Michael Lippautz (Google)
2014/07/11 23:40:45
Done.
|
| + 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 +2970,7 @@ SequenceNode* Parser::ParseFunc(const Function& func, |
| intptr_t saved_try_index = last_used_try_index_; |
| last_used_try_index_ = 0; |
| + intptr_t saved_pos = TokenPos(); |
|
hausner
2014/07/11 20:18:40
Nit: please name the variable after what it points
Michael Lippautz (Google)
2014/07/11 23:40:45
Done.
|
| // TODO(12455) : Need better validation mechanism. |
| if (func.IsConstructor()) { |
| @@ -2925,12 +3005,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 +3063,11 @@ SequenceNode* Parser::ParseFunc(const Function& func, |
| } |
| } |
| + intptr_t async_type = ParseAsyncSpecifier(); |
| + if (async_type == 1) { |
| + func.set_modifier(RawFunction::kAsync); |
| + } |
| + |
| OpenBlock(); // Open a nested scope for the outermost function block. |
| intptr_t end_token_pos = 0; |
| if (CurrentToken() == Token::kLBRACE) { |
| @@ -3032,6 +3129,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(body, ¶ms, saved_pos); |
| + } |
| current_block_->statements->Add(body); |
| innermost_function_ = saved_innermost_function.raw(); |
| last_used_try_index_ = saved_try_index; |
| @@ -3345,6 +3445,8 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { |
| method->name->ToCString()); |
| } |
| + ParseAsyncSpecifier(); |
| + |
| intptr_t method_end_pos = TokenPos(); |
| if ((CurrentToken() == Token::kLBRACE) || |
| (CurrentToken() == Token::kARROW)) { |
| @@ -4779,6 +4881,22 @@ void Parser::ParseTopLevelVariable(TopLevel* top_level, |
| } |
| +intptr_t Parser::ParseAsyncSpecifier() { |
|
hausner
2014/07/11 20:18:41
What does the integer return value mean. Should pr
Michael Lippautz (Google)
2014/07/11 23:40:45
Return value is now RawFunction::Modifier. This ca
|
| + if (FLAG_enable_async) { |
| + if (IsLiteral("async")) { |
| + const Class& future = Class::Handle(library_.LookupClass( |
| + String::Handle(String::New("Future")))); |
| + if (future.IsNull()) { |
| + ReportError("async modifier requires dart:async to be imported"); |
|
hausner
2014/07/11 20:18:41
I think we need to have a discussion with Gilad wh
Michael Lippautz (Google)
2014/07/11 23:40:45
Factored out. We still bomb until we know what to
|
| + } |
| + ConsumeToken(); |
| + return 1; |
| + } |
| + } |
| + return 0; |
| +} |
| + |
| + |
| void Parser::ParseTopLevelFunction(TopLevel* top_level, |
| intptr_t metadata_pos) { |
| TRACE_PARSER("ParseTopLevelFunction"); |
| @@ -4832,6 +4950,8 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level, |
| const bool allow_explicit_default_values = true; |
| ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
| + intptr_t async_type = ParseAsyncSpecifier(); |
| + |
| intptr_t function_end_pos = function_pos; |
| bool is_native = false; |
| if (is_external) { |
| @@ -4866,6 +4986,9 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level, |
| decl_begin_pos)); |
| func.set_result_type(result_type); |
| func.set_end_token_pos(function_end_pos); |
| + if (async_type == 1) { |
| + func.set_modifier(RawFunction::kAsync); |
| + } |
| if (is_native && library_.is_dart_scheme() && library_.IsPrivate(func_name)) { |
| func.set_is_visible(false); |
| } |
| @@ -4968,6 +5091,8 @@ void Parser::ParseTopLevelAccessor(TopLevel* top_level, |
| field_name->ToCString()); |
| } |
| + intptr_t async_type = ParseAsyncSpecifier(); |
| + |
| intptr_t accessor_end_pos = accessor_pos; |
| bool is_native = false; |
| if (is_external) { |
| @@ -5003,6 +5128,9 @@ void Parser::ParseTopLevelAccessor(TopLevel* top_level, |
| decl_begin_pos)); |
| func.set_result_type(result_type); |
| func.set_end_token_pos(accessor_end_pos); |
| + if (async_type == 1) { |
| + func.set_modifier(RawFunction::kAsync); |
| + } |
| if (is_native && library_.is_dart_scheme() && |
| library_.IsPrivate(accessor_name)) { |
| func.set_is_visible(false); |
| @@ -6207,7 +6335,8 @@ bool Parser::IsFunctionDeclaration() { |
| if ((CurrentToken() == Token::kLBRACE) || |
| (CurrentToken() == Token::kARROW) || |
| (is_top_level_ && IsLiteral("native")) || |
| - is_external) { |
| + is_external || |
| + (FLAG_enable_async && IsLiteral("async"))) { |
|
hausner
2014/07/11 20:18:40
You should create a new Symbol for "async" (in sym
Michael Lippautz (Google)
2014/07/11 23:40:45
Done.
|
| SetPosition(saved_pos); |
| return true; |
| } |