Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(513)

Side by Side Diff: runtime/vm/parser.cc

Issue 10809089: Make sure the "Skip*" functions know about cascades as well. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/parser.h ('k') | tests/language/language.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "vm/bigint_operations.h" 7 #include "vm/bigint_operations.h"
8 #include "vm/class_finalizer.h" 8 #include "vm/class_finalizer.h"
9 #include "vm/compiler.h" 9 #include "vm/compiler.h"
10 #include "vm/compiler_stats.h" 10 #include "vm/compiler_stats.h"
(...skipping 6246 matching lines...) Expand 10 before | Expand all | Expand 10 after
6257 new LoadLocalNode(cascade_pos, *cascade_receiver_var); 6257 new LoadLocalNode(cascade_pos, *cascade_receiver_var);
6258 if (Token::IsIdentifier(LookaheadToken(1))) { 6258 if (Token::IsIdentifier(LookaheadToken(1))) {
6259 // Replace .. with . for ParseSelectors(). 6259 // Replace .. with . for ParseSelectors().
6260 token_kind_ = Token::kPERIOD; 6260 token_kind_ = Token::kPERIOD;
6261 } else if (LookaheadToken(1) == Token::kLBRACK) { 6261 } else if (LookaheadToken(1) == Token::kLBRACK) {
6262 ConsumeToken(); 6262 ConsumeToken();
6263 } else { 6263 } else {
6264 ErrorMsg("identifier or [ expected after .."); 6264 ErrorMsg("identifier or [ expected after ..");
6265 } 6265 }
6266 expr = ParseSelectors(load_cascade_receiver, true); 6266 expr = ParseSelectors(load_cascade_receiver, true);
6267
6268 // Assignments after a cascade are part of the cascade. The
6269 // assigned expression must not contain cascades.
6270 if (Token::IsAssignmentOperator(CurrentToken())) {
6271 Token::Kind assignment_op = CurrentToken();
6272 const intptr_t assignment_pos = TokenPos();
6273 ConsumeToken();
6274 AstNode* right_expr = ParseExpr(kAllowConst, kNoCascades);
6275 AstNode* left_expr = expr;
6276 if (assignment_op != Token::kASSIGN) {
6277 // Compound assignment: store inputs with side effects into
6278 // temporary locals.
6279 left_expr = PrepareCompoundAssignmentNodes(&expr);
6280 }
6281 right_expr =
6282 ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr);
6283 AstNode* assign_expr = CreateAssignmentNode(left_expr, right_expr);
6284 if (assign_expr == NULL) {
6285 ErrorMsg(assignment_pos,
6286 "left hand side of '%s' is not assignable",
6287 Token::Str(assignment_op));
6288 }
6289 expr = assign_expr;
6290 }
6267 current_block_->statements->Add(expr); 6291 current_block_->statements->Add(expr);
6268 } 6292 }
6269 // Result of the cascade is the receiver. 6293 // Result of the cascade is the receiver.
6270 return new LoadLocalNode(cascade_pos, *cascade_receiver_var); 6294 return new LoadLocalNode(cascade_pos, *cascade_receiver_var);
6271 } 6295 }
6272 6296
6273 6297
6274 AstNode* Parser::ParseExpr(bool require_compiletime_const, 6298 AstNode* Parser::ParseExpr(bool require_compiletime_const,
6275 bool consume_cascades) { 6299 bool consume_cascades) {
6276 TRACE_PARSER("ParseExpr"); 6300 TRACE_PARSER("ParseExpr");
6277 const intptr_t expr_pos = TokenPos(); 6301 const intptr_t expr_pos = TokenPos();
6278 AstNode* expr = ParseConditionalExpr(); 6302 AstNode* expr = ParseConditionalExpr();
6279 if (!Token::IsAssignmentOperator(CurrentToken())) { 6303 if (!Token::IsAssignmentOperator(CurrentToken())) {
6280 if ((CurrentToken() == Token::kCASCADE) && consume_cascades) { 6304 if ((CurrentToken() == Token::kCASCADE) && consume_cascades) {
6281 return ParseCascades(expr); 6305 return ParseCascades(expr);
6282 } 6306 }
6283 if (require_compiletime_const) { 6307 if (require_compiletime_const) {
6284 expr = FoldConstExpr(expr_pos, expr); 6308 expr = FoldConstExpr(expr_pos, expr);
6285 } 6309 }
6286 return expr; 6310 return expr;
6287 } 6311 }
6288 // Assignment expressions. 6312 // Assignment expressions.
6289 Token::Kind assignment_op = CurrentToken(); 6313 Token::Kind assignment_op = CurrentToken();
6290 const intptr_t assignment_pos = TokenPos(); 6314 const intptr_t assignment_pos = TokenPos();
6291 ConsumeToken(); 6315 ConsumeToken();
6292 const intptr_t right_expr_pos = TokenPos(); 6316 const intptr_t right_expr_pos = TokenPos();
6293 if (require_compiletime_const && (assignment_op != Token::kASSIGN)) { 6317 if (require_compiletime_const && (assignment_op != Token::kASSIGN)) {
6294 ErrorMsg(right_expr_pos, "expression must be a compile time constant"); 6318 ErrorMsg(right_expr_pos, "expression must be a compile time constant");
6295 } 6319 }
6296 AstNode* right_expr = ParseExpr(require_compiletime_const, kConsumeCascades); 6320 AstNode* right_expr = ParseExpr(require_compiletime_const, consume_cascades);
6297 AstNode* left_expr = expr; 6321 AstNode* left_expr = expr;
6298 if (assignment_op != Token::kASSIGN) { 6322 if (assignment_op != Token::kASSIGN) {
6299 // Compound assignment: store inputs with side effects into temp. locals. 6323 // Compound assignment: store inputs with side effects into temp. locals.
6300 left_expr = PrepareCompoundAssignmentNodes(&expr); 6324 left_expr = PrepareCompoundAssignmentNodes(&expr);
6301 } 6325 }
6302 right_expr = 6326 right_expr =
6303 ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr); 6327 ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr);
6304 AstNode* assign_expr = CreateAssignmentNode(left_expr, right_expr); 6328 AstNode* assign_expr = CreateAssignmentNode(left_expr, right_expr);
6305 if (assign_expr == NULL) { 6329 if (assign_expr == NULL) {
6306 ErrorMsg(assignment_pos, 6330 ErrorMsg(assignment_pos,
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
6510 AstNode* Parser::ParseClosureCall(AstNode* closure) { 6534 AstNode* Parser::ParseClosureCall(AstNode* closure) {
6511 TRACE_PARSER("ParseClosureCall"); 6535 TRACE_PARSER("ParseClosureCall");
6512 const intptr_t call_pos = TokenPos(); 6536 const intptr_t call_pos = TokenPos();
6513 ASSERT(CurrentToken() == Token::kLPAREN); 6537 ASSERT(CurrentToken() == Token::kLPAREN);
6514 EnsureExpressionTemp(); 6538 EnsureExpressionTemp();
6515 ArgumentListNode* arguments = ParseActualParameters(NULL, kAllowConst); 6539 ArgumentListNode* arguments = ParseActualParameters(NULL, kAllowConst);
6516 return new ClosureCallNode(call_pos, closure, arguments); 6540 return new ClosureCallNode(call_pos, closure, arguments);
6517 } 6541 }
6518 6542
6519 6543
6520 AstNode* Parser::ParseInstanceFieldAccess(AstNode* receiver,
6521 const String& field_name,
6522 bool consume_cascades) {
6523 TRACE_PARSER("ParseInstanceFieldAccess");
6524 AstNode* access = NULL;
6525 const intptr_t call_pos = TokenPos();
6526 if (Token::IsAssignmentOperator(CurrentToken())) {
6527 Token::Kind assignment_op = CurrentToken();
6528 ConsumeToken();
6529 AstNode* value = ParseExpr(kAllowConst, consume_cascades);
6530 AstNode* load_access =
6531 new InstanceGetterNode(call_pos, receiver, field_name);
6532 AstNode* left_load_access = load_access;
6533 if (assignment_op != Token::kASSIGN) {
6534 // Compound assignment: store inputs with side effects into temp. locals.
6535 left_load_access = PrepareCompoundAssignmentNodes(&load_access);
6536 }
6537 value = ExpandAssignableOp(call_pos, assignment_op, load_access, value);
6538 access = CreateAssignmentNode(left_load_access, value);
6539 } else {
6540 access = CallGetter(call_pos, receiver, field_name);
6541 }
6542 return access;
6543 }
6544
6545
6546 AstNode* Parser::GenerateStaticFieldLookup(const Field& field, 6544 AstNode* Parser::GenerateStaticFieldLookup(const Field& field,
6547 intptr_t ident_pos) { 6545 intptr_t ident_pos) {
6548 // If the static field has an initializer, initialize the field at compile 6546 // If the static field has an initializer, initialize the field at compile
6549 // time, which is only possible if the field is const. 6547 // time, which is only possible if the field is const.
6550 AstNode* initializing_getter = RunStaticFieldInitializer(field); 6548 AstNode* initializing_getter = RunStaticFieldInitializer(field);
6551 if (initializing_getter != NULL) { 6549 if (initializing_getter != NULL) {
6552 // The field is not yet initialized and could not be initialized at compile 6550 // The field is not yet initialized and could not be initialized at compile
6553 // time. The getter will initialize the field. 6551 // time. The getter will initialize the field.
6554 return initializing_getter; 6552 return initializing_getter;
6555 } 6553 }
(...skipping 11 matching lines...) Expand all
6567 AstNode* Parser::ParseStaticFieldAccess(const Class& cls, 6565 AstNode* Parser::ParseStaticFieldAccess(const Class& cls,
6568 const String& field_name, 6566 const String& field_name,
6569 intptr_t ident_pos, 6567 intptr_t ident_pos,
6570 bool consume_cascades) { 6568 bool consume_cascades) {
6571 TRACE_PARSER("ParseStaticFieldAccess"); 6569 TRACE_PARSER("ParseStaticFieldAccess");
6572 AstNode* access = NULL; 6570 AstNode* access = NULL;
6573 const intptr_t call_pos = TokenPos(); 6571 const intptr_t call_pos = TokenPos();
6574 const Field& field = Field::ZoneHandle(cls.LookupStaticField(field_name)); 6572 const Field& field = Field::ZoneHandle(cls.LookupStaticField(field_name));
6575 Function& func = Function::ZoneHandle(); 6573 Function& func = Function::ZoneHandle();
6576 if (Token::IsAssignmentOperator(CurrentToken())) { 6574 if (Token::IsAssignmentOperator(CurrentToken())) {
6577 Token::Kind assignment_op = CurrentToken(); 6575 // Make sure an assignment is legal.
6578 if (field.IsNull()) { 6576 if (field.IsNull()) {
6579 // No field, check if we have an explicit setter function. 6577 // No field, check if we have an explicit setter function.
6580 const String& setter_name = 6578 const String& setter_name =
6581 String::ZoneHandle(Field::SetterName(field_name)); 6579 String::ZoneHandle(Field::SetterName(field_name));
6582 const int kNumArguments = 1; // value. 6580 const int kNumArguments = 1; // value.
6583 const Array& kNoArgumentNames = Array::Handle(); 6581 const Array& kNoArgumentNames = Array::Handle();
6584 func = Resolver::ResolveStatic(cls, 6582 func = Resolver::ResolveStatic(cls,
6585 setter_name, 6583 setter_name,
6586 kNumArguments, 6584 kNumArguments,
6587 kNoArgumentNames, 6585 kNoArgumentNames,
6588 Resolver::kIsQualified); 6586 Resolver::kIsQualified);
6589 if (func.IsNull()) { 6587 if (func.IsNull()) {
6590 // No field or explicit setter function, this is an error. 6588 // No field or explicit setter function, this is an error.
6591 ErrorMsg(ident_pos, "unknown static field '%s'", 6589 ErrorMsg(ident_pos, "unknown static field '%s'",
6592 field_name.ToCString()); 6590 field_name.ToCString());
6593 return access;
6594 } 6591 }
6595 } 6592
6596 ConsumeToken();
6597 AstNode* value = ParseExpr(kAllowConst, consume_cascades);
6598 AstNode* load_access = NULL;
6599 if (field.IsNull()) {
6600 // No field found, we must have at least a setter function defined.
6601 ASSERT(!func.IsNull());
6602 // Explicit setter function for the field found, field does not exist. 6593 // Explicit setter function for the field found, field does not exist.
6603 // Create a getter node first in case it is needed. If getter node 6594 // Create a getter node first in case it is needed. If getter node
6604 // is used as part of, e.g., "+=", and the explicit getter does not 6595 // is used as part of, e.g., "+=", and the explicit getter does not
6605 // exist, and error will be reported by the code generator. 6596 // exist, and error will be reported by the code generator.
6606 load_access = new StaticGetterNode(call_pos, 6597 access = new StaticGetterNode(call_pos,
6607 NULL, 6598 NULL,
6608 Class::ZoneHandle(cls.raw()), 6599 Class::ZoneHandle(cls.raw()),
6609 String::ZoneHandle(field_name.raw())); 6600 String::ZoneHandle(field_name.raw()));
6610 } else { 6601 } else {
6611 // Field exists. 6602 // Field exists.
6612 if (field.is_final()) { 6603 if (field.is_final()) {
6613 // Field has been marked as final, report an error as the field 6604 // Field has been marked as final, report an error as the field
6614 // is not settable. 6605 // is not settable.
6615 ErrorMsg(ident_pos, 6606 ErrorMsg(ident_pos,
6616 "field '%s' is const static, cannot assign to it", 6607 "field '%s' is const static, cannot assign to it",
6617 field_name.ToCString()); 6608 field_name.ToCString());
6618 return access;
6619 } 6609 }
6620 load_access = GenerateStaticFieldLookup(field, TokenPos()); 6610 access = GenerateStaticFieldLookup(field, TokenPos());
6621 } 6611 }
6622 value = ExpandAssignableOp(call_pos, assignment_op, load_access, value);
6623 access = CreateAssignmentNode(load_access, value);
6624 } else { // Not Token::IsAssignmentOperator(CurrentToken()). 6612 } else { // Not Token::IsAssignmentOperator(CurrentToken()).
6625 if (field.IsNull()) { 6613 if (field.IsNull()) {
6626 // No field, check if we have an explicit getter function. 6614 // No field, check if we have an explicit getter function.
6627 const String& getter_name = 6615 const String& getter_name =
6628 String::ZoneHandle(Field::GetterName(field_name)); 6616 String::ZoneHandle(Field::GetterName(field_name));
6629 const int kNumArguments = 0; // no arguments. 6617 const int kNumArguments = 0; // no arguments.
6630 const Array& kNoArgumentNames = Array::Handle(); 6618 const Array& kNoArgumentNames = Array::Handle();
6631 func = Resolver::ResolveStatic(cls, 6619 func = Resolver::ResolveStatic(cls,
6632 getter_name, 6620 getter_name,
6633 kNumArguments, 6621 kNumArguments,
6634 kNoArgumentNames, 6622 kNoArgumentNames,
6635 Resolver::kIsQualified); 6623 Resolver::kIsQualified);
6636 if (func.IsNull()) { 6624 if (func.IsNull()) {
6637 // We might be referring to an implicit closure, check to see if 6625 // We might be referring to an implicit closure, check to see if
6638 // there is a function of the same name. 6626 // there is a function of the same name.
6639 func = cls.LookupStaticFunction(field_name); 6627 func = cls.LookupStaticFunction(field_name);
6640 if (func.IsNull()) { 6628 if (func.IsNull()) {
6641 // No field or explicit getter function, this is an error. 6629 // No field or explicit getter function, this is an error.
6642 ErrorMsg(ident_pos, 6630 ErrorMsg(ident_pos,
6643 "unknown static field '%s'", field_name.ToCString()); 6631 "unknown static field '%s'", field_name.ToCString());
6644 return access;
6645 } 6632 }
6646 access = CreateImplicitClosureNode(func, call_pos, NULL); 6633 access = CreateImplicitClosureNode(func, call_pos, NULL);
6647 } else { 6634 } else {
6648 ASSERT(func.kind() != RawFunction::kConstImplicitGetter); 6635 ASSERT(func.kind() != RawFunction::kConstImplicitGetter);
6649 access = new StaticGetterNode(call_pos, 6636 access = new StaticGetterNode(call_pos,
6650 NULL, 6637 NULL,
6651 Class::ZoneHandle(cls.raw()), 6638 Class::ZoneHandle(cls.raw()),
6652 field_name); 6639 field_name);
6653 } 6640 }
6654 } else { 6641 } else {
6655 return GenerateStaticFieldLookup(field, TokenPos()); 6642 access = GenerateStaticFieldLookup(field, TokenPos());
6656 } 6643 }
6657 } 6644 }
6658 return access; 6645 return access;
6659 } 6646 }
6660 6647
6661 6648
6662 AstNode* Parser::LoadFieldIfUnresolved(AstNode* node) { 6649 AstNode* Parser::LoadFieldIfUnresolved(AstNode* node) {
6663 if (!node->IsPrimaryNode()) { 6650 if (!node->IsPrimaryNode()) {
6664 return node; 6651 return node;
6665 } 6652 }
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
6739 if (left->IsPrimaryNode()) { 6726 if (left->IsPrimaryNode()) {
6740 PrimaryNode* primary_node = left->AsPrimaryNode(); 6727 PrimaryNode* primary_node = left->AsPrimaryNode();
6741 if (primary_node->primary().IsClass()) { 6728 if (primary_node->primary().IsClass()) {
6742 // If the primary node referred to a class we are loading a 6729 // If the primary node referred to a class we are loading a
6743 // qualified static field. 6730 // qualified static field.
6744 cls ^= primary_node->primary().raw(); 6731 cls ^= primary_node->primary().raw();
6745 } 6732 }
6746 } 6733 }
6747 if (cls.IsNull()) { 6734 if (cls.IsNull()) {
6748 // Instance field access. 6735 // Instance field access.
6749 selector = ParseInstanceFieldAccess(left, *ident, !is_cascade); 6736 selector = CallGetter(ident_pos, left, *ident);
6750 } else { 6737 } else {
6751 // Static field access. 6738 // Static field access.
6752 selector = 6739 selector =
6753 ParseStaticFieldAccess(cls, *ident, ident_pos, !is_cascade); 6740 ParseStaticFieldAccess(cls, *ident, ident_pos, !is_cascade);
6754 } 6741 }
6755 } 6742 }
6756 } else if (CurrentToken() == Token::kLBRACK) { 6743 } else if (CurrentToken() == Token::kLBRACK) {
6757 const intptr_t bracket_pos = TokenPos(); 6744 const intptr_t bracket_pos = TokenPos();
6758 ConsumeToken(); 6745 ConsumeToken();
6759 left = LoadFieldIfUnresolved(left); 6746 left = LoadFieldIfUnresolved(left);
(...skipping 1865 matching lines...) Expand 10 before | Expand all | Expand 10 after
8625 ConsumeToken(); // Handle pseudo-keyword identifiers. 8612 ConsumeToken(); // Handle pseudo-keyword identifiers.
8626 } else { 8613 } else {
8627 UnexpectedToken(); 8614 UnexpectedToken();
8628 UNREACHABLE(); 8615 UNREACHABLE();
8629 } 8616 }
8630 break; 8617 break;
8631 } 8618 }
8632 } 8619 }
8633 8620
8634 8621
8635 void Parser::SkipPostfixExpr() { 8622 void Parser::SkipSelectors() {
8636 SkipPrimary();
8637 while (true) { 8623 while (true) {
8638 if (CurrentToken() == Token::kPERIOD) { 8624 if ((CurrentToken() == Token::kPERIOD) ||
8625 (CurrentToken() == Token::kCASCADE)) {
8639 ConsumeToken(); 8626 ConsumeToken();
8640 ExpectIdentifier("identifier expected"); 8627 ExpectIdentifier("identifier expected");
8641 } else if (CurrentToken() == Token::kLBRACK) { 8628 } else if (CurrentToken() == Token::kLBRACK) {
8642 ConsumeToken(); 8629 ConsumeToken();
8643 SkipNestedExpr(); 8630 SkipNestedExpr();
8644 ExpectToken(Token::kRBRACK); 8631 ExpectToken(Token::kRBRACK);
8645 } else if (CurrentToken() == Token::kLPAREN) { 8632 } else if (CurrentToken() == Token::kLPAREN) {
8646 SkipActualParameters(); 8633 SkipActualParameters();
8647 } else { 8634 } else {
8648 break; 8635 break;
8649 } 8636 }
8650 } 8637 }
8638 }
8639
8640 void Parser::SkipPostfixExpr() {
8641 SkipPrimary();
8642 SkipSelectors();
8651 if (IsIncrementOperator(CurrentToken())) { 8643 if (IsIncrementOperator(CurrentToken())) {
8652 ConsumeToken(); 8644 ConsumeToken();
8653 } 8645 }
8654 } 8646 }
8655 8647
8656 8648
8657 void Parser::SkipUnaryExpr() { 8649 void Parser::SkipUnaryExpr() {
8658 if (IsPrefixOperator(CurrentToken()) || 8650 if (IsPrefixOperator(CurrentToken()) ||
8659 IsIncrementOperator(CurrentToken())) { 8651 IsIncrementOperator(CurrentToken())) {
8660 ConsumeToken(); 8652 ConsumeToken();
(...skipping 20 matching lines...) Expand all
8681 ConsumeToken(); 8673 ConsumeToken();
8682 SkipExpr(); 8674 SkipExpr();
8683 ExpectToken(Token::kCOLON); 8675 ExpectToken(Token::kCOLON);
8684 SkipExpr(); 8676 SkipExpr();
8685 } 8677 }
8686 } 8678 }
8687 8679
8688 8680
8689 void Parser::SkipExpr() { 8681 void Parser::SkipExpr() {
8690 SkipConditionalExpr(); 8682 SkipConditionalExpr();
8683 if (CurrentToken() == Token::kCASCADE) {
8684 SkipSelectors();
8685 }
8691 if (Token::IsAssignmentOperator(CurrentToken())) { 8686 if (Token::IsAssignmentOperator(CurrentToken())) {
8692 ConsumeToken(); 8687 ConsumeToken();
8693 SkipExpr(); 8688 SkipExpr();
8694 } 8689 }
8695 } 8690 }
8696 8691
8697 8692
8698 void Parser::SkipNestedExpr() { 8693 void Parser::SkipNestedExpr() {
8699 const bool saved_mode = SetAllowFunctionLiterals(true); 8694 const bool saved_mode = SetAllowFunctionLiterals(true);
8700 SkipExpr(); 8695 SkipExpr();
8701 SetAllowFunctionLiterals(saved_mode); 8696 SetAllowFunctionLiterals(saved_mode);
8702 } 8697 }
8703 8698
8704 8699
8705 void Parser::SkipQualIdent() { 8700 void Parser::SkipQualIdent() {
8706 ASSERT(IsIdentifier()); 8701 ASSERT(IsIdentifier());
8707 ConsumeToken(); 8702 ConsumeToken();
8708 if (CurrentToken() == Token::kPERIOD) { 8703 if (CurrentToken() == Token::kPERIOD) {
8709 ConsumeToken(); // Consume the kPERIOD token. 8704 ConsumeToken(); // Consume the kPERIOD token.
8710 ExpectIdentifier("identifier expected after '.'"); 8705 ExpectIdentifier("identifier expected after '.'");
8711 } 8706 }
8712 } 8707 }
8713 8708
8714 } // namespace dart 8709 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/parser.h ('k') | tests/language/language.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698