Index: runtime/vm/parser.cc |
=================================================================== |
--- runtime/vm/parser.cc (revision 43515) |
+++ runtime/vm/parser.cc (working copy) |
@@ -888,8 +888,14 @@ |
} |
if (!HasReturnNode(node_sequence)) { |
- // Add implicit return node. |
- node_sequence->Add(new ReturnNode(func.end_token_pos())); |
+ // Add implicit return node. The implicit return value of synchronous |
+ // generator closures is false, to indicate that there are no more |
+ // elements in the iterable. In other cases the implicit return value |
+ // is null. |
+ AstNode* return_value = func.IsSyncGenClosure() |
+ ? new LiteralNode(func.end_token_pos(), Bool::False()) |
+ : new LiteralNode(func.end_token_pos(), Instance::ZoneHandle()); |
+ node_sequence->Add(new ReturnNode(func.end_token_pos(), return_value)); |
} |
if (parsed_function->has_expression_temp_var()) { |
node_sequence->scope()->AddVariable(parsed_function->expression_temp_var()); |
@@ -3060,38 +3066,19 @@ |
&Symbols::TypeArgumentsParameter(), |
&Type::ZoneHandle(Z, Type::DynamicType())); |
} |
+ // Expect the parameter list unless this is a getter function, or the |
+ // body closure of an async or generator getter function. |
ASSERT((CurrentToken() == Token::kLPAREN) || |
func.IsGetterFunction() || |
- func.is_async_closure()); |
+ (func.is_generated_body() && |
+ Function::Handle(func.parent_function()).IsGetterFunction())); |
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_async_closure()) { |
- // Async closures have two optional parameters: |
- // * A continuation result. |
- // * A continuation error. |
- // |
- // If the error!=null we rethrow the error at the next await. |
- const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType()); |
- ParamDesc result_param; |
- result_param.name = &Symbols::AsyncOperationParam(); |
- result_param.default_value = &Object::null_instance(); |
- result_param.type = &dynamic_type; |
- ParamDesc error_param; |
- error_param.name = &Symbols::AsyncOperationErrorParam(); |
- error_param.default_value = &Object::null_instance(); |
- error_param.type = &dynamic_type; |
- ParamDesc stack_trace_param; |
- stack_trace_param.name = &Symbols::AsyncOperationStackTraceParam(); |
- stack_trace_param.default_value = &Object::null_instance(); |
- stack_trace_param.type = &dynamic_type; |
- params.parameters->Add(result_param); |
- params.parameters->Add(error_param); |
- params.parameters->Add(stack_trace_param); |
- params.num_optional_parameters += 3; |
- params.has_optional_positional_parameters = true; |
+ } else if (func.IsAsyncClosure()) { |
+ AddAsyncClosureParameters(¶ms); |
SetupDefaultsForOptionalParams(¶ms, default_parameter_values); |
AddFormalParamsToScope(¶ms, current_block_->scope); |
ASSERT(AbstractType::Handle(Z, func.result_type()).IsResolved()); |
@@ -3099,11 +3086,24 @@ |
if (!Function::Handle(func.parent_function()).IsGetterFunction()) { |
// Parse and discard any formal parameters. They are accessed as |
// context variables. |
- ParamList parse_away; |
+ ParamList discarded_params; |
ParseFormalParameterList(allow_explicit_default_values, |
false, |
- &parse_away); |
+ &discarded_params); |
} |
+ } else if (func.IsSyncGenClosure()) { |
+ AddSyncGenClosureParameters(¶ms); |
+ SetupDefaultsForOptionalParams(¶ms, default_parameter_values); |
+ AddFormalParamsToScope(¶ms, current_block_->scope); |
+ ASSERT(AbstractType::Handle(Z, func.result_type()).IsResolved()); |
+ if (!Function::Handle(func.parent_function()).IsGetterFunction()) { |
+ // Parse and discard any formal parameters. They are accessed as |
+ // context variables. |
+ ParamList discarded_params; |
+ ParseFormalParameterList(allow_explicit_default_values, |
+ false, |
+ &discarded_params); |
+ } |
} else { |
ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
@@ -3144,24 +3144,38 @@ |
} |
} |
+ const intptr_t modifier_pos = TokenPos(); |
RawFunction::AsyncModifier func_modifier = ParseFunctionModifier(); |
- func.set_modifier(func_modifier); |
+ if (!func.is_generated_body()) { |
+ // Don't add a modifier to the closure representing the body of |
+ // the asynchronous function or generator. |
+ func.set_modifier(func_modifier); |
+ } |
OpenBlock(); // Open a nested scope for the outermost function block. |
- Function& async_closure = Function::ZoneHandle(Z); |
- if (func.IsAsyncFunction() && !func.is_async_closure()) { |
+ Function& generated_body_closure = Function::ZoneHandle(Z); |
+ if (func.IsAsyncFunction()) { |
+ ASSERT(!func.is_generated_body()); |
// The code of an async function is synthesized. Disable debugging. |
func.set_is_debuggable(false); |
- async_closure = OpenAsyncFunction(func.token_pos()); |
- } else if (func.is_async_closure()) { |
+ generated_body_closure = OpenAsyncFunction(func.token_pos()); |
+ } else if (func.IsAsyncClosure()) { |
// The closure containing the body of an async function is debuggable. |
ASSERT(func.is_debuggable()); |
OpenAsyncClosure(); |
+ } else if (func.IsSyncGenerator()) { |
+ // The code of a sync generator is synthesized. Disable debugging. |
+ func.set_is_debuggable(false); |
+ generated_body_closure = OpenSyncGeneratorFunction(func.token_pos()); |
+ } else if (func.IsSyncGenClosure()) { |
+ // The closure containing the body of a sync generator is debuggable. |
+ ASSERT(func.is_debuggable()); |
+ // Nothing special to do. |
} |
BoolScope allow_await(&this->await_is_keyword_, |
- func.IsAsyncFunction() || func.is_async_closure()); |
+ func.IsAsyncOrGenerator() || func.is_generated_body()); |
intptr_t end_token_pos = 0; |
if (CurrentToken() == Token::kLBRACE) { |
ConsumeToken(); |
@@ -3175,6 +3189,10 @@ |
end_token_pos = TokenPos(); |
ExpectToken(Token::kRBRACE); |
} else if (CurrentToken() == Token::kARROW) { |
+ if (func.IsGenerator()) { |
+ ReportError(modifier_pos, |
+ "=> style function may not be sync* or async* generator"); |
+ } |
ConsumeToken(); |
if (String::Handle(Z, func.name()).Equals( |
Symbols::EqualOperator())) { |
@@ -3221,11 +3239,16 @@ |
func.end_token_pos() == end_token_pos); |
func.set_end_token_pos(end_token_pos); |
SequenceNode* body = CloseBlock(); |
- if (func.IsAsyncFunction() && !func.is_async_closure()) { |
- body = CloseAsyncFunction(async_closure, body); |
- async_closure.set_end_token_pos(end_token_pos); |
- } else if (func.is_async_closure()) { |
+ if (func.IsAsyncFunction()) { |
+ body = CloseAsyncFunction(generated_body_closure, body); |
+ generated_body_closure.set_end_token_pos(end_token_pos); |
+ } else if (func.IsAsyncClosure()) { |
body = CloseAsyncClosure(body); |
+ } else if (func.IsSyncGenerator()) { |
+ body = CloseSyncGenFunction(generated_body_closure, body); |
+ generated_body_closure.set_end_token_pos(end_token_pos); |
+ } else if (func.IsSyncGenClosure()) { |
+ body->scope()->RecursivelyCaptureAllVariables(); |
} |
current_block_->statements->Add(body); |
innermost_function_ = saved_innermost_function.raw(); |
@@ -3544,11 +3567,12 @@ |
method->name->ToCString()); |
} |
+ const intptr_t modifier_pos = TokenPos(); |
RawFunction::AsyncModifier async_modifier = ParseFunctionModifier(); |
if ((method->IsFactoryOrConstructor() || method->IsSetter()) && |
- async_modifier != RawFunction::kNoModifier) { |
- ReportError(method->name_pos, |
- "%s '%s' may not be async", |
+ (async_modifier != RawFunction::kNoModifier)) { |
+ ReportError(modifier_pos, |
+ "%s '%s' may not be async, async* or sync*", |
(method->IsSetter()) ? "setter" : "constructor", |
method->name->ToCString()); |
} |
@@ -3583,6 +3607,11 @@ |
method_end_pos = TokenPos(); |
ExpectToken(Token::kRBRACE); |
} else { |
+ if ((async_modifier & RawFunction::kGeneratorBit) != 0) { |
+ ReportError(modifier_pos, |
+ "=> style function may not be sync* or async* generator"); |
+ } |
+ |
ConsumeToken(); |
BoolScope allow_await(&this->await_is_keyword_, |
async_modifier != RawFunction::kNoModifier); |
@@ -3646,6 +3675,12 @@ |
} |
} |
+ if (method->has_abstract && (async_modifier != RawFunction::kNoModifier)) { |
+ ReportError(modifier_pos, |
+ "abstract function '%s' may not be async, async* or sync*", |
+ method->name->ToCString()); |
+ } |
+ |
RawFunction::Kind function_kind; |
if (method->IsFactoryOrConstructor()) { |
function_kind = RawFunction::kConstructor; |
@@ -5195,7 +5230,22 @@ |
RawFunction::AsyncModifier Parser::ParseFunctionModifier() { |
if (CurrentLiteral()->raw() == Symbols::Async().raw()) { |
ConsumeToken(); |
- return RawFunction::kAsync; |
+ if (CurrentToken() == Token::kMUL) { |
+ ReportError("async* generator functions are not yet supported"); |
+ ConsumeToken(); |
+ return RawFunction::kAsyncGen; |
+ } else { |
+ return RawFunction::kAsync; |
+ } |
+ } else if ((CurrentLiteral()->raw() == Symbols::Sync().raw()) && |
+ (LookaheadToken(1) == Token::kMUL)) { |
+ const bool enableSyncStar = true; |
+ if (!enableSyncStar) { |
+ ReportError("sync* generator functions are not yet supported"); |
+ } |
+ ConsumeToken(); |
+ ConsumeToken(); |
+ return RawFunction::kSyncGen; |
} |
return RawFunction::kNoModifier; |
} |
@@ -5254,6 +5304,7 @@ |
const bool allow_explicit_default_values = true; |
ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
+ const intptr_t modifier_pos = TokenPos(); |
RawFunction::AsyncModifier func_modifier = ParseFunctionModifier(); |
intptr_t function_end_pos = function_pos; |
@@ -5266,6 +5317,10 @@ |
function_end_pos = TokenPos(); |
ExpectToken(Token::kRBRACE); |
} else if (CurrentToken() == Token::kARROW) { |
+ if ((func_modifier & RawFunction::kGeneratorBit) != 0) { |
+ ReportError(modifier_pos, |
+ "=> style function may not be sync* or async* generator"); |
+ } |
ConsumeToken(); |
BoolScope allow_await(&this->await_is_keyword_, |
func_modifier != RawFunction::kNoModifier); |
@@ -5395,7 +5450,12 @@ |
field_name->ToCString()); |
} |
+ const intptr_t modifier_pos = TokenPos(); |
RawFunction::AsyncModifier func_modifier = ParseFunctionModifier(); |
+ if (!is_getter && (func_modifier != RawFunction::kNoModifier)) { |
+ ReportError(modifier_pos, |
+ "setter function cannot be async, async* or sync*"); |
+ } |
intptr_t accessor_end_pos = accessor_pos; |
bool is_native = false; |
@@ -5915,7 +5975,7 @@ |
} |
ASSERT(try_blocks_list_ != NULL); |
- if (innermost_function().is_async_closure() || |
+ if (innermost_function().IsAsyncClosure() || |
innermost_function().IsAsyncFunction()) { |
if ((try_blocks_list_->outer_try_block() != NULL) && |
(try_blocks_list_->outer_try_block()->try_block() |
@@ -6020,15 +6080,175 @@ |
OpenBlock(); |
PushTryBlock(current_block_); |
- if (innermost_function().is_async_closure() || |
+ if (innermost_function().IsAsyncClosure() || |
innermost_function().IsAsyncFunction()) { |
SetupSavedTryContext(context_var); |
} |
} |
+void Parser::AddSyncGenClosureParameters(ParamList* params) { |
+ // Create the parameter list for the body closure of a sync generator: |
+ // 1) Implicit closure parameter; |
+ // 2) Iterator |
+ const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType()); |
+ // Add implicit closure parameter if not already present. |
+ if (params->parameters->length() == 0) { |
+ params->AddFinalParameter(0, &Symbols::ClosureParameter(), &dynamic_type); |
+ } |
+ ParamDesc iterator_param; |
+ iterator_param.name = &Symbols::IteratorParameter(); |
+ iterator_param.type = &dynamic_type; |
+ params->parameters->Add(iterator_param); |
+ params->num_fixed_parameters++; |
+} |
+ |
+ |
+RawFunction* Parser::OpenSyncGeneratorFunction(intptr_t func_pos) { |
+ Function& body = Function::Handle(Z); |
+ String& body_closure_name = String::Handle(Z); |
+ bool is_new_closure = false; |
+ |
+ AddContinuationVariables(); |
+ |
+ // Check whether a function for the body of this generator |
+ // function has already been created by a previous |
+ // compilation. |
+ const Function& found_func = Function::Handle( |
+ Z, current_class().LookupClosureFunction(func_pos)); |
+ if (!found_func.IsNull() && |
+ (found_func.token_pos() == func_pos) && |
+ (found_func.script() == innermost_function().script()) && |
+ (found_func.parent_function() == innermost_function().raw())) { |
+ ASSERT(found_func.IsSyncGenClosure()); |
+ body = found_func.raw(); |
+ body_closure_name = body.name(); |
+ } else { |
+ // Create the closure containing the body of this generator function. |
+ String& generator_name = String::Handle(Z, innermost_function().name()); |
+ body_closure_name = |
+ String::NewFormatted("<%s_sync_body>", generator_name.ToCString()); |
+ body_closure_name = Symbols::New(body_closure_name); |
+ body = Function::NewClosureFunction(body_closure_name, |
+ innermost_function(), |
+ func_pos); |
+ body.set_is_generated_body(true); |
+ body.set_result_type(AbstractType::Handle(Type::DynamicType())); |
+ is_new_closure = true; |
+ } |
+ |
+ ParamList closure_params; |
+ AddSyncGenClosureParameters(&closure_params); |
+ |
+ if (is_new_closure) { |
+ // Add the parameters to the newly created closure. |
+ AddFormalParamsToFunction(&closure_params, body); |
+ |
+ // Create and set the signature class of the closure. |
+ const String& sig = String::Handle(Z, body.Signature()); |
+ Class& sig_cls = Class::Handle(Z, library_.LookupLocalClass(sig)); |
+ if (sig_cls.IsNull()) { |
+ sig_cls = Class::NewSignatureClass(sig, body, script_, body.token_pos()); |
+ library_.AddClass(sig_cls); |
+ } |
+ body.set_signature_class(sig_cls); |
+ const Type& sig_type = Type::Handle(Z, sig_cls.SignatureType()); |
+ if (!sig_type.IsFinalized()) { |
+ ClassFinalizer::FinalizeType( |
+ sig_cls, sig_type, ClassFinalizer::kCanonicalize); |
+ } |
+ ASSERT(AbstractType::Handle(Z, body.result_type()).IsResolved()); |
+ ASSERT(body.NumParameters() == closure_params.parameters->length()); |
+ } |
+ |
+ OpenFunctionBlock(body); |
+ AddFormalParamsToScope(&closure_params, current_block_->scope); |
+ OpenBlock(); |
+ |
+ /* |
+ async_temp_scope_ = current_block_->scope; // Is this needed? |
+ */ |
+ return body.raw(); |
+} |
+ |
+SequenceNode* Parser::CloseSyncGenFunction(const Function& closure, |
+ SequenceNode* closure_body) { |
+ // The block for the closure body has already been closed. Close the |
+ // corresponding function block. |
+ CloseBlock(); |
+ |
+ closure_body->scope()->LookupVariable(Symbols::AwaitJumpVar(), false); |
+ closure_body->scope()->LookupVariable(Symbols::AwaitContextVar(), false); |
+ |
+ // :await_jump_var = -1; |
+ LocalVariable* jump_var = |
+ current_block_->scope->LookupVariable(Symbols::AwaitJumpVar(), false); |
+ LiteralNode* init_value = |
+ new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1))); |
+ current_block_->statements->Add( |
+ new(Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value)); |
+ |
+ // return new SyncIterable(body_closure); |
+ const Class& iterable_class = |
+ Class::Handle(Z, Library::LookupCoreClass(Symbols::_SyncIterable())); |
+ ASSERT(!iterable_class.IsNull()); |
+ const Function& iterable_constructor = Function::ZoneHandle(Z, |
+ iterable_class.LookupConstructorAllowPrivate( |
+ Symbols::_SyncIterableConstructor())); |
+ ASSERT(!iterable_constructor.IsNull()); |
+ |
+ const String& closure_name = String::Handle(Z, closure.name()); |
+ ASSERT(closure_name.IsSymbol()); |
+ |
+ ArgumentListNode* arguments = new(Z) ArgumentListNode(Scanner::kNoSourcePos); |
+ ClosureNode* closure_obj = new(Z) ClosureNode( |
+ Scanner::kNoSourcePos, closure, NULL, closure_body->scope()); |
+ arguments->Add(closure_obj); |
+ ConstructorCallNode* new_iterable = |
+ new(Z) ConstructorCallNode(Scanner::kNoSourcePos, |
+ TypeArguments::ZoneHandle(Z), |
+ iterable_constructor, |
+ arguments); |
+ ReturnNode* return_node = |
+ new (Z) ReturnNode(Scanner::kNoSourcePos, new_iterable); |
+ current_block_->statements->Add(return_node); |
+ return CloseBlock(); |
+} |
+ |
+ |
+void Parser::AddAsyncClosureParameters(ParamList* params) { |
+ // Async closures have two optional parameters: |
+ // * A continuation result. |
+ // * A continuation error. |
+ // * A continuation stack trace. |
+ const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType()); |
+ // Add implicit closure parameter if not yet present. |
+ if (params->parameters->length() == 0) { |
+ params->AddFinalParameter(0, &Symbols::ClosureParameter(), &dynamic_type); |
+ } |
+ ParamDesc result_param; |
+ result_param.name = &Symbols::AsyncOperationParam(); |
+ result_param.default_value = &Object::null_instance(); |
+ result_param.type = &dynamic_type; |
+ params->parameters->Add(result_param); |
+ ParamDesc error_param; |
+ error_param.name = &Symbols::AsyncOperationErrorParam(); |
+ error_param.default_value = &Object::null_instance(); |
+ error_param.type = &dynamic_type; |
+ params->parameters->Add(error_param); |
+ ParamDesc stack_trace_param; |
+ stack_trace_param.name = &Symbols::AsyncOperationStackTraceParam(); |
+ stack_trace_param.default_value = &Object::null_instance(); |
+ stack_trace_param.type = &dynamic_type; |
+ params->parameters->Add(stack_trace_param); |
+ params->has_optional_positional_parameters = true; |
+ params->num_optional_parameters += 3; |
+} |
+ |
+ |
RawFunction* Parser::OpenAsyncFunction(intptr_t async_func_pos) { |
TRACE_PARSER("OpenAsyncFunction"); |
+ AddContinuationVariables(); |
AddAsyncClosureVariables(); |
Function& closure = Function::Handle(Z); |
bool is_new_closure = false; |
@@ -6042,7 +6262,7 @@ |
(found_func.token_pos() == async_func_pos) && |
(found_func.script() == innermost_function().script()) && |
(found_func.parent_function() == innermost_function().raw())) { |
- ASSERT(found_func.is_async_closure()); |
+ ASSERT(found_func.IsAsyncClosure()); |
closure = found_func.raw(); |
} else { |
// Create the closure containing the body of this async function. |
@@ -6054,33 +6274,13 @@ |
String::Handle(Z, Symbols::New(closure_name)), |
innermost_function(), |
async_func_pos); |
- closure.set_is_async_closure(true); |
+ closure.set_is_generated_body(true); |
closure.set_result_type(AbstractType::Handle(Type::DynamicType())); |
is_new_closure = true; |
} |
// Create the parameter list for the async body closure. |
ParamList closure_params; |
- const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType()); |
- closure_params.AddFinalParameter( |
- async_func_pos, &Symbols::ClosureParameter(), &dynamic_type); |
- ParamDesc result_param; |
- result_param.name = &Symbols::AsyncOperationParam(); |
- result_param.default_value = &Object::null_instance(); |
- result_param.type = &dynamic_type; |
- closure_params.parameters->Add(result_param); |
- ParamDesc error_param; |
- error_param.name = &Symbols::AsyncOperationErrorParam(); |
- error_param.default_value = &Object::null_instance(); |
- error_param.type = &dynamic_type; |
- closure_params.parameters->Add(error_param); |
- ParamDesc stack_trace_param; |
- stack_trace_param.name = &Symbols::AsyncOperationStackTraceParam(); |
- stack_trace_param.default_value = &Object::null_instance(); |
- stack_trace_param.type = &dynamic_type; |
- closure_params.parameters->Add(stack_trace_param); |
- closure_params.has_optional_positional_parameters = true; |
- closure_params.num_optional_parameters += 3; |
- |
+ AddAsyncClosureParameters(&closure_params); |
if (is_new_closure) { |
// Add the parameters to the newly created closure. |
AddFormalParamsToFunction(&closure_params, closure); |
@@ -6110,12 +6310,10 @@ |
} |
-void Parser::AddAsyncClosureVariables() { |
- // Add to AST: |
+void Parser::AddContinuationVariables() { |
+ // Add to current block's scope: |
// var :await_jump_var; |
// var :await_ctx_var; |
- // var :async_op; |
- // var :async_completer; |
const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType()); |
LocalVariable* await_jump_var = new (Z) LocalVariable( |
Scanner::kNoSourcePos, Symbols::AwaitJumpVar(), dynamic_type); |
@@ -6127,12 +6325,20 @@ |
current_block_->scope->AddVariable(await_ctx_var); |
current_block_->scope->CaptureVariable(Symbols::AwaitContextVar()); |
await_ctx_var->set_is_captured(); |
- LocalVariable* async_op_var = new (Z) LocalVariable( |
+} |
+ |
+ |
+void Parser::AddAsyncClosureVariables() { |
+ // Add to current block's scope: |
+ // var :async_op; |
+ // var :async_completer; |
+ const Type& dynamic_type = Type::ZoneHandle(Z, Type::DynamicType()); |
+ LocalVariable* async_op_var = new(Z) LocalVariable( |
Scanner::kNoSourcePos, Symbols::AsyncOperation(), dynamic_type); |
current_block_->scope->AddVariable(async_op_var); |
current_block_->scope->CaptureVariable(Symbols::AsyncOperation()); |
async_op_var->set_is_captured(); |
- LocalVariable* async_completer = new (Z) LocalVariable( |
+ LocalVariable* async_completer = new(Z) LocalVariable( |
Scanner::kNoSourcePos, Symbols::AsyncCompleter(), dynamic_type); |
current_block_->scope->AddVariable(async_completer); |
current_block_->scope->CaptureVariable(Symbols::AsyncCompleter()); |
@@ -6214,12 +6420,12 @@ |
current_block_->statements->Add(store_completer); |
// :await_jump_var = -1; |
- LocalVariable* jump_var = current_block_->scope->LookupVariable( |
- Symbols::AwaitJumpVar(), false); |
+ LocalVariable* jump_var = |
+ current_block_->scope->LookupVariable(Symbols::AwaitJumpVar(), false); |
LiteralNode* init_value = |
- new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1))); |
+ new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1))); |
current_block_->statements->Add( |
- new (Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value)); |
+ new(Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value)); |
// Add to AST: |
// :async_op = <closure>; (containing the original body) |
@@ -6476,8 +6682,7 @@ |
"missing initialization of 'final' or 'const' variable"); |
} else { |
// Initialize variable with null. |
- AstNode* null_expr = new(Z) LiteralNode( |
- ident_pos, Instance::ZoneHandle(Z)); |
+ AstNode* null_expr = new(Z) LiteralNode(ident_pos, Instance::ZoneHandle(Z)); |
initialization = new(Z) StoreLocalNode( |
ident_pos, variable, null_expr); |
} |
@@ -6907,7 +7112,11 @@ |
// Returns true if the current token is kIDENT or a pseudo-keyword. |
bool Parser::IsIdentifier() { |
- return Token::IsIdentifier(CurrentToken()) && !IsAwaitKeyword(); |
+ return Token::IsIdentifier(CurrentToken()) && |
+ !(await_is_keyword_ && |
+ ((CurrentLiteral()->raw() == Symbols::Await().raw()) || |
+ (CurrentLiteral()->raw() == Symbols::Async().raw()) || |
+ (CurrentLiteral()->raw() == Symbols::Yield().raw()))); |
} |
@@ -7056,7 +7265,8 @@ |
(CurrentToken() == Token::kARROW) || |
(is_top_level_ && IsLiteral("native")) || |
is_external || |
- (CurrentLiteral()->raw() == Symbols::Async().raw())) { |
+ (CurrentLiteral()->raw() == Symbols::Async().raw()) || |
+ (CurrentLiteral()->raw() == Symbols::Sync().raw())) { |
SetPosition(saved_pos); |
return true; |
} |
@@ -7546,6 +7756,12 @@ |
ConsumeToken(); // for. |
ExpectToken(Token::kLPAREN); |
+ if (!innermost_function().IsAsyncFunction() && |
+ !innermost_function().IsAsyncClosure()) { |
+ ReportError(await_for_pos, |
+ "await for loop is only allowed in async function"); |
+ } |
+ |
// Parse loop variable. |
bool loop_var_is_final = (CurrentToken() == Token::kFINAL); |
if (CurrentToken() == Token::kCONST) { |
@@ -7728,7 +7944,7 @@ |
// Generate initialization of iterator variable. |
ArgumentListNode* no_args = new(Z) ArgumentListNode(collection_pos); |
AstNode* get_iterator = new(Z) InstanceGetterNode( |
- collection_pos, collection_expr, Symbols::GetIterator()); |
+ collection_pos, collection_expr, Symbols::iterator()); |
AstNode* iterator_init = |
new(Z) StoreLocalNode(collection_pos, iterator_var, get_iterator); |
current_block_->statements->Add(iterator_init); |
@@ -7979,7 +8195,7 @@ |
// In case of async closures we need to restore the saved try index of an |
// outer try block (if it exists). The current try block has already been |
// removed from the stack of try blocks. |
- if ((innermost_function().is_async_closure() || |
+ if ((innermost_function().IsAsyncClosure() || |
innermost_function().IsAsyncFunction()) && |
(try_blocks_list_ != NULL)) { |
// We need two unchain two scopes: finally clause, and the try block level. |
@@ -8139,7 +8355,7 @@ |
// In case of async closures we need to restore the saved try index of an |
// outer try block (if it exists). |
ASSERT(try_blocks_list_ != NULL); |
- if (innermost_function().is_async_closure() || |
+ if (innermost_function().IsAsyncClosure() || |
innermost_function().IsAsyncFunction()) { |
if ((try_blocks_list_->outer_try_block() != NULL) && |
(try_blocks_list_->outer_try_block()->try_block() |
@@ -8247,7 +8463,7 @@ |
// In case of async closures we need to restore the saved try index of an |
// outer try block (if it exists). |
ASSERT(try_blocks_list_ != NULL); |
- if (innermost_function().is_async_closure() || |
+ if (innermost_function().IsAsyncClosure() || |
innermost_function().IsAsyncFunction()) { |
if ((try_blocks_list_->outer_try_block() != NULL) && |
(try_blocks_list_->outer_try_block()->try_block() |
@@ -8285,15 +8501,17 @@ |
async_saved_try_ctx_name, false); |
ASSERT(async_saved_try_ctx != NULL); |
ASSERT(saved_try_context != NULL); |
- current_block_->statements->Add(new (Z) StoreLocalNode( |
- Scanner::kNoSourcePos, async_saved_try_ctx, new (Z) LoadLocalNode( |
- Scanner::kNoSourcePos, saved_try_context))); |
+ current_block_->statements->Add(new(Z) StoreLocalNode( |
+ Scanner::kNoSourcePos, |
+ async_saved_try_ctx, |
+ new(Z) LoadLocalNode(Scanner::kNoSourcePos, saved_try_context))); |
parsed_function()->set_saved_try_ctx(saved_try_context); |
parsed_function()->set_async_saved_try_ctx_name(async_saved_try_ctx_name); |
} |
-// Set up the currently relevant :saved_try_context_var on the stack: |
+// Restore the currently relevant :saved_try_context_var on the stack |
+// from the captured :async_saved_try_cts_var. |
// * Try blocks: Set the context variable for this try block. |
// * Catch/finally blocks: Set the context variable for any outer try block (if |
// existent). |
@@ -8381,7 +8599,7 @@ |
PushTryBlock(current_block_); |
ExpectToken(Token::kLBRACE); |
- if (innermost_function().is_async_closure() || |
+ if (innermost_function().IsAsyncClosure() || |
innermost_function().IsAsyncFunction()) { |
SetupSavedTryContext(context_var); |
} |
@@ -8560,18 +8778,72 @@ |
const intptr_t return_pos = TokenPos(); |
ConsumeToken(); |
if (CurrentToken() != Token::kSEMICOLON) { |
+ const intptr_t expr_pos = TokenPos(); |
if (current_function().IsConstructor() && |
(current_block_->scope->function_level() == 0)) { |
- ReportError(return_pos, |
- "return of a value not allowed in constructors"); |
+ ReportError(expr_pos, |
+ "return of a value is not allowed in constructors"); |
+ } else if (current_function().IsGenerator()) { |
+ ReportError(expr_pos, "generator functions may not return a value"); |
} |
AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL); |
statement = new(Z) ReturnNode(statement_pos, expr); |
} else { |
- statement = new(Z) ReturnNode(statement_pos); |
+ if (current_function().IsSyncGenClosure() && |
+ (current_block_->scope->function_level() == 0)) { |
+ // In a synchronous generator, return without an expression |
+ // returns false, signaling that the iterator terminates and |
+ // did not yield a value. |
+ statement = new(Z) ReturnNode(statement_pos, |
+ new(Z) LiteralNode(return_pos, Bool::False())); |
+ } else { |
+ statement = new(Z) ReturnNode(statement_pos); |
+ } |
} |
AddNodeForFinallyInlining(statement); |
ExpectSemicolon(); |
+ } else if (IsYieldKeyword()) { |
+ bool is_yield_each = false; |
+ ConsumeToken(); |
+ ASSERT(innermost_function().IsGenerator() || |
+ innermost_function().IsSyncGenClosure()); |
+ if (CurrentToken() == Token::kMUL) { |
+ is_yield_each = true; |
+ ConsumeToken(); |
+ } |
+ AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL); |
+ LocalVariable* iterator_param = |
+ LookupLocalScope(Symbols::IteratorParameter()); |
+ ASSERT(iterator_param != NULL); |
+ // Generate :iterator.current = expr; |
+ AstNode* iterator = |
+ new(Z) LoadLocalNode(Scanner::kNoSourcePos, iterator_param); |
+ AstNode* store_current = |
+ new(Z) InstanceSetterNode(Scanner::kNoSourcePos, |
+ iterator, |
+ String::ZoneHandle(Symbols::Current().raw()), |
+ expr); |
+ LetNode* yield = new(Z) LetNode(statement_pos); |
+ yield->AddNode(store_current); |
+ if (is_yield_each) { |
+ // Generate :iterator.isYieldEach = true; |
+ AstNode* set_is_yield_each = |
+ new(Z) InstanceSetterNode(Scanner::kNoSourcePos, |
+ iterator, |
+ String::ZoneHandle(Symbols::IsYieldEach().raw()), |
+ new(Z) LiteralNode(TokenPos(), Bool::True())); |
+ yield->AddNode(set_is_yield_each); |
+ } |
+ AwaitMarkerNode* await_marker = new(Z) AwaitMarkerNode(); |
+ await_marker->set_scope(current_block_->scope); |
+ yield->AddNode(await_marker); |
+ // Return true to indicate that a value has been generated. |
+ ReturnNode* return_true = new(Z) ReturnNode(statement_pos, |
+ new(Z) LiteralNode(TokenPos(), Bool::True())); |
+ return_true->set_return_type(ReturnNode::kContinuationTarget); |
+ yield->AddNode(return_true); |
+ statement = yield; |
+ ExpectSemicolon(); |
} else if (token == Token::kIF) { |
statement = ParseIfStatement(label_name); |
} else if (token == Token::kASSERT) { |
@@ -8757,6 +9029,12 @@ |
} |
+bool Parser::IsYieldKeyword() { |
+ return await_is_keyword_ && |
+ (CurrentLiteral()->raw() == Symbols::Yield().raw()); |
+} |
+ |
+ |
static bool IsIncrementOperator(Token::Kind token) { |
return token == Token::kINCR || token == Token::kDECR; |
} |
@@ -9414,6 +9692,10 @@ |
const intptr_t op_pos = TokenPos(); |
if (IsAwaitKeyword()) { |
TRACE_PARSER("ParseAwaitExpr"); |
+ if (!innermost_function().IsAsyncFunction() && |
+ !innermost_function().IsAsyncClosure()) { |
+ ReportError("await operator is only allowed in async function"); |
+ } |
ConsumeToken(); |
parsed_function()->record_await(); |
expr = new (Z) AwaitNode(op_pos, ParseUnaryExpr()); |