OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/parser.h" | 5 #include "vm/parser.h" |
6 | 6 |
7 #include "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
8 #include "platform/utils.h" | 8 #include "platform/utils.h" |
| 9 #include "vm/ast_transformer.h" |
9 #include "vm/bootstrap.h" | 10 #include "vm/bootstrap.h" |
10 #include "vm/class_finalizer.h" | 11 #include "vm/class_finalizer.h" |
11 #include "vm/compiler.h" | 12 #include "vm/compiler.h" |
12 #include "vm/compiler_stats.h" | 13 #include "vm/compiler_stats.h" |
13 #include "vm/dart_api_impl.h" | 14 #include "vm/dart_api_impl.h" |
14 #include "vm/dart_entry.h" | 15 #include "vm/dart_entry.h" |
15 #include "vm/flags.h" | 16 #include "vm/flags.h" |
16 #include "vm/growable_array.h" | 17 #include "vm/growable_array.h" |
17 #include "vm/handles.h" | 18 #include "vm/handles.h" |
18 #include "vm/heap.h" | 19 #include "vm/heap.h" |
(...skipping 2962 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2981 } | 2982 } |
2982 ASSERT((CurrentToken() == Token::kLPAREN) || | 2983 ASSERT((CurrentToken() == Token::kLPAREN) || |
2983 func.IsGetterFunction() || | 2984 func.IsGetterFunction() || |
2984 func.is_async_closure()); | 2985 func.is_async_closure()); |
2985 const bool allow_explicit_default_values = true; | 2986 const bool allow_explicit_default_values = true; |
2986 if (func.IsGetterFunction()) { | 2987 if (func.IsGetterFunction()) { |
2987 // Populate function scope with the formal parameters. Since in this case | 2988 // Populate function scope with the formal parameters. Since in this case |
2988 // we are compiling a getter this will at most populate the receiver. | 2989 // we are compiling a getter this will at most populate the receiver. |
2989 AddFormalParamsToScope(¶ms, current_block_->scope); | 2990 AddFormalParamsToScope(¶ms, current_block_->scope); |
2990 } else if (func.is_async_closure()) { | 2991 } else if (func.is_async_closure()) { |
| 2992 // Async closures have one optional parameter for continuation results. |
| 2993 ParamDesc result_param; |
| 2994 result_param.name = &Symbols::AsyncOperationParam(); |
| 2995 result_param.default_value = &Object::null_instance(); |
| 2996 result_param.type = &Type::ZoneHandle(I, Type::DynamicType()); |
| 2997 params.parameters->Add(result_param); |
| 2998 params.num_optional_parameters++; |
| 2999 params.has_optional_positional_parameters = true; |
| 3000 SetupDefaultsForOptionalParams(¶ms, default_parameter_values); |
2991 AddFormalParamsToScope(¶ms, current_block_->scope); | 3001 AddFormalParamsToScope(¶ms, current_block_->scope); |
2992 ASSERT(AbstractType::Handle(I, func.result_type()).IsResolved()); | 3002 ASSERT(AbstractType::Handle(I, func.result_type()).IsResolved()); |
2993 ASSERT(func.NumParameters() == params.parameters->length()); | 3003 ASSERT(func.NumParameters() == params.parameters->length()); |
2994 if (!Function::Handle(func.parent_function()).IsGetterFunction()) { | 3004 if (!Function::Handle(func.parent_function()).IsGetterFunction()) { |
2995 // Parse away any formal parameters, as they are accessed as as context | 3005 // Parse away any formal parameters, as they are accessed as as context |
2996 // variables. | 3006 // variables. |
2997 ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); | 3007 ParamList parse_away; |
| 3008 ParseFormalParameterList(allow_explicit_default_values, |
| 3009 false, |
| 3010 &parse_away); |
2998 } | 3011 } |
2999 } else { | 3012 } else { |
3000 ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); | 3013 ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
3001 | 3014 |
3002 // The number of parameters and their type are not yet set in local | 3015 // The number of parameters and their type are not yet set in local |
3003 // functions, since they are not 'top-level' parsed. | 3016 // functions, since they are not 'top-level' parsed. |
3004 if (func.IsLocalFunction()) { | 3017 if (func.IsLocalFunction()) { |
3005 AddFormalParamsToFunction(¶ms, func); | 3018 AddFormalParamsToFunction(¶ms, func); |
3006 } | 3019 } |
3007 SetupDefaultsForOptionalParams(¶ms, default_parameter_values); | 3020 SetupDefaultsForOptionalParams(¶ms, default_parameter_values); |
(...skipping 29 matching lines...) Expand all Loading... |
3037 } | 3050 } |
3038 | 3051 |
3039 RawFunction::AsyncModifier func_modifier = ParseFunctionModifier(); | 3052 RawFunction::AsyncModifier func_modifier = ParseFunctionModifier(); |
3040 func.set_modifier(func_modifier); | 3053 func.set_modifier(func_modifier); |
3041 | 3054 |
3042 OpenBlock(); // Open a nested scope for the outermost function block. | 3055 OpenBlock(); // Open a nested scope for the outermost function block. |
3043 | 3056 |
3044 Function& async_closure = Function::ZoneHandle(I); | 3057 Function& async_closure = Function::ZoneHandle(I); |
3045 if (func.IsAsyncFunction() && !func.is_async_closure()) { | 3058 if (func.IsAsyncFunction() && !func.is_async_closure()) { |
3046 async_closure = OpenAsyncFunction(formal_params_pos); | 3059 async_closure = OpenAsyncFunction(formal_params_pos); |
| 3060 } else if (func.is_async_closure()) { |
| 3061 OpenAsyncClosure(); |
3047 } | 3062 } |
3048 | 3063 |
3049 intptr_t end_token_pos = 0; | 3064 intptr_t end_token_pos = 0; |
3050 if (CurrentToken() == Token::kLBRACE) { | 3065 if (CurrentToken() == Token::kLBRACE) { |
3051 ConsumeToken(); | 3066 ConsumeToken(); |
3052 if (String::Handle(I, func.name()).Equals( | 3067 if (String::Handle(I, func.name()).Equals( |
3053 Symbols::EqualOperator())) { | 3068 Symbols::EqualOperator())) { |
3054 const Class& owner = Class::Handle(I, func.Owner()); | 3069 const Class& owner = Class::Handle(I, func.Owner()); |
3055 if (!owner.IsObjectClass()) { | 3070 if (!owner.IsObjectClass()) { |
3056 AddEqualityNullCheck(); | 3071 AddEqualityNullCheck(); |
(...skipping 2462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5519 // We are parsing a nested function while compiling the enclosing function. | 5534 // We are parsing a nested function while compiling the enclosing function. |
5520 outer_scope = | 5535 outer_scope = |
5521 new(I) LocalScope(current_block_->scope, | 5536 new(I) LocalScope(current_block_->scope, |
5522 current_block_->scope->function_level() + 1, | 5537 current_block_->scope->function_level() + 1, |
5523 0); | 5538 0); |
5524 } | 5539 } |
5525 ChainNewBlock(outer_scope); | 5540 ChainNewBlock(outer_scope); |
5526 } | 5541 } |
5527 | 5542 |
5528 | 5543 |
| 5544 void Parser::OpenAsyncClosure() { |
| 5545 TRACE_PARSER("OpenAsyncClosure"); |
| 5546 parsed_function()->set_await_temps_scope(current_block_->scope); |
| 5547 // TODO(mlippautz): Set up explicit jump table for await continuations. |
| 5548 } |
| 5549 |
| 5550 |
5529 RawFunction* Parser::OpenAsyncFunction(intptr_t formal_param_pos) { | 5551 RawFunction* Parser::OpenAsyncFunction(intptr_t formal_param_pos) { |
| 5552 TRACE_PARSER("OpenAsyncFunction"); |
5530 // Create the closure containing the old body of this function. | 5553 // Create the closure containing the old body of this function. |
5531 Class& sig_cls = Class::ZoneHandle(I); | 5554 Class& sig_cls = Class::ZoneHandle(I); |
5532 Type& sig_type = Type::ZoneHandle(I); | 5555 Type& sig_type = Type::ZoneHandle(I); |
5533 Function& closure = Function::ZoneHandle(I); | 5556 Function& closure = Function::ZoneHandle(I); |
5534 String& sig = String::ZoneHandle(I); | 5557 String& sig = String::ZoneHandle(I); |
5535 ParamList closure_params; | 5558 ParamList closure_params; |
5536 closure_params.AddFinalParameter( | 5559 closure_params.AddFinalParameter( |
5537 formal_param_pos, | 5560 formal_param_pos, |
5538 &Symbols::ClosureParameter(), | 5561 &Symbols::ClosureParameter(), |
5539 &Type::ZoneHandle(I, Type::DynamicType())); | 5562 &Type::ZoneHandle(I, Type::DynamicType())); |
| 5563 ParamDesc result_param; |
| 5564 result_param.name = &Symbols::AsyncOperationParam(); |
| 5565 result_param.default_value = &Object::null_instance(); |
| 5566 result_param.type = &Type::ZoneHandle(I, Type::DynamicType()); |
| 5567 closure_params.parameters->Add(result_param); |
| 5568 closure_params.has_optional_positional_parameters = true; |
| 5569 closure_params.num_optional_parameters++; |
5540 closure = Function::NewClosureFunction( | 5570 closure = Function::NewClosureFunction( |
5541 Symbols::AnonymousClosure(), | 5571 Symbols::AnonymousClosure(), |
5542 innermost_function(), | 5572 innermost_function(), |
5543 formal_param_pos); | 5573 formal_param_pos); |
5544 AddFormalParamsToFunction(&closure_params, closure); | 5574 AddFormalParamsToFunction(&closure_params, closure); |
5545 closure.set_is_async_closure(true); | 5575 closure.set_is_async_closure(true); |
5546 closure.set_result_type(AbstractType::Handle(Type::DynamicType())); | 5576 closure.set_result_type(AbstractType::Handle(Type::DynamicType())); |
5547 sig = closure.Signature(); | 5577 sig = closure.Signature(); |
5548 sig_cls = library_.LookupLocalClass(sig); | 5578 sig_cls = library_.LookupLocalClass(sig); |
5549 if (sig_cls.IsNull()) { | 5579 if (sig_cls.IsNull()) { |
(...skipping 23 matching lines...) Expand all Loading... |
5573 current_block_->scope->set_begin_token_pos(statements->token_pos()); | 5603 current_block_->scope->set_begin_token_pos(statements->token_pos()); |
5574 current_block_->scope->set_end_token_pos(TokenPos()); | 5604 current_block_->scope->set_end_token_pos(TokenPos()); |
5575 } | 5605 } |
5576 current_block_ = current_block_->parent; | 5606 current_block_ = current_block_->parent; |
5577 return statements; | 5607 return statements; |
5578 } | 5608 } |
5579 | 5609 |
5580 | 5610 |
5581 SequenceNode* Parser::CloseAsyncFunction(const Function& closure, | 5611 SequenceNode* Parser::CloseAsyncFunction(const Function& closure, |
5582 SequenceNode* closure_body) { | 5612 SequenceNode* closure_body) { |
| 5613 TRACE_PARSER("CloseAsyncFunction"); |
5583 ASSERT(!closure.IsNull()); | 5614 ASSERT(!closure.IsNull()); |
5584 ASSERT(closure_body != NULL); | 5615 ASSERT(closure_body != NULL); |
5585 // The block for the async closure body has already been closed. Close the | 5616 // The block for the async closure body has already been closed. Close the |
5586 // corresponding function block. | 5617 // corresponding function block. |
5587 CloseBlock(); | 5618 CloseBlock(); |
5588 | 5619 |
5589 // Create and return a new future that executes a closure with the current | 5620 // Create and return a new future that executes a closure with the current |
5590 // body. | 5621 // body. |
5591 | 5622 |
5592 bool found = false; | 5623 bool found = false; |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5669 new (I) LoadLocalNode( | 5700 new (I) LoadLocalNode( |
5670 Scanner::kNoSourcePos, | 5701 Scanner::kNoSourcePos, |
5671 async_completer), | 5702 async_completer), |
5672 Symbols::CompleterFuture())); | 5703 Symbols::CompleterFuture())); |
5673 current_block_->statements->Add(return_node); | 5704 current_block_->statements->Add(return_node); |
5674 return CloseBlock(); | 5705 return CloseBlock(); |
5675 } | 5706 } |
5676 | 5707 |
5677 | 5708 |
5678 void Parser::CloseAsyncClosure(SequenceNode* body) { | 5709 void Parser::CloseAsyncClosure(SequenceNode* body) { |
| 5710 TRACE_PARSER("CloseAsyncClosure"); |
5679 // We need a temporary expression to store intermediate return values. | 5711 // We need a temporary expression to store intermediate return values. |
5680 parsed_function()->EnsureExpressionTemp(); | 5712 parsed_function()->EnsureExpressionTemp(); |
5681 } | 5713 } |
5682 | 5714 |
5683 | 5715 |
5684 // Set up default values for all optional parameters to the function. | 5716 // Set up default values for all optional parameters to the function. |
5685 void Parser::SetupDefaultsForOptionalParams(const ParamList* params, | 5717 void Parser::SetupDefaultsForOptionalParams(const ParamList* params, |
5686 Array* default_values) { | 5718 Array* default_values) { |
5687 if (params->num_optional_parameters > 0) { | 5719 if (params->num_optional_parameters > 0) { |
5688 // Build array of default parameter values. | 5720 // Build array of default parameter values. |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5871 const intptr_t ident_pos = TokenPos(); | 5903 const intptr_t ident_pos = TokenPos(); |
5872 const String& ident = *CurrentLiteral(); | 5904 const String& ident = *CurrentLiteral(); |
5873 LocalVariable* variable = new(I) LocalVariable( | 5905 LocalVariable* variable = new(I) LocalVariable( |
5874 ident_pos, ident, type); | 5906 ident_pos, ident, type); |
5875 ConsumeToken(); // Variable identifier. | 5907 ConsumeToken(); // Variable identifier. |
5876 AstNode* initialization = NULL; | 5908 AstNode* initialization = NULL; |
5877 if (CurrentToken() == Token::kASSIGN) { | 5909 if (CurrentToken() == Token::kASSIGN) { |
5878 // Variable initialization. | 5910 // Variable initialization. |
5879 const intptr_t assign_pos = TokenPos(); | 5911 const intptr_t assign_pos = TokenPos(); |
5880 ConsumeToken(); | 5912 ConsumeToken(); |
5881 AstNode* expr = ParseExpr(is_const, kConsumeCascades); | 5913 AstNode* expr = ParseAwaitableExpr(is_const, kConsumeCascades); |
5882 initialization = new(I) StoreLocalNode( | 5914 initialization = new(I) StoreLocalNode( |
5883 assign_pos, variable, expr); | 5915 assign_pos, variable, expr); |
5884 if (is_const) { | 5916 if (is_const) { |
5885 ASSERT(expr->IsLiteralNode()); | 5917 ASSERT(expr->IsLiteralNode()); |
5886 variable->SetConstValue(expr->AsLiteralNode()->literal()); | 5918 variable->SetConstValue(expr->AsLiteralNode()->literal()); |
5887 } | 5919 } |
5888 } else if (is_final || is_const) { | 5920 } else if (is_final || is_const) { |
5889 ReportError(ident_pos, | 5921 ReportError(ident_pos, |
5890 "missing initialization of 'final' or 'const' variable"); | 5922 "missing initialization of 'final' or 'const' variable"); |
5891 } else { | 5923 } else { |
(...skipping 1852 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7744 scope->LocalLookupVariable(Symbols::ExceptionVar()); | 7776 scope->LocalLookupVariable(Symbols::ExceptionVar()); |
7745 ASSERT(excp_var != NULL); | 7777 ASSERT(excp_var != NULL); |
7746 LocalVariable* trace_var = | 7778 LocalVariable* trace_var = |
7747 scope->LocalLookupVariable(Symbols::StackTraceVar()); | 7779 scope->LocalLookupVariable(Symbols::StackTraceVar()); |
7748 ASSERT(trace_var != NULL); | 7780 ASSERT(trace_var != NULL); |
7749 statement = new(I) ThrowNode( | 7781 statement = new(I) ThrowNode( |
7750 statement_pos, | 7782 statement_pos, |
7751 new(I) LoadLocalNode(statement_pos, excp_var), | 7783 new(I) LoadLocalNode(statement_pos, excp_var), |
7752 new(I) LoadLocalNode(statement_pos, trace_var)); | 7784 new(I) LoadLocalNode(statement_pos, trace_var)); |
7753 } else { | 7785 } else { |
7754 statement = ParseExpr(kAllowConst, kConsumeCascades); | 7786 statement = ParseAwaitableExpr(kAllowConst, kConsumeCascades); |
7755 ExpectSemicolon(); | 7787 ExpectSemicolon(); |
7756 } | 7788 } |
7757 return statement; | 7789 return statement; |
7758 } | 7790 } |
7759 | 7791 |
7760 | 7792 |
7761 void Parser::ReportError(const Error& error) { | 7793 void Parser::ReportError(const Error& error) { |
7762 Report::LongJump(error); | 7794 Report::LongJump(error); |
7763 UNREACHABLE(); | 7795 UNREACHABLE(); |
7764 } | 7796 } |
(...skipping 635 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8400 ASSERT(field.value() != Object::sentinel().raw()); | 8432 ASSERT(field.value() != Object::sentinel().raw()); |
8401 ASSERT(field.value() != Object::transition_sentinel().raw()); | 8433 ASSERT(field.value() != Object::transition_sentinel().raw()); |
8402 return new(iso) LiteralNode(expr->token_pos(), | 8434 return new(iso) LiteralNode(expr->token_pos(), |
8403 Instance::ZoneHandle(iso, field.value())); | 8435 Instance::ZoneHandle(iso, field.value())); |
8404 } | 8436 } |
8405 } | 8437 } |
8406 return expr; | 8438 return expr; |
8407 } | 8439 } |
8408 | 8440 |
8409 | 8441 |
| 8442 AstNode* Parser::ParseAwaitableExpr(bool require_compiletime_const, |
| 8443 bool consume_cascades) { |
| 8444 TRACE_PARSER("ParseAwaitableExpr"); |
| 8445 parsed_function()->reset_have_seen_await(); |
| 8446 AstNode* expr = ParseExpr(require_compiletime_const, consume_cascades); |
| 8447 if (parsed_function()->have_seen_await()) { |
| 8448 if (!current_block_->scope->LookupVariable( |
| 8449 Symbols::AsyncOperation(), true)) { |
| 8450 // Async operations are always encapsulated into a local function. We only |
| 8451 // need to transform the expression when generating code for this inner |
| 8452 // function. |
| 8453 return expr; |
| 8454 } |
| 8455 SequenceNode* intermediates_block = new(I) SequenceNode( |
| 8456 Scanner::kNoSourcePos, current_block_->scope); |
| 8457 AwaitTransformer at(intermediates_block, library_, parsed_function()); |
| 8458 AstNode* result = at.Transform(expr); |
| 8459 current_block_->statements->Add(intermediates_block); |
| 8460 parsed_function()->reset_have_seen_await(); |
| 8461 return result; |
| 8462 } |
| 8463 return expr; |
| 8464 } |
| 8465 |
| 8466 |
8410 AstNode* Parser::ParseExpr(bool require_compiletime_const, | 8467 AstNode* Parser::ParseExpr(bool require_compiletime_const, |
8411 bool consume_cascades) { | 8468 bool consume_cascades) { |
8412 TRACE_PARSER("ParseExpr"); | 8469 TRACE_PARSER("ParseExpr"); |
8413 String* expr_ident = | 8470 String* expr_ident = |
8414 Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL; | 8471 Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL; |
8415 const intptr_t expr_pos = TokenPos(); | 8472 const intptr_t expr_pos = TokenPos(); |
8416 | 8473 |
8417 if (CurrentToken() == Token::kTHROW) { | 8474 if (CurrentToken() == Token::kTHROW) { |
8418 ConsumeToken(); | 8475 ConsumeToken(); |
8419 if (CurrentToken() == Token::kSEMICOLON) { | 8476 if (CurrentToken() == Token::kSEMICOLON) { |
(...skipping 2348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10768 TRACE_PARSER("ParsePrimary"); | 10825 TRACE_PARSER("ParsePrimary"); |
10769 ASSERT(!is_top_level_); | 10826 ASSERT(!is_top_level_); |
10770 AstNode* primary = NULL; | 10827 AstNode* primary = NULL; |
10771 const Token::Kind token = CurrentToken(); | 10828 const Token::Kind token = CurrentToken(); |
10772 if (IsFunctionLiteral()) { | 10829 if (IsFunctionLiteral()) { |
10773 // The name of a literal function is visible from inside the function, but | 10830 // The name of a literal function is visible from inside the function, but |
10774 // must not collide with names in the scope declaring the literal. | 10831 // must not collide with names in the scope declaring the literal. |
10775 OpenBlock(); | 10832 OpenBlock(); |
10776 primary = ParseFunctionStatement(true); | 10833 primary = ParseFunctionStatement(true); |
10777 CloseBlock(); | 10834 CloseBlock(); |
| 10835 } else if (IsLiteral("await") && |
| 10836 (parsed_function()->function().IsAsyncFunction() || |
| 10837 parsed_function()->function().is_async_closure())) { |
| 10838 // The body of an async function is parsed multiple times. The first time |
| 10839 // when setting up an AsyncFunction() for generating relevant scope |
| 10840 // information. The second time the body is parsed for actually generating |
| 10841 // code. |
| 10842 TRACE_PARSER("ParseAwaitExpr"); |
| 10843 ConsumeToken(); |
| 10844 parsed_function()->record_await(); |
| 10845 primary = new(I) AwaitNode( |
| 10846 TokenPos(), ParseExpr(kAllowConst, kConsumeCascades)); |
10778 } else if (IsIdentifier()) { | 10847 } else if (IsIdentifier()) { |
10779 intptr_t qual_ident_pos = TokenPos(); | 10848 intptr_t qual_ident_pos = TokenPos(); |
10780 const LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(I, ParsePrefix()); | 10849 const LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(I, ParsePrefix()); |
10781 String& ident = *CurrentLiteral(); | 10850 String& ident = *CurrentLiteral(); |
10782 ConsumeToken(); | 10851 ConsumeToken(); |
10783 if (prefix.IsNull()) { | 10852 if (prefix.IsNull()) { |
10784 if (!ResolveIdentInLocalScope(qual_ident_pos, ident, &primary)) { | 10853 if (!ResolveIdentInLocalScope(qual_ident_pos, ident, &primary)) { |
10785 // Check whether the identifier is a type parameter. | 10854 // Check whether the identifier is a type parameter. |
10786 if (!current_class().IsNull()) { | 10855 if (!current_class().IsNull()) { |
10787 TypeParameter& type_param = TypeParameter::ZoneHandle(I, | 10856 TypeParameter& type_param = TypeParameter::ZoneHandle(I, |
(...skipping 520 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11308 void Parser::SkipQualIdent() { | 11377 void Parser::SkipQualIdent() { |
11309 ASSERT(IsIdentifier()); | 11378 ASSERT(IsIdentifier()); |
11310 ConsumeToken(); | 11379 ConsumeToken(); |
11311 if (CurrentToken() == Token::kPERIOD) { | 11380 if (CurrentToken() == Token::kPERIOD) { |
11312 ConsumeToken(); // Consume the kPERIOD token. | 11381 ConsumeToken(); // Consume the kPERIOD token. |
11313 ExpectIdentifier("identifier expected after '.'"); | 11382 ExpectIdentifier("identifier expected after '.'"); |
11314 } | 11383 } |
11315 } | 11384 } |
11316 | 11385 |
11317 } // namespace dart | 11386 } // namespace dart |
OLD | NEW |