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 fasta.parser.parser; | 5 library fasta.parser.parser; |
6 | 6 |
7 import '../scanner.dart' show | 7 import '../scanner.dart' show |
8 ErrorToken; | 8 ErrorToken; |
9 | 9 |
10 import '../scanner/recover.dart' show | 10 import '../scanner/recover.dart' show |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 /** | 93 /** |
94 * An event generating parser of Dart programs. This parser expects | 94 * An event generating parser of Dart programs. This parser expects |
95 * all tokens in a linked list (aka a token stream). | 95 * all tokens in a linked list (aka a token stream). |
96 * | 96 * |
97 * The class [Scanner] is used to generate a token stream. See the | 97 * The class [Scanner] is used to generate a token stream. See the |
98 * file scanner.dart. | 98 * file scanner.dart. |
99 * | 99 * |
100 * Subclasses of the class [Listener] are used to listen to events. | 100 * Subclasses of the class [Listener] are used to listen to events. |
101 * | 101 * |
102 * Most methods of this class belong in one of two major categories: | 102 * Most methods of this class belong in one of two major categories: |
103 * parse metods and peek methods. Parse methods all have the prefix | 103 * parse methods and peek methods. Parse methods all have the prefix |
104 * parse, and peek methods all have the prefix peek. | 104 * parse, and peek methods all have the prefix peek. |
105 * | 105 * |
106 * Parse methods generate events (by calling methods on [listener]) | 106 * Parse methods generate events (by calling methods on [listener]) |
107 * and return the next token to parse. Peek methods do not generate | 107 * and return the next token to parse. Peek methods do not generate |
108 * events (except for errors) and may return null. | 108 * events (except for errors) and may return null. |
109 * | 109 * |
110 * Parse methods are generally named parseGrammarProductionSuffix. The | 110 * Parse methods are generally named parseGrammarProductionSuffix. The |
111 * suffix can be one of "opt", or "star". "opt" means zero or one | 111 * suffix can be one of "opt", or "star". "opt" means zero or one |
112 * matches, "star" means zero or more matches. For example, | 112 * matches, "star" means zero or more matches. For example, |
113 * [parseMetadataStar] corresponds to this grammar snippet: [: | 113 * [parseMetadataStar] corresponds to this grammar snippet: [: |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 period = token; | 377 period = token; |
378 token = parseIdentifier(token.next); | 378 token = parseIdentifier(token.next); |
379 } | 379 } |
380 token = parseArgumentsOpt(token); | 380 token = parseArgumentsOpt(token); |
381 listener.endMetadata(atToken, period, token); | 381 listener.endMetadata(atToken, period, token); |
382 return token; | 382 return token; |
383 } | 383 } |
384 | 384 |
385 Token parseTypedef(Token token) { | 385 Token parseTypedef(Token token) { |
386 Token typedefKeyword = token; | 386 Token typedefKeyword = token; |
387 listener.beginFunctionTypeAlias(token); | 387 listener.beginTypedef(token); |
388 token = parseReturnTypeOpt(token.next); | 388 Token equals; |
389 token = parseIdentifier(token); | 389 if (optional('=', peekAfterNominalType(token.next))) { |
390 token = parseTypeVariablesOpt(token); | 390 token = parseIdentifier(token.next); |
391 token = parseFormalParameters(token); | 391 token = parseTypeVariablesOpt(token); |
392 listener.endFunctionTypeAlias(typedefKeyword, token); | 392 equals = token; |
| 393 token = expect('=', token); |
| 394 token = parseType(token); |
| 395 } else { |
| 396 token = parseReturnTypeOpt(token.next); |
| 397 token = parseIdentifier(token); |
| 398 token = parseTypeVariablesOpt(token); |
| 399 token = parseFormalParameters(token); |
| 400 } |
| 401 listener.endTypedef(typedefKeyword, equals, token); |
393 return expect(';', token); | 402 return expect(';', token); |
394 } | 403 } |
395 | 404 |
396 Token parseMixinApplication(Token token) { | 405 Token parseMixinApplication(Token token) { |
397 listener.beginMixinApplication(token); | 406 listener.beginMixinApplication(token); |
398 token = parseType(token); | 407 token = parseType(token); |
399 token = expect('with', token); | 408 token = expect('with', token); |
400 token = parseTypeList(token); | 409 token = parseTypeList(token); |
401 listener.endMixinApplication(); | 410 listener.endMixinApplication(); |
402 return token; | 411 return token; |
(...skipping 27 matching lines...) Expand all Loading... |
430 } | 439 } |
431 return reportUnrecoverableError( | 440 return reportUnrecoverableError( |
432 token, ErrorKind.ExpectedButGot, {"expected": "("}); | 441 token, ErrorKind.ExpectedButGot, {"expected": "("}); |
433 } | 442 } |
434 BeginGroupToken beginGroupToken = token; | 443 BeginGroupToken beginGroupToken = token; |
435 Token endToken = beginGroupToken.endGroup; | 444 Token endToken = beginGroupToken.endGroup; |
436 listener.endFormalParameters(0, token, endToken); | 445 listener.endFormalParameters(0, token, endToken); |
437 return endToken.next; | 446 return endToken.next; |
438 } | 447 } |
439 | 448 |
440 Token parseFormalParameters(Token token) { | 449 /// Parses the formal parameter list of a function. |
| 450 /// |
| 451 /// If [inFunctionType] is true, then the names may be omitted (except for |
| 452 /// named arguments). If it is false, then the types may be omitted. |
| 453 Token parseFormalParameters(Token token, {bool inFunctionType: false}) { |
441 Token begin = token; | 454 Token begin = token; |
442 listener.beginFormalParameters(begin); | 455 listener.beginFormalParameters(begin); |
443 expect('(', token); | 456 expect('(', token); |
444 int parameterCount = 0; | 457 int parameterCount = 0; |
445 do { | 458 do { |
446 token = token.next; | 459 token = token.next; |
447 if (optional(')', token)) { | 460 if (optional(')', token)) { |
448 break; | 461 break; |
449 } | 462 } |
450 ++parameterCount; | 463 ++parameterCount; |
451 String value = token.stringValue; | 464 String value = token.stringValue; |
452 if (identical(value, '[')) { | 465 if (identical(value, '[')) { |
453 token = parseOptionalFormalParameters(token, false); | 466 token = parseOptionalFormalParameters( |
| 467 token, false, inFunctionType: inFunctionType); |
454 break; | 468 break; |
455 } else if (identical(value, '{')) { | 469 } else if (identical(value, '{')) { |
456 token = parseOptionalFormalParameters(token, true); | 470 token = parseOptionalFormalParameters( |
| 471 token, true, inFunctionType: inFunctionType); |
457 break; | 472 break; |
458 } | 473 } |
459 token = parseFormalParameter(token, FormalParameterType.REQUIRED); | 474 token = parseFormalParameter(token, FormalParameterType.REQUIRED, |
| 475 inFunctionType: inFunctionType); |
460 } while (optional(',', token)); | 476 } while (optional(',', token)); |
461 listener.endFormalParameters(parameterCount, begin, token); | 477 listener.endFormalParameters(parameterCount, begin, token); |
462 return expect(')', token); | 478 return expect(')', token); |
463 } | 479 } |
464 | 480 |
465 Token parseFormalParameter(Token token, FormalParameterType type) { | 481 Token parseFormalParameter(Token token, FormalParameterType type, |
| 482 {bool inFunctionType}) { |
466 token = parseMetadataStar(token, forParameter: true); | 483 token = parseMetadataStar(token, forParameter: true); |
467 listener.beginFormalParameter(token); | 484 listener.beginFormalParameter(token); |
468 | 485 |
469 // Skip over `covariant` token, if the next token is an identifier or | 486 // Skip over `covariant` token, if the next token is an identifier or |
470 // modifier. | 487 // modifier. |
471 // This enables the case where `covariant` is the name of the parameter: | 488 // This enables the case where `covariant` is the name of the parameter: |
472 // void foo(covariant); | 489 // void foo(covariant); |
473 if (identical(token.stringValue, 'covariant') && | 490 if (identical(token.stringValue, 'covariant') && |
474 (token.next.isIdentifier() || isModifier(token.next))) { | 491 (token.next.isIdentifier() || isModifier(token.next))) { |
475 token = token.next; | 492 token = token.next; |
476 } | 493 } |
477 token = parseModifiers(token); | 494 token = parseModifiers(token); |
478 // TODO(ahe): Validate that there are formal parameters if void. | 495 bool isNamedParameter = type == FormalParameterType.NAMED; |
479 token = parseReturnTypeOpt(token); | 496 |
480 Token thisKeyword = null; | 497 Token thisKeyword = null; |
481 if (optional('this', token)) { | 498 if (inFunctionType && isNamedParameter) { |
482 thisKeyword = token; | 499 token = parseType(token); |
483 // TODO(ahe): Validate field initializers are only used in | 500 token = parseIdentifier(token); |
484 // constructors, and not for function-typed arguments. | 501 } else if (inFunctionType) { |
485 token = expect('.', token.next); | 502 token = parseType(token); |
| 503 if (token.isIdentifier()) { |
| 504 token = parseIdentifier(token); |
| 505 } else { |
| 506 listener.handleNoName(token); |
| 507 } |
| 508 } else { |
| 509 token = parseReturnTypeOpt(token); |
| 510 if (optional('this', token)) { |
| 511 thisKeyword = token; |
| 512 token = expect('.', token.next); |
| 513 } |
| 514 token = parseIdentifier(token); |
486 } | 515 } |
487 token = parseIdentifier(token); | 516 |
| 517 // Generalized function types don't allow inline function types. |
| 518 // The following isn't allowed: |
| 519 // int Function(int bar(String x)). |
488 if (optional('(', token)) { | 520 if (optional('(', token)) { |
| 521 Token inlineFunctionTypeStart = token; |
489 listener.beginFunctionTypedFormalParameter(token); | 522 listener.beginFunctionTypedFormalParameter(token); |
490 listener.handleNoTypeVariables(token); | 523 listener.handleNoTypeVariables(token); |
491 token = parseFormalParameters(token); | 524 token = parseFormalParameters(token); |
492 listener.endFunctionTypedFormalParameter(token); | 525 listener.endFunctionTypedFormalParameter(token); |
| 526 if (inFunctionType) { |
| 527 reportRecoverableError( |
| 528 inlineFunctionTypeStart, ErrorKind.InvalidInlineFunctionType); |
| 529 } |
493 } else if (optional('<', token)) { | 530 } else if (optional('<', token)) { |
| 531 Token inlineFunctionTypeStart = token; |
494 listener.beginFunctionTypedFormalParameter(token); | 532 listener.beginFunctionTypedFormalParameter(token); |
495 token = parseTypeVariablesOpt(token); | 533 token = parseTypeVariablesOpt(token); |
496 token = parseFormalParameters(token); | 534 token = parseFormalParameters(token); |
497 listener.endFunctionTypedFormalParameter(token); | 535 listener.endFunctionTypedFormalParameter(token); |
| 536 if (inFunctionType) { |
| 537 reportRecoverableError( |
| 538 inlineFunctionTypeStart, ErrorKind.InvalidInlineFunctionType); |
| 539 } |
498 } | 540 } |
499 String value = token.stringValue; | 541 String value = token.stringValue; |
500 if ((identical('=', value)) || (identical(':', value))) { | 542 if ((identical('=', value)) || (identical(':', value))) { |
501 // TODO(ahe): Validate that these are only used for optional parameters. | 543 // TODO(ahe): Validate that these are only used for optional parameters. |
502 Token equal = token; | 544 Token equal = token; |
503 token = parseExpression(token.next); | 545 token = parseExpression(token.next); |
504 listener.handleValuedFormalParameter(equal, token); | 546 listener.handleValuedFormalParameter(equal, token); |
505 if (type.isRequired) { | 547 if (type.isRequired) { |
506 reportRecoverableError( | 548 reportRecoverableError( |
507 equal, ErrorKind.RequiredParameterWithDefault); | 549 equal, ErrorKind.RequiredParameterWithDefault); |
508 } else if (type.isPositional && identical(':', value)) { | 550 } else if (type.isPositional && identical(':', value)) { |
509 reportRecoverableError( | 551 reportRecoverableError( |
510 equal, ErrorKind.PositionalParameterWithEquals); | 552 equal, ErrorKind.PositionalParameterWithEquals); |
511 } | 553 } |
512 } | 554 } |
513 listener.endFormalParameter(thisKeyword); | 555 listener.endFormalParameter(thisKeyword); |
514 return token; | 556 return token; |
515 } | 557 } |
516 | 558 |
517 Token parseOptionalFormalParameters(Token token, bool isNamed) { | 559 Token parseOptionalFormalParameters(Token token, bool isNamed, |
| 560 {bool inFunctionType}) { |
518 Token begin = token; | 561 Token begin = token; |
519 listener.beginOptionalFormalParameters(begin); | 562 listener.beginOptionalFormalParameters(begin); |
520 assert((isNamed && optional('{', token)) || optional('[', token)); | 563 assert((isNamed && optional('{', token)) || optional('[', token)); |
521 int parameterCount = 0; | 564 int parameterCount = 0; |
522 do { | 565 do { |
523 token = token.next; | 566 token = token.next; |
524 if (isNamed && optional('}', token)) { | 567 if (isNamed && optional('}', token)) { |
525 break; | 568 break; |
526 } else if (!isNamed && optional(']', token)) { | 569 } else if (!isNamed && optional(']', token)) { |
527 break; | 570 break; |
528 } | 571 } |
529 var type = | 572 var type = |
530 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; | 573 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; |
531 token = parseFormalParameter(token, type); | 574 token = |
| 575 parseFormalParameter(token, type, inFunctionType: inFunctionType); |
532 ++parameterCount; | 576 ++parameterCount; |
533 } while (optional(',', token)); | 577 } while (optional(',', token)); |
534 if (parameterCount == 0) { | 578 if (parameterCount == 0) { |
535 reportRecoverableError( | 579 reportRecoverableError( |
536 token, | 580 token, |
537 isNamed | 581 isNamed |
538 ? ErrorKind.EmptyNamedParameterList | 582 ? ErrorKind.EmptyNamedParameterList |
539 : ErrorKind.EmptyOptionalParameterList); | 583 : ErrorKind.EmptyOptionalParameterList); |
540 } | 584 } |
541 listener.endOptionalFormalParameters(parameterCount, begin, token); | 585 listener.endOptionalFormalParameters(parameterCount, begin, token); |
542 if (isNamed) { | 586 if (isNamed) { |
543 return expect('}', token); | 587 return expect('}', token); |
544 } else { | 588 } else { |
545 return expect(']', token); | 589 return expect(']', token); |
546 } | 590 } |
547 } | 591 } |
548 | 592 |
549 Token parseTypeOpt(Token token) { | 593 Token parseTypeOpt(Token token) { |
| 594 if (isGeneralizedFunctionType(token)) { |
| 595 // Function type without return type. |
| 596 return parseType(token); |
| 597 } |
550 Token peek = peekAfterIfType(token); | 598 Token peek = peekAfterIfType(token); |
551 if (peek != null && (peek.isIdentifier() || optional('this', peek))) { | 599 if (peek != null && (peek.isIdentifier() || optional('this', peek))) { |
552 return parseType(token); | 600 return parseType(token); |
553 } | 601 } |
554 listener.handleNoType(token); | 602 listener.handleNoType(token); |
555 return token; | 603 return token; |
556 } | 604 } |
557 | 605 |
558 bool isValidTypeReference(Token token) { | 606 bool isValidTypeReference(Token token) { |
559 final kind = token.kind; | 607 final kind = token.kind; |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
706 } | 754 } |
707 | 755 |
708 Token parseClassOrNamedMixinApplication(Token token) { | 756 Token parseClassOrNamedMixinApplication(Token token) { |
709 Token begin = token; | 757 Token begin = token; |
710 Token abstractKeyword; | 758 Token abstractKeyword; |
711 if (optional('abstract', token)) { | 759 if (optional('abstract', token)) { |
712 abstractKeyword = token; | 760 abstractKeyword = token; |
713 token = token.next; | 761 token = token.next; |
714 } | 762 } |
715 Token classKeyword = token; | 763 Token classKeyword = token; |
716 var isMixinApplication = optional('=', peekAfterType(token.next)); | 764 var isMixinApplication = optional('=', peekAfterNominalType(token.next)); |
717 if (isMixinApplication) { | 765 if (isMixinApplication) { |
718 listener.beginNamedMixinApplication(begin); | 766 listener.beginNamedMixinApplication(begin); |
719 } else { | 767 } else { |
720 listener.beginClassDeclaration(begin); | 768 listener.beginClassDeclaration(begin); |
721 } | 769 } |
722 | 770 |
723 int modifierCount = 0; | 771 int modifierCount = 0; |
724 if (abstractKeyword != null) { | 772 if (abstractKeyword != null) { |
725 parseModifier(abstractKeyword); | 773 parseModifier(abstractKeyword); |
726 modifierCount++; | 774 modifierCount++; |
(...skipping 20 matching lines...) Expand all Loading... |
747 listener.endNamedMixinApplication(classKeyword, implementsKeyword, token); | 795 listener.endNamedMixinApplication(classKeyword, implementsKeyword, token); |
748 return expect(';', token); | 796 return expect(';', token); |
749 } | 797 } |
750 | 798 |
751 Token parseClass(Token begin, Token classKeyword) { | 799 Token parseClass(Token begin, Token classKeyword) { |
752 Token token = parseIdentifier(classKeyword.next); | 800 Token token = parseIdentifier(classKeyword.next); |
753 token = parseTypeVariablesOpt(token); | 801 token = parseTypeVariablesOpt(token); |
754 Token extendsKeyword; | 802 Token extendsKeyword; |
755 if (optional('extends', token)) { | 803 if (optional('extends', token)) { |
756 extendsKeyword = token; | 804 extendsKeyword = token; |
757 if (optional('with', peekAfterType(token.next))) { | 805 if (optional('with', peekAfterNominalType(token.next))) { |
758 token = parseMixinApplication(token.next); | 806 token = parseMixinApplication(token.next); |
759 } else { | 807 } else { |
760 token = parseType(token.next); | 808 token = parseType(token.next); |
761 } | 809 } |
762 } else { | 810 } else { |
763 extendsKeyword = null; | 811 extendsKeyword = null; |
764 listener.handleNoType(token); | 812 listener.handleNoType(token); |
765 } | 813 } |
766 Token implementsKeyword; | 814 Token implementsKeyword; |
767 int interfacesCount = 0; | 815 int interfacesCount = 0; |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
838 value2 == stringValue || | 886 value2 == stringValue || |
839 value3 == stringValue || | 887 value3 == stringValue || |
840 value4 == stringValue; | 888 value4 == stringValue; |
841 } | 889 } |
842 | 890 |
843 bool notEofOrValue(String value, Token token) { | 891 bool notEofOrValue(String value, Token token) { |
844 return !identical(token.kind, EOF_TOKEN) && | 892 return !identical(token.kind, EOF_TOKEN) && |
845 !identical(value, token.stringValue); | 893 !identical(value, token.stringValue); |
846 } | 894 } |
847 | 895 |
| 896 bool isGeneralizedFunctionType(Token token) { |
| 897 return optional('Function', token) && |
| 898 (optional('<', token.next) || optional('(', token.next)); |
| 899 } |
| 900 |
848 Token parseType(Token token) { | 901 Token parseType(Token token) { |
849 Token begin = token; | 902 Token begin = token; |
850 if (isValidTypeReference(token)) { | 903 if (isGeneralizedFunctionType(token)) { |
851 token = parseIdentifier(token); | 904 // A function type without return type. |
852 token = parseQualifiedRestOpt(token); | 905 // Push the non-existing return type first. The loop below will |
| 906 // generate the full type. |
| 907 listener.handleNoType(token); |
853 } else { | 908 } else { |
854 token = reportUnrecoverableError(token, ErrorKind.ExpectedType); | 909 if (isValidTypeReference(token)) { |
855 listener.handleInvalidTypeReference(token); | 910 token = parseIdentifier(token); |
| 911 token = parseQualifiedRestOpt(token); |
| 912 } else { |
| 913 token = reportUnrecoverableError(token, ErrorKind.ExpectedType); |
| 914 listener.handleInvalidTypeReference(token); |
| 915 } |
| 916 token = parseTypeArgumentsOpt(token); |
| 917 listener.endType(begin, token); |
856 } | 918 } |
857 token = parseTypeArgumentsOpt(token); | 919 |
858 listener.endType(begin, token); | 920 // While we see a `Function(` treat the pushed type as return type. |
| 921 // For example: `int Function() Function(int) Function(String x)`. |
| 922 while (isGeneralizedFunctionType(token)) { |
| 923 token = parseFunctionType(token); |
| 924 } |
859 return token; | 925 return token; |
860 } | 926 } |
861 | 927 |
| 928 /// Parses a generalized function type. |
| 929 /// |
| 930 /// The return type must already be pushed. |
| 931 Token parseFunctionType(Token token) { |
| 932 assert(optional('Function', token)); |
| 933 Token functionToken = token; |
| 934 token = token.next; |
| 935 token = parseTypeVariablesOpt(token); |
| 936 token = parseFormalParameters(token, inFunctionType: true); |
| 937 listener.endFunctionType(functionToken, token); |
| 938 return token; |
| 939 } |
| 940 |
862 Token parseTypeArgumentsOpt(Token token) { | 941 Token parseTypeArgumentsOpt(Token token) { |
863 return parseStuff( | 942 return parseStuff( |
864 token, | 943 token, |
865 (t) => listener.beginTypeArguments(t), | 944 (t) => listener.beginTypeArguments(t), |
866 (t) => parseType(t), | 945 (t) => parseType(t), |
867 (c, bt, et) => listener.endTypeArguments(c, bt, et), | 946 (c, bt, et) => listener.endTypeArguments(c, bt, et), |
868 (t) => listener.handleNoTypeArguments(t)); | 947 (t) => listener.handleNoTypeArguments(t)); |
869 } | 948 } |
870 | 949 |
871 Token parseTypeVariablesOpt(Token token) { | 950 Token parseTypeVariablesOpt(Token token) { |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1203 return listener.handleMemberName(identifiers); | 1282 return listener.handleMemberName(identifiers); |
1204 } else if (optional("=", token) || optional(";", token) || | 1283 } else if (optional("=", token) || optional(";", token) || |
1205 optional(",", token)) { | 1284 optional(",", token)) { |
1206 // A field or abstract getter. | 1285 // A field or abstract getter. |
1207 identifiers = identifiers.prepend(token); | 1286 identifiers = identifiers.prepend(token); |
1208 return listener.handleMemberName(identifiers); | 1287 return listener.handleMemberName(identifiers); |
1209 } else if (isGetter) { | 1288 } else if (isGetter) { |
1210 hasName = true; | 1289 hasName = true; |
1211 } | 1290 } |
1212 identifiers = identifiers.prepend(token); | 1291 identifiers = identifiers.prepend(token); |
1213 if (isValidTypeReference(token)) { | 1292 |
1214 // type ... | 1293 if (!isGeneralizedFunctionType(token)) { |
1215 if (optional('.', token.next)) { | 1294 // Read a potential return type. |
1216 // type '.' ... | 1295 if (isValidTypeReference(token)) { |
1217 if (token.next.next.isIdentifier()) { | 1296 // type ... |
1218 // type '.' identifier | 1297 if (optional('.', token.next)) { |
1219 token = token.next.next; | 1298 // type '.' ... |
| 1299 if (token.next.next.isIdentifier()) { |
| 1300 // type '.' identifier |
| 1301 token = token.next.next; |
| 1302 } |
| 1303 } |
| 1304 if (optional('<', token.next)) { |
| 1305 if (token.next is BeginGroupToken) { |
| 1306 BeginGroupToken beginGroup = token.next; |
| 1307 if (beginGroup.endGroup == null) { |
| 1308 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); |
| 1309 } else { |
| 1310 token = beginGroup.endGroup; |
| 1311 } |
| 1312 } |
1220 } | 1313 } |
1221 } | 1314 } |
1222 if (optional('<', token.next)) { | 1315 token = token.next; |
1223 if (token.next is BeginGroupToken) { | 1316 } |
1224 BeginGroupToken beginGroup = token.next; | 1317 while (isGeneralizedFunctionType(token)) { |
| 1318 token = token.next; |
| 1319 if (optional('<', token)) { |
| 1320 if (token is BeginGroupToken) { |
| 1321 BeginGroupToken beginGroup = token; |
1225 if (beginGroup.endGroup == null) { | 1322 if (beginGroup.endGroup == null) { |
1226 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); | 1323 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); |
1227 } else { | 1324 } else { |
1228 token = beginGroup.endGroup; | 1325 token = beginGroup.endGroup.next; |
1229 } | 1326 } |
1230 } | 1327 } |
1231 } | 1328 } |
| 1329 if (!optional('(', token)) { |
| 1330 if (optional(';', token)) { |
| 1331 reportRecoverableError(token, ErrorKind.ExpectedOpenParens); |
| 1332 } |
| 1333 token = expect("(", token); |
| 1334 } |
| 1335 if (token is BeginGroupToken) { |
| 1336 BeginGroupToken beginGroup = token; |
| 1337 if (beginGroup.endGroup == null) { |
| 1338 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); |
| 1339 } else { |
| 1340 token = beginGroup.endGroup.next; |
| 1341 } |
| 1342 } |
1232 } | 1343 } |
1233 token = token.next; | |
1234 } | 1344 } |
1235 return listener.handleMemberName(const Link<Token>()); | 1345 return listener.handleMemberName(const Link<Token>()); |
1236 } | 1346 } |
1237 | 1347 |
1238 Token parseFieldInitializerOpt(Token token) { | 1348 Token parseFieldInitializerOpt(Token token) { |
1239 if (optional('=', token)) { | 1349 if (optional('=', token)) { |
1240 Token assignment = token; | 1350 Token assignment = token; |
1241 listener.beginFieldInitializer(token); | 1351 listener.beginFieldInitializer(token); |
1242 token = parseExpression(token.next); | 1352 token = parseExpression(token.next); |
1243 listener.endFieldInitializer(assignment); | 1353 listener.endFieldInitializer(assignment); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1336 if (!isModifier(token)) break; | 1446 if (!isModifier(token)) break; |
1337 token = parseModifier(token); | 1447 token = parseModifier(token); |
1338 count++; | 1448 count++; |
1339 } | 1449 } |
1340 listener.handleModifiers(count); | 1450 listener.handleModifiers(count); |
1341 return token; | 1451 return token; |
1342 } | 1452 } |
1343 | 1453 |
1344 /** | 1454 /** |
1345 * Returns the first token after the type starting at [token]. | 1455 * Returns the first token after the type starting at [token]. |
| 1456 * |
1346 * This method assumes that [token] is an identifier (or void). | 1457 * This method assumes that [token] is an identifier (or void). |
1347 * Use [peekAfterIfType] if [token] isn't known to be an identifier. | 1458 * Use [peekAfterIfType] if [token] isn't known to be an identifier. |
1348 */ | 1459 */ |
1349 Token peekAfterType(Token token) { | 1460 Token peekAfterType(Token token) { |
1350 // We are looking at "identifier ...". | 1461 // We are looking at "identifier ...". |
| 1462 Token peek = token; |
| 1463 if (!isGeneralizedFunctionType(token)) { |
| 1464 peek = peekAfterNominalType(token); |
| 1465 } |
| 1466 |
| 1467 // We might have just skipped over the return value of the function type. |
| 1468 // Check again, if we are now at a function type position. |
| 1469 while (isGeneralizedFunctionType(peek)) { |
| 1470 peek = peekAfterFunctionType(peek); |
| 1471 } |
| 1472 return peek; |
| 1473 } |
| 1474 |
| 1475 /** |
| 1476 * Returns the first token after the nominal type starting at [token]. |
| 1477 * |
| 1478 * This method assumes that [token] is an identifier (or void). |
| 1479 */ |
| 1480 Token peekAfterNominalType(Token token) { |
1351 Token peek = token.next; | 1481 Token peek = token.next; |
1352 if (identical(peek.kind, PERIOD_TOKEN)) { | 1482 if (identical(peek.kind, PERIOD_TOKEN)) { |
1353 if (peek.next.isIdentifier()) { | 1483 if (peek.next.isIdentifier()) { |
1354 // Look past a library prefix. | 1484 // Look past a library prefix. |
1355 peek = peek.next.next; | 1485 peek = peek.next.next; |
1356 } | 1486 } |
1357 } | 1487 } |
1358 // We are looking at "qualified ...". | 1488 // We are looking at "qualified ...". |
1359 if (identical(peek.kind, LT_TOKEN)) { | 1489 if (identical(peek.kind, LT_TOKEN)) { |
1360 // Possibly generic type. | 1490 // Possibly generic type. |
1361 // We are looking at "qualified '<'". | 1491 // We are looking at "qualified '<'". |
1362 BeginGroupToken beginGroupToken = peek; | 1492 BeginGroupToken beginGroupToken = peek; |
1363 Token gtToken = beginGroupToken.endGroup; | 1493 Token gtToken = beginGroupToken.endGroup; |
1364 if (gtToken != null) { | 1494 if (gtToken != null) { |
1365 // We are looking at "qualified '<' ... '>' ...". | 1495 // We are looking at "qualified '<' ... '>' ...". |
1366 return gtToken.next; | 1496 peek = gtToken.next; |
1367 } | 1497 } |
1368 } | 1498 } |
1369 return peek; | 1499 return peek; |
1370 } | 1500 } |
1371 | 1501 |
1372 /** | 1502 /** |
| 1503 * Returns the first token after the function type starting at [token]. |
| 1504 * |
| 1505 * The token must be at the `Function` token position. That is, the return |
| 1506 * type must have already been skipped. |
| 1507 * |
| 1508 * This function only skips over one function type syntax. |
| 1509 * If necessary, this function must be called multiple times. |
| 1510 * |
| 1511 * Example: |
| 1512 * ``` |
| 1513 * int Function() Function<T>(int) |
| 1514 * ^ ^ |
| 1515 * A call to this function must be at one of the `Function` tokens. |
| 1516 * If `token` pointed to the first `Function` token, then the returned |
| 1517 * token points to the second `Function` token. |
| 1518 */ |
| 1519 Token peekAfterFunctionType(Token token) { |
| 1520 // Possible inputs are: |
| 1521 // Function( ... ) |
| 1522 // Function< ... >( ... ) |
| 1523 |
| 1524 Token peek = token.next; // Skip over the Function token. |
| 1525 // If there is a generic argument to the function, skip over that one first. |
| 1526 if (identical(peek.kind, LT_TOKEN)) { |
| 1527 BeginGroupToken beginGroupToken = peek; |
| 1528 Token closeToken = beginGroupToken.endGroup; |
| 1529 if (closeToken != null) { |
| 1530 peek = closeToken.next; |
| 1531 } |
| 1532 } |
| 1533 |
| 1534 // Now we just need to skip over the formals. |
| 1535 expect('(', peek); |
| 1536 |
| 1537 BeginGroupToken beginGroupToken = peek; |
| 1538 Token closeToken = beginGroupToken.endGroup; |
| 1539 if (closeToken != null) { |
| 1540 peek = closeToken.next; |
| 1541 } |
| 1542 |
| 1543 return peek; |
| 1544 } |
| 1545 |
| 1546 /** |
1373 * If [token] is the start of a type, returns the token after that type. | 1547 * If [token] is the start of a type, returns the token after that type. |
1374 * If [token] is not the start of a type, null is returned. | 1548 * If [token] is not the start of a type, null is returned. |
1375 */ | 1549 */ |
1376 Token peekAfterIfType(Token token) { | 1550 Token peekAfterIfType(Token token) { |
1377 if (!optional('void', token) && !token.isIdentifier()) { | 1551 if (!optional('void', token) && !token.isIdentifier()) { |
1378 return null; | 1552 return null; |
1379 } | 1553 } |
1380 return peekAfterType(token); | 1554 return peekAfterType(token); |
1381 } | 1555 } |
1382 | 1556 |
(...skipping 1929 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3312 break; | 3486 break; |
3313 } | 3487 } |
3314 if (isRecoverable) { | 3488 if (isRecoverable) { |
3315 listener.handleRecoverableError(token, kind, arguments); | 3489 listener.handleRecoverableError(token, kind, arguments); |
3316 return null; | 3490 return null; |
3317 } else { | 3491 } else { |
3318 return listener.handleUnrecoverableError(token, kind, arguments); | 3492 return listener.handleUnrecoverableError(token, kind, arguments); |
3319 } | 3493 } |
3320 } | 3494 } |
3321 } | 3495 } |
OLD | NEW |