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 library dart_parser; | 5 library dart_parser; |
6 | 6 |
7 import 'package:dart_scanner/src/keyword.dart' show | 7 import 'package:dart_scanner/src/keyword.dart' show |
8 Keyword; | 8 Keyword; |
9 | 9 |
10 import 'package:dart_scanner/src/precedence.dart' show | 10 import 'package:dart_scanner/src/precedence.dart' show |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 * [parseMetadataStar] corresponds to this grammar snippet: [: | 108 * [parseMetadataStar] corresponds to this grammar snippet: [: |
109 * metadata* :], and [parseTypeOpt] corresponds to: [: type? :]. | 109 * metadata* :], and [parseTypeOpt] corresponds to: [: type? :]. |
110 */ | 110 */ |
111 class Parser { | 111 class Parser { |
112 final Listener listener; | 112 final Listener listener; |
113 | 113 |
114 bool mayParseFunctionExpressions = true; | 114 bool mayParseFunctionExpressions = true; |
115 | 115 |
116 bool asyncAwaitKeywordsEnabled; | 116 bool asyncAwaitKeywordsEnabled; |
117 | 117 |
118 final bool enableGenericMethodSyntax; | 118 Parser(this.listener, {this.asyncAwaitKeywordsEnabled: false}); |
119 | |
120 Parser(this.listener, | |
121 {this.asyncAwaitKeywordsEnabled: false, | |
122 this.enableGenericMethodSyntax: false}); | |
123 | 119 |
124 Token parseUnit(Token token) { | 120 Token parseUnit(Token token) { |
125 listener.beginCompilationUnit(token); | 121 listener.beginCompilationUnit(token); |
126 int count = 0; | 122 int count = 0; |
127 while (!identical(token.kind, EOF_TOKEN)) { | 123 while (!identical(token.kind, EOF_TOKEN)) { |
128 token = parseTopLevelDeclaration(token); | 124 token = parseTopLevelDeclaration(token); |
129 count++; | 125 count++; |
130 } | 126 } |
131 listener.endCompilationUnit(count, token); | 127 listener.endCompilationUnit(count, token); |
132 return token; | 128 return token; |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 period = token; | 372 period = token; |
377 token = parseIdentifier(token.next); | 373 token = parseIdentifier(token.next); |
378 } | 374 } |
379 token = parseArgumentsOpt(token); | 375 token = parseArgumentsOpt(token); |
380 listener.endMetadata(atToken, period, token); | 376 listener.endMetadata(atToken, period, token); |
381 return token; | 377 return token; |
382 } | 378 } |
383 | 379 |
384 Token parseTypedef(Token token) { | 380 Token parseTypedef(Token token) { |
385 Token typedefKeyword = token; | 381 Token typedefKeyword = token; |
386 if (optional('=', peekAfterType(token.next))) { | 382 listener.beginFunctionTypeAlias(token); |
387 // TODO(aprelev@gmail.com): Remove deprecated 'typedef' mixin application, | 383 token = parseReturnTypeOpt(token.next); |
388 // remove corresponding diagnostic from members.dart. | 384 token = parseIdentifier(token); |
389 listener.beginNamedMixinApplication(token); | 385 token = parseTypeVariablesOpt(token); |
390 token = parseIdentifier(token.next); | 386 token = parseFormalParameters(token); |
391 token = parseTypeVariablesOpt(token); | 387 listener.endFunctionTypeAlias(typedefKeyword, token); |
392 token = expect('=', token); | |
393 token = parseModifiers(token); | |
394 token = parseMixinApplication(token); | |
395 Token implementsKeyword = null; | |
396 if (optional('implements', token)) { | |
397 implementsKeyword = token; | |
398 token = parseTypeList(token.next); | |
399 } | |
400 listener.endNamedMixinApplication( | |
401 typedefKeyword, implementsKeyword, token); | |
402 } else { | |
403 listener.beginFunctionTypeAlias(token); | |
404 token = parseReturnTypeOpt(token.next); | |
405 token = parseIdentifier(token); | |
406 token = parseTypeVariablesOpt(token); | |
407 token = parseFormalParameters(token); | |
408 listener.endFunctionTypeAlias(typedefKeyword, token); | |
409 } | |
410 return expect(';', token); | 388 return expect(';', token); |
411 } | 389 } |
412 | 390 |
413 Token parseMixinApplication(Token token) { | 391 Token parseMixinApplication(Token token) { |
414 listener.beginMixinApplication(token); | 392 listener.beginMixinApplication(token); |
415 token = parseType(token); | 393 token = parseType(token); |
416 token = expect('with', token); | 394 token = expect('with', token); |
417 token = parseTypeList(token); | 395 token = parseTypeList(token); |
418 listener.endMixinApplication(); | 396 listener.endMixinApplication(); |
419 return token; | 397 return token; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 } | 436 } |
459 token = parseFormalParameter(token, FormalParameterType.REQUIRED); | 437 token = parseFormalParameter(token, FormalParameterType.REQUIRED); |
460 } while (optional(',', token)); | 438 } while (optional(',', token)); |
461 listener.endFormalParameters(parameterCount, begin, token); | 439 listener.endFormalParameters(parameterCount, begin, token); |
462 return expect(')', token); | 440 return expect(')', token); |
463 } | 441 } |
464 | 442 |
465 Token parseFormalParameter(Token token, FormalParameterType type) { | 443 Token parseFormalParameter(Token token, FormalParameterType type) { |
466 token = parseMetadataStar(token, forParameter: true); | 444 token = parseMetadataStar(token, forParameter: true); |
467 listener.beginFormalParameter(token); | 445 listener.beginFormalParameter(token); |
| 446 |
| 447 // Skip over `covariant` token, if the next token is an identifier or |
| 448 // modifier. |
| 449 // This enables the case where `covariant` is the name of the parameter: |
| 450 // void foo(covariant); |
| 451 if (identical(token.stringValue, 'covariant') && |
| 452 (token.next.isIdentifier() || isModifier(token.next))) { |
| 453 token = token.next; |
| 454 } |
468 token = parseModifiers(token); | 455 token = parseModifiers(token); |
469 // TODO(ahe): Validate that there are formal parameters if void. | 456 // TODO(ahe): Validate that there are formal parameters if void. |
470 token = parseReturnTypeOpt(token); | 457 token = parseReturnTypeOpt(token); |
471 Token thisKeyword = null; | 458 Token thisKeyword = null; |
472 if (optional('this', token)) { | 459 if (optional('this', token)) { |
473 thisKeyword = token; | 460 thisKeyword = token; |
474 // TODO(ahe): Validate field initializers are only used in | 461 // TODO(ahe): Validate field initializers are only used in |
475 // constructors, and not for function-typed arguments. | 462 // constructors, and not for function-typed arguments. |
476 token = expect('.', token.next); | 463 token = expect('.', token.next); |
477 } | 464 } |
478 token = parseIdentifier(token); | 465 token = parseIdentifier(token); |
479 if (optional('(', token)) { | 466 if (optional('(', token)) { |
480 listener.beginFunctionTypedFormalParameter(token); | 467 listener.beginFunctionTypedFormalParameter(token); |
481 listener.handleNoTypeVariables(token); | 468 listener.handleNoTypeVariables(token); |
482 token = parseFormalParameters(token); | 469 token = parseFormalParameters(token); |
483 listener.handleFunctionTypedFormalParameter(token); | 470 listener.handleFunctionTypedFormalParameter(token); |
484 } else if (enableGenericMethodSyntax && optional('<', token)) { | 471 } else if (optional('<', token)) { |
485 listener.beginFunctionTypedFormalParameter(token); | 472 listener.beginFunctionTypedFormalParameter(token); |
486 token = parseTypeVariablesOpt(token); | 473 token = parseTypeVariablesOpt(token); |
487 token = parseFormalParameters(token); | 474 token = parseFormalParameters(token); |
488 listener.handleFunctionTypedFormalParameter(token); | 475 listener.handleFunctionTypedFormalParameter(token); |
489 } | 476 } |
490 String value = token.stringValue; | 477 String value = token.stringValue; |
491 if ((identical('=', value)) || (identical(':', value))) { | 478 if ((identical('=', value)) || (identical(':', value))) { |
492 // TODO(ahe): Validate that these are only used for optional parameters. | 479 // TODO(ahe): Validate that these are only used for optional parameters. |
493 Token equal = token; | 480 Token equal = token; |
494 token = parseExpression(token.next); | 481 token = parseExpression(token.next); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 token = tryParseQualified(token); | 580 token = tryParseQualified(token); |
594 if (token == null) return null; | 581 if (token == null) return null; |
595 Token tokenAfterQualified = token; | 582 Token tokenAfterQualified = token; |
596 token = tryParseNestedTypeArguments(token); | 583 token = tryParseNestedTypeArguments(token); |
597 return token == null ? tokenAfterQualified : token; | 584 return token == null ? tokenAfterQualified : token; |
598 } | 585 } |
599 | 586 |
600 /// Returns token after match if [token] matches identifier ('.' identifier)?, | 587 /// Returns token after match if [token] matches identifier ('.' identifier)?, |
601 /// and otherwise returns null. Does not produce listener events. | 588 /// and otherwise returns null. Does not produce listener events. |
602 Token tryParseQualified(Token token) { | 589 Token tryParseQualified(Token token) { |
603 if (!identical(token.kind, IDENTIFIER_TOKEN)) return null; | 590 if (!isValidTypeReference(token)) return null; |
604 token = token.next; | 591 token = token.next; |
605 if (!identical(token.kind, PERIOD_TOKEN)) return token; | 592 if (!identical(token.kind, PERIOD_TOKEN)) return token; |
606 token = token.next; | 593 token = token.next; |
607 if (!identical(token.kind, IDENTIFIER_TOKEN)) return null; | 594 if (!identical(token.kind, IDENTIFIER_TOKEN)) return null; |
608 return token.next; | 595 return token.next; |
609 } | 596 } |
610 | 597 |
611 /// Returns token after match if [token] matches '<' type (',' type)* '>', | 598 /// Returns token after match if [token] matches '<' type (',' type)* '>', |
612 /// and otherwise returns null. Does not produce listener events. The final | 599 /// and otherwise returns null. Does not produce listener events. The final |
613 /// '>' may be the first character in a '>>' token, in which case a synthetic | 600 /// '>' may be the first character in a '>>' token, in which case a synthetic |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
698 Token begin = token; | 685 Token begin = token; |
699 Token abstractKeyword; | 686 Token abstractKeyword; |
700 if (optional('abstract', token)) { | 687 if (optional('abstract', token)) { |
701 abstractKeyword = token; | 688 abstractKeyword = token; |
702 token = token.next; | 689 token = token.next; |
703 } | 690 } |
704 Token classKeyword = token; | 691 Token classKeyword = token; |
705 var isMixinApplication = optional('=', peekAfterType(token.next)); | 692 var isMixinApplication = optional('=', peekAfterType(token.next)); |
706 if (isMixinApplication) { | 693 if (isMixinApplication) { |
707 listener.beginNamedMixinApplication(begin); | 694 listener.beginNamedMixinApplication(begin); |
708 token = parseIdentifier(token.next); | |
709 token = parseTypeVariablesOpt(token); | |
710 token = expect('=', token); | |
711 } else { | 695 } else { |
712 listener.beginClassDeclaration(begin); | 696 listener.beginClassDeclaration(begin); |
713 } | 697 } |
714 | 698 |
715 // TODO(aprelev@gmail.com): Once 'typedef' named mixin application is | |
716 // removed, move modifiers for named mixin application to the bottom of | |
717 // listener stack. This is so stacks for class declaration and named | |
718 // mixin application look similar. | |
719 int modifierCount = 0; | 699 int modifierCount = 0; |
720 if (abstractKeyword != null) { | 700 if (abstractKeyword != null) { |
721 parseModifier(abstractKeyword); | 701 parseModifier(abstractKeyword); |
722 modifierCount++; | 702 modifierCount++; |
723 } | 703 } |
724 listener.handleModifiers(modifierCount); | 704 listener.handleModifiers(modifierCount); |
725 | 705 |
726 if (isMixinApplication) { | 706 if (isMixinApplication) { |
| 707 token = parseIdentifier(token.next); |
| 708 token = parseTypeVariablesOpt(token); |
| 709 token = expect('=', token); |
727 return parseNamedMixinApplication(token, classKeyword); | 710 return parseNamedMixinApplication(token, classKeyword); |
728 } else { | 711 } else { |
729 return parseClass(begin, classKeyword); | 712 return parseClass(begin, classKeyword); |
730 } | 713 } |
731 } | 714 } |
732 | 715 |
733 Token parseNamedMixinApplication(Token token, Token classKeyword) { | 716 Token parseNamedMixinApplication(Token token, Token classKeyword) { |
734 token = parseMixinApplication(token); | 717 token = parseMixinApplication(token); |
735 Token implementsKeyword = null; | 718 Token implementsKeyword = null; |
736 if (optional('implements', token)) { | 719 if (optional('implements', token)) { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
792 if (!identical(string, token.stringValue)) { | 775 if (!identical(string, token.stringValue)) { |
793 return listener.expected(string, token); | 776 return listener.expected(string, token); |
794 } | 777 } |
795 return token.next; | 778 return token.next; |
796 } | 779 } |
797 | 780 |
798 Token parseTypeVariable(Token token) { | 781 Token parseTypeVariable(Token token) { |
799 listener.beginTypeVariable(token); | 782 listener.beginTypeVariable(token); |
800 token = parseIdentifier(token); | 783 token = parseIdentifier(token); |
801 Token extendsOrSuper = null; | 784 Token extendsOrSuper = null; |
802 if (optional('extends', token) || | 785 if (optional('extends', token) || optional('super', token)) { |
803 (enableGenericMethodSyntax && optional('super', token))) { | |
804 extendsOrSuper = token; | 786 extendsOrSuper = token; |
805 token = parseType(token.next); | 787 token = parseType(token.next); |
806 } else { | 788 } else { |
807 listener.handleNoType(token); | 789 listener.handleNoType(token); |
808 } | 790 } |
809 listener.endTypeVariable(token, extendsOrSuper); | 791 listener.endTypeVariable(token, extendsOrSuper); |
810 return token; | 792 return token; |
811 } | 793 } |
812 | 794 |
813 /** | 795 /** |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1020 listener.handleModifiers(modifierCount); | 1002 listener.handleModifiers(modifierCount); |
1021 var kind = hasTypeOrModifier | 1003 var kind = hasTypeOrModifier |
1022 ? ErrorKind.EXTRANEOUS_MODIFIER | 1004 ? ErrorKind.EXTRANEOUS_MODIFIER |
1023 : ErrorKind.EXTRANEOUS_MODIFIER_REPLACE; | 1005 : ErrorKind.EXTRANEOUS_MODIFIER_REPLACE; |
1024 for (Token modifier in modifierList) { | 1006 for (Token modifier in modifierList) { |
1025 listener.reportError(modifier, kind, {'modifier': modifier}); | 1007 listener.reportError(modifier, kind, {'modifier': modifier}); |
1026 } | 1008 } |
1027 return null; | 1009 return null; |
1028 } | 1010 } |
1029 | 1011 |
| 1012 /// Removes the optional `covariant` token from the modifiers, if there |
| 1013 /// is no `static` in the list, and `covariant` is the first modifier. |
| 1014 Link<Token> removeOptCovariantTokenIfNotStatic(Link<Token> modifiers) { |
| 1015 if (modifiers.isEmpty || |
| 1016 !identical(modifiers.first.stringValue, 'covariant')) { |
| 1017 return modifiers; |
| 1018 } |
| 1019 for (Token modifier in modifiers.tail) { |
| 1020 if (identical(modifier.stringValue, 'static')) { |
| 1021 return modifiers; |
| 1022 } |
| 1023 } |
| 1024 return modifiers.tail; |
| 1025 } |
| 1026 |
1030 Token parseFields(Token start, Link<Token> modifiers, Token type, | 1027 Token parseFields(Token start, Link<Token> modifiers, Token type, |
1031 Token getOrSet, Token name, bool isTopLevel) { | 1028 Token getOrSet, Token name, bool isTopLevel) { |
1032 bool hasType = type != null; | 1029 bool hasType = type != null; |
| 1030 |
| 1031 if (getOrSet == null && !isTopLevel) { |
| 1032 modifiers = removeOptCovariantTokenIfNotStatic(modifiers); |
| 1033 } |
| 1034 |
1033 Token varFinalOrConst = | 1035 Token varFinalOrConst = |
1034 expectVarFinalOrConst(modifiers, hasType, !isTopLevel); | 1036 expectVarFinalOrConst(modifiers, hasType, !isTopLevel); |
1035 bool isVar = false; | 1037 bool isVar = false; |
1036 bool hasModifier = false; | 1038 bool hasModifier = false; |
1037 if (varFinalOrConst != null) { | 1039 if (varFinalOrConst != null) { |
1038 hasModifier = true; | 1040 hasModifier = true; |
1039 isVar = optional('var', varFinalOrConst); | 1041 isVar = optional('var', varFinalOrConst); |
1040 } | 1042 } |
1041 | 1043 |
1042 if (getOrSet != null) { | 1044 if (getOrSet != null) { |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1101 listener.handleModifiers(0); | 1103 listener.handleModifiers(0); |
1102 } | 1104 } |
1103 | 1105 |
1104 if (type == null) { | 1106 if (type == null) { |
1105 listener.handleNoType(name); | 1107 listener.handleNoType(name); |
1106 } else { | 1108 } else { |
1107 parseReturnTypeOpt(type); | 1109 parseReturnTypeOpt(type); |
1108 } | 1110 } |
1109 Token token = parseIdentifier(name); | 1111 Token token = parseIdentifier(name); |
1110 | 1112 |
1111 if (enableGenericMethodSyntax && getOrSet == null) { | 1113 if (getOrSet == null) { |
1112 token = parseTypeVariablesOpt(token); | 1114 token = parseTypeVariablesOpt(token); |
1113 } else { | 1115 } else { |
1114 listener.handleNoTypeVariables(token); | 1116 listener.handleNoTypeVariables(token); |
1115 } | 1117 } |
1116 token = parseFormalParametersOpt(token); | 1118 token = parseFormalParametersOpt(token); |
1117 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1119 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
1118 token = parseAsyncModifier(token); | 1120 token = parseAsyncModifier(token); |
1119 token = parseFunctionBody(token, false, externalModifier != null); | 1121 token = parseFunctionBody(token, false, externalModifier != null); |
1120 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; | 1122 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; |
1121 Token endToken = token; | 1123 Token endToken = token; |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1386 return optional('factory', token); | 1388 return optional('factory', token); |
1387 } | 1389 } |
1388 | 1390 |
1389 Token parseMember(Token token) { | 1391 Token parseMember(Token token) { |
1390 token = parseMetadataStar(token); | 1392 token = parseMetadataStar(token); |
1391 Token start = token; | 1393 Token start = token; |
1392 listener.beginMember(token); | 1394 listener.beginMember(token); |
1393 if (isFactoryDeclaration(token)) { | 1395 if (isFactoryDeclaration(token)) { |
1394 token = parseFactoryMethod(token); | 1396 token = parseFactoryMethod(token); |
1395 listener.endMember(); | 1397 listener.endMember(); |
1396 assert (token != null); | 1398 assert(token != null); |
1397 return token; | 1399 return token; |
1398 } | 1400 } |
1399 | 1401 |
1400 Link<Token> identifiers = findMemberName(token); | 1402 Link<Token> identifiers = findMemberName(token); |
1401 if (identifiers.isEmpty) { | 1403 if (identifiers.isEmpty) { |
1402 return listener.expectedDeclaration(start); | 1404 return listener.expectedDeclaration(start); |
1403 } | 1405 } |
1404 Token afterName = identifiers.head; | 1406 Token afterName = identifiers.head; |
1405 identifiers = identifiers.tail; | 1407 identifiers = identifiers.tail; |
1406 | 1408 |
(...skipping 26 matching lines...) Expand all Loading... |
1433 token = afterName; | 1435 token = afterName; |
1434 bool isField; | 1436 bool isField; |
1435 while (true) { | 1437 while (true) { |
1436 // Loop to allow the listener to rewrite the token stream for | 1438 // Loop to allow the listener to rewrite the token stream for |
1437 // error handling. | 1439 // error handling. |
1438 final String value = token.stringValue; | 1440 final String value = token.stringValue; |
1439 if ((identical(value, '(')) || | 1441 if ((identical(value, '(')) || |
1440 (identical(value, '.')) || | 1442 (identical(value, '.')) || |
1441 (identical(value, '{')) || | 1443 (identical(value, '{')) || |
1442 (identical(value, '=>')) || | 1444 (identical(value, '=>')) || |
1443 (enableGenericMethodSyntax && identical(value, '<'))) { | 1445 (identical(value, '<'))) { |
1444 isField = false; | 1446 isField = false; |
1445 break; | 1447 break; |
1446 } else if (identical(value, ';')) { | 1448 } else if (identical(value, ';')) { |
1447 if (getOrSet != null) { | 1449 if (getOrSet != null) { |
1448 // If we found a "get" keyword, this must be an abstract | 1450 // If we found a "get" keyword, this must be an abstract |
1449 // getter. | 1451 // getter. |
1450 isField = (!identical(getOrSet.stringValue, 'get')); | 1452 isField = (!identical(getOrSet.stringValue, 'get')); |
1451 // TODO(ahe): This feels like a hack. | 1453 // TODO(ahe): This feels like a hack. |
1452 } else { | 1454 } else { |
1453 isField = true; | 1455 isField = true; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1528 token = parseOperatorName(name); | 1530 token = parseOperatorName(name); |
1529 if (staticModifier != null) { | 1531 if (staticModifier != null) { |
1530 listener.reportError(staticModifier, ErrorKind.EXTRANEOUS_MODIFIER, | 1532 listener.reportError(staticModifier, ErrorKind.EXTRANEOUS_MODIFIER, |
1531 {'modifier': staticModifier}); | 1533 {'modifier': staticModifier}); |
1532 } | 1534 } |
1533 } else { | 1535 } else { |
1534 token = parseIdentifier(name); | 1536 token = parseIdentifier(name); |
1535 } | 1537 } |
1536 | 1538 |
1537 token = parseQualifiedRestOpt(token); | 1539 token = parseQualifiedRestOpt(token); |
1538 if (enableGenericMethodSyntax && getOrSet == null) { | 1540 if (getOrSet == null) { |
1539 token = parseTypeVariablesOpt(token); | 1541 token = parseTypeVariablesOpt(token); |
1540 } else { | 1542 } else { |
1541 listener.handleNoTypeVariables(token); | 1543 listener.handleNoTypeVariables(token); |
1542 } | 1544 } |
1543 token = parseFormalParametersOpt(token); | 1545 token = parseFormalParametersOpt(token); |
1544 token = parseInitializersOpt(token); | 1546 token = parseInitializersOpt(token); |
1545 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1547 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
1546 token = parseAsyncModifier(token); | 1548 token = parseAsyncModifier(token); |
1547 if (optional('=', token)) { | 1549 if (optional('=', token)) { |
1548 token = parseRedirectingFactoryBody(token); | 1550 token = parseRedirectingFactoryBody(token); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1619 } | 1621 } |
1620 listener.beginFunctionName(token); | 1622 listener.beginFunctionName(token); |
1621 if (optional('operator', token)) { | 1623 if (optional('operator', token)) { |
1622 token = parseOperatorName(token); | 1624 token = parseOperatorName(token); |
1623 } else { | 1625 } else { |
1624 token = parseIdentifier(token); | 1626 token = parseIdentifier(token); |
1625 } | 1627 } |
1626 } | 1628 } |
1627 token = parseQualifiedRestOpt(token); | 1629 token = parseQualifiedRestOpt(token); |
1628 listener.endFunctionName(token); | 1630 listener.endFunctionName(token); |
1629 if (enableGenericMethodSyntax && getOrSet == null) { | 1631 if (getOrSet == null) { |
1630 token = parseTypeVariablesOpt(token); | 1632 token = parseTypeVariablesOpt(token); |
1631 } else { | 1633 } else { |
1632 listener.handleNoTypeVariables(token); | 1634 listener.handleNoTypeVariables(token); |
1633 } | 1635 } |
1634 token = parseFormalParametersOpt(token); | 1636 token = parseFormalParametersOpt(token); |
1635 token = parseInitializersOpt(token); | 1637 token = parseInitializersOpt(token); |
1636 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1638 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
1637 token = parseAsyncModifier(token); | 1639 token = parseAsyncModifier(token); |
1638 if (optional('=', token)) { | 1640 if (optional('=', token)) { |
1639 token = parseRedirectingFactoryBody(token); | 1641 token = parseRedirectingFactoryBody(token); |
(...skipping 24 matching lines...) Expand all Loading... |
1664 return token; | 1666 return token; |
1665 } | 1667 } |
1666 | 1668 |
1667 Token parseFunctionExpression(Token token) { | 1669 Token parseFunctionExpression(Token token) { |
1668 listener.beginFunction(token); | 1670 listener.beginFunction(token); |
1669 listener.handleModifiers(0); | 1671 listener.handleModifiers(0); |
1670 token = parseReturnTypeOpt(token); | 1672 token = parseReturnTypeOpt(token); |
1671 listener.beginFunctionName(token); | 1673 listener.beginFunctionName(token); |
1672 token = parseIdentifier(token); | 1674 token = parseIdentifier(token); |
1673 listener.endFunctionName(token); | 1675 listener.endFunctionName(token); |
1674 if (enableGenericMethodSyntax) { | 1676 token = parseTypeVariablesOpt(token); |
1675 token = parseTypeVariablesOpt(token); | |
1676 } else { | |
1677 listener.handleNoTypeVariables(token); | |
1678 } | |
1679 token = parseFormalParameters(token); | 1677 token = parseFormalParameters(token); |
1680 listener.handleNoInitializers(); | 1678 listener.handleNoInitializers(); |
1681 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1679 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
1682 token = parseAsyncModifier(token); | 1680 token = parseAsyncModifier(token); |
1683 bool isBlock = optional('{', token); | 1681 bool isBlock = optional('{', token); |
1684 token = parseFunctionBody(token, true, false); | 1682 token = parseFunctionBody(token, true, false); |
1685 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; | 1683 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; |
1686 listener.endFunction(null, token); | 1684 listener.endFunction(null, token); |
1687 return isBlock ? token.next : token; | 1685 return isBlock ? token.next : token; |
1688 } | 1686 } |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1944 // TODO(eernst): Check for NPE as described in issue 26252. | 1942 // TODO(eernst): Check for NPE as described in issue 26252. |
1945 Token afterParens = endParen.next; | 1943 Token afterParens = endParen.next; |
1946 if (optional('{', afterParens) || | 1944 if (optional('{', afterParens) || |
1947 optional('=>', afterParens) || | 1945 optional('=>', afterParens) || |
1948 optional('async', afterParens) || | 1946 optional('async', afterParens) || |
1949 optional('sync', afterParens)) { | 1947 optional('sync', afterParens)) { |
1950 // We are looking at "type identifier '(' ... ')'" followed | 1948 // We are looking at "type identifier '(' ... ')'" followed |
1951 // by '{', '=>', 'async', or 'sync'. | 1949 // by '{', '=>', 'async', or 'sync'. |
1952 return parseFunctionDeclaration(token); | 1950 return parseFunctionDeclaration(token); |
1953 } | 1951 } |
1954 } else if (enableGenericMethodSyntax && | 1952 } else if (identical(afterIdKind, LT_TOKEN)) { |
1955 identical(afterIdKind, LT_TOKEN)) { | |
1956 // We are looking at "type identifier '<'". | 1953 // We are looking at "type identifier '<'". |
1957 BeginGroupToken beginAngle = afterId; | 1954 BeginGroupToken beginAngle = afterId; |
1958 Token endAngle = beginAngle.endGroup; | 1955 Token endAngle = beginAngle.endGroup; |
1959 if (endAngle != null && | 1956 if (endAngle != null && |
1960 identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) { | 1957 identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) { |
1961 BeginGroupToken beginParen = endAngle.next; | 1958 BeginGroupToken beginParen = endAngle.next; |
1962 Token endParen = beginParen.endGroup; | 1959 Token endParen = beginParen.endGroup; |
1963 if (endParen != null) { | 1960 if (endParen != null) { |
1964 Token afterParens = endParen.next; | 1961 Token afterParens = endParen.next; |
1965 if (optional('{', afterParens) || | 1962 if (optional('{', afterParens) || |
(...skipping 14 matching lines...) Expand all Loading... |
1980 } else if (optional('(', token.next)) { | 1977 } else if (optional('(', token.next)) { |
1981 BeginGroupToken begin = token.next; | 1978 BeginGroupToken begin = token.next; |
1982 // TODO(eernst): Check for NPE as described in issue 26252. | 1979 // TODO(eernst): Check for NPE as described in issue 26252. |
1983 String afterParens = begin.endGroup.next.stringValue; | 1980 String afterParens = begin.endGroup.next.stringValue; |
1984 if (identical(afterParens, '{') || | 1981 if (identical(afterParens, '{') || |
1985 identical(afterParens, '=>') || | 1982 identical(afterParens, '=>') || |
1986 identical(afterParens, 'async') || | 1983 identical(afterParens, 'async') || |
1987 identical(afterParens, 'sync')) { | 1984 identical(afterParens, 'sync')) { |
1988 return parseFunctionDeclaration(token); | 1985 return parseFunctionDeclaration(token); |
1989 } | 1986 } |
1990 } else if (enableGenericMethodSyntax && optional('<', token.next)) { | 1987 } else if (optional('<', token.next)) { |
1991 BeginGroupToken beginAngle = token.next; | 1988 BeginGroupToken beginAngle = token.next; |
1992 Token endAngle = beginAngle.endGroup; | 1989 Token endAngle = beginAngle.endGroup; |
1993 if (endAngle != null && | 1990 if (endAngle != null && |
1994 identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) { | 1991 identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) { |
1995 BeginGroupToken beginParen = endAngle.next; | 1992 BeginGroupToken beginParen = endAngle.next; |
1996 Token endParen = beginParen.endGroup; | 1993 Token endParen = beginParen.endGroup; |
1997 if (endParen != null) { | 1994 if (endParen != null) { |
1998 String afterParens = endParen.next.stringValue; | 1995 String afterParens = endParen.next.stringValue; |
1999 if (identical(afterParens, '{') || | 1996 if (identical(afterParens, '{') || |
2000 identical(afterParens, '=>') || | 1997 identical(afterParens, '=>') || |
(...skipping 493 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2494 /// Where | 2491 /// Where |
2495 /// genericListLiteral ::= typeArguments '[' (expressionList ','?)? ']' | 2492 /// genericListLiteral ::= typeArguments '[' (expressionList ','?)? ']' |
2496 /// genericMapLiteral ::= | 2493 /// genericMapLiteral ::= |
2497 /// typeArguments '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}' | 2494 /// typeArguments '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}' |
2498 /// genericFunctionLiteral ::= | 2495 /// genericFunctionLiteral ::= |
2499 /// typeParameters formalParameterList functionBody | 2496 /// typeParameters formalParameterList functionBody |
2500 /// Provide token for [constKeyword] if preceded by 'const', null if not. | 2497 /// Provide token for [constKeyword] if preceded by 'const', null if not. |
2501 Token parseLiteralListOrMapOrFunction(Token token, Token constKeyword) { | 2498 Token parseLiteralListOrMapOrFunction(Token token, Token constKeyword) { |
2502 assert(optional('<', token)); | 2499 assert(optional('<', token)); |
2503 BeginGroupToken begin = token; | 2500 BeginGroupToken begin = token; |
2504 if (enableGenericMethodSyntax && | 2501 if (constKeyword == null && |
2505 constKeyword == null && | |
2506 begin.endGroup != null && | 2502 begin.endGroup != null && |
2507 identical(begin.endGroup.next.kind, OPEN_PAREN_TOKEN)) { | 2503 identical(begin.endGroup.next.kind, OPEN_PAREN_TOKEN)) { |
2508 token = parseTypeVariablesOpt(token); | 2504 token = parseTypeVariablesOpt(token); |
2509 return parseLiteralFunctionSuffix(token); | 2505 return parseLiteralFunctionSuffix(token); |
2510 } else { | 2506 } else { |
2511 token = parseTypeArgumentsOpt(token); | 2507 token = parseTypeArgumentsOpt(token); |
2512 if (optional('{', token)) { | 2508 if (optional('{', token)) { |
2513 return parseLiteralMapSuffix(token, constKeyword); | 2509 return parseLiteralMapSuffix(token, constKeyword); |
2514 } else if ((optional('[', token)) || (optional('[]', token))) { | 2510 } else if ((optional('[', token)) || (optional('[]', token))) { |
2515 return parseLiteralListSuffix(token, constKeyword); | 2511 return parseLiteralListSuffix(token, constKeyword); |
(...skipping 22 matching lines...) Expand all Loading... |
2538 isFunctionDeclaration(peek.next)) { | 2534 isFunctionDeclaration(peek.next)) { |
2539 return parseFunctionExpression(token); | 2535 return parseFunctionExpression(token); |
2540 } else if (isFunctionDeclaration(token.next)) { | 2536 } else if (isFunctionDeclaration(token.next)) { |
2541 return parseFunctionExpression(token); | 2537 return parseFunctionExpression(token); |
2542 } else { | 2538 } else { |
2543 return parseSend(token); | 2539 return parseSend(token); |
2544 } | 2540 } |
2545 } | 2541 } |
2546 | 2542 |
2547 bool isFunctionDeclaration(Token token) { | 2543 bool isFunctionDeclaration(Token token) { |
2548 if (enableGenericMethodSyntax && optional('<', token)) { | 2544 if (optional('<', token)) { |
2549 BeginGroupToken begin = token; | 2545 BeginGroupToken begin = token; |
2550 if (begin.endGroup == null) return false; | 2546 if (begin.endGroup == null) return false; |
2551 token = begin.endGroup.next; | 2547 token = begin.endGroup.next; |
2552 } | 2548 } |
2553 if (optional('(', token)) { | 2549 if (optional('(', token)) { |
2554 BeginGroupToken begin = token; | 2550 BeginGroupToken begin = token; |
2555 // TODO(eernst): Check for NPE as described in issue 26252. | 2551 // TODO(eernst): Check for NPE as described in issue 26252. |
2556 String afterParens = begin.endGroup.next.stringValue; | 2552 String afterParens = begin.endGroup.next.stringValue; |
2557 if (identical(afterParens, '{') || | 2553 if (identical(afterParens, '{') || |
2558 identical(afterParens, '=>') || | 2554 identical(afterParens, '=>') || |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2687 } | 2683 } |
2688 | 2684 |
2689 Token parseLiteralNull(Token token) { | 2685 Token parseLiteralNull(Token token) { |
2690 listener.handleLiteralNull(token); | 2686 listener.handleLiteralNull(token); |
2691 return token.next; | 2687 return token.next; |
2692 } | 2688 } |
2693 | 2689 |
2694 Token parseSend(Token token) { | 2690 Token parseSend(Token token) { |
2695 listener.beginSend(token); | 2691 listener.beginSend(token); |
2696 token = parseIdentifier(token); | 2692 token = parseIdentifier(token); |
2697 if (enableGenericMethodSyntax && isValidMethodTypeArguments(token)) { | 2693 if (isValidMethodTypeArguments(token)) { |
2698 token = parseTypeArgumentsOpt(token); | 2694 token = parseTypeArgumentsOpt(token); |
2699 } else { | 2695 } else { |
2700 listener.handleNoTypeArguments(token); | 2696 listener.handleNoTypeArguments(token); |
2701 } | 2697 } |
2702 token = parseArgumentsOpt(token); | 2698 token = parseArgumentsOpt(token); |
2703 listener.endSend(token); | 2699 listener.endSend(token); |
2704 return token; | 2700 return token; |
2705 } | 2701 } |
2706 | 2702 |
2707 Token skipArgumentsOpt(Token token) { | 2703 Token skipArgumentsOpt(Token token) { |
(...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3174 } | 3170 } |
3175 listener.handleContinueStatement(hasTarget, continueKeyword, token); | 3171 listener.handleContinueStatement(hasTarget, continueKeyword, token); |
3176 return expectSemicolon(token); | 3172 return expectSemicolon(token); |
3177 } | 3173 } |
3178 | 3174 |
3179 Token parseEmptyStatement(Token token) { | 3175 Token parseEmptyStatement(Token token) { |
3180 listener.handleEmptyStatement(token); | 3176 listener.handleEmptyStatement(token); |
3181 return expectSemicolon(token); | 3177 return expectSemicolon(token); |
3182 } | 3178 } |
3183 } | 3179 } |
OLD | NEW |