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 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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.beginFunctionTypeAlias(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.endFunctionTypeAlias(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; |
403 } | 412 } |
404 | 413 |
405 Token parseReturnTypeOpt(Token token) { | 414 Token parseReturnTypeOpt(Token token) { |
406 if (identical(token.stringValue, 'void')) { | 415 if (identical(token.stringValue, 'void')) { |
407 listener.handleVoidKeyword(token); | 416 if (isGeneralizedFunctionType(token.next)) { |
408 return token.next; | 417 return parseType(token); |
| 418 } else { |
| 419 listener.handleVoidKeyword(token); |
| 420 return token.next; |
| 421 } |
409 } else { | 422 } else { |
410 return parseTypeOpt(token); | 423 return parseTypeOpt(token); |
411 } | 424 } |
412 } | 425 } |
413 | 426 |
414 Token parseFormalParametersOpt(Token token) { | 427 Token parseFormalParametersOpt(Token token) { |
415 if (optional('(', token)) { | 428 if (optional('(', token)) { |
416 return parseFormalParameters(token); | 429 return parseFormalParameters(token); |
417 } else { | 430 } else { |
418 listener.handleNoFormalParameters(token); | 431 listener.handleNoFormalParameters(token); |
(...skipping 11 matching lines...) Expand all Loading... |
430 } | 443 } |
431 return reportUnrecoverableError( | 444 return reportUnrecoverableError( |
432 token, ErrorKind.ExpectedButGot, {"expected": "("}); | 445 token, ErrorKind.ExpectedButGot, {"expected": "("}); |
433 } | 446 } |
434 BeginGroupToken beginGroupToken = token; | 447 BeginGroupToken beginGroupToken = token; |
435 Token endToken = beginGroupToken.endGroup; | 448 Token endToken = beginGroupToken.endGroup; |
436 listener.endFormalParameters(0, token, endToken); | 449 listener.endFormalParameters(0, token, endToken); |
437 return endToken.next; | 450 return endToken.next; |
438 } | 451 } |
439 | 452 |
440 Token parseFormalParameters(Token token) { | 453 /// Parses the formal parameter list of a function. |
| 454 /// |
| 455 /// If [inFunctionType] is true, then the names may be omitted (except for |
| 456 /// named arguments). If it is false, then the types may be omitted. |
| 457 Token parseFormalParameters(Token token, {bool inFunctionType: false}) { |
441 Token begin = token; | 458 Token begin = token; |
442 listener.beginFormalParameters(begin); | 459 listener.beginFormalParameters(begin); |
443 expect('(', token); | 460 expect('(', token); |
444 int parameterCount = 0; | 461 int parameterCount = 0; |
445 do { | 462 do { |
446 token = token.next; | 463 token = token.next; |
447 if (optional(')', token)) { | 464 if (optional(')', token)) { |
448 break; | 465 break; |
449 } | 466 } |
450 ++parameterCount; | 467 ++parameterCount; |
451 String value = token.stringValue; | 468 String value = token.stringValue; |
452 if (identical(value, '[')) { | 469 if (identical(value, '[')) { |
453 token = parseOptionalFormalParameters(token, false); | 470 token = parseOptionalFormalParameters( |
| 471 token, false, inFunctionType: inFunctionType); |
454 break; | 472 break; |
455 } else if (identical(value, '{')) { | 473 } else if (identical(value, '{')) { |
456 token = parseOptionalFormalParameters(token, true); | 474 token = parseOptionalFormalParameters( |
| 475 token, true, inFunctionType: inFunctionType); |
457 break; | 476 break; |
458 } | 477 } |
459 token = parseFormalParameter(token, FormalParameterType.REQUIRED); | 478 token = parseFormalParameter(token, FormalParameterType.REQUIRED, |
| 479 inFunctionType: inFunctionType); |
460 } while (optional(',', token)); | 480 } while (optional(',', token)); |
461 listener.endFormalParameters(parameterCount, begin, token); | 481 listener.endFormalParameters(parameterCount, begin, token); |
462 return expect(')', token); | 482 return expect(')', token); |
463 } | 483 } |
464 | 484 |
465 Token parseFormalParameter(Token token, FormalParameterType type) { | 485 Token parseFormalParameter(Token token, FormalParameterType type, |
| 486 {bool inFunctionType: false}) { |
466 token = parseMetadataStar(token, forParameter: true); | 487 token = parseMetadataStar(token, forParameter: true); |
467 listener.beginFormalParameter(token); | 488 listener.beginFormalParameter(token); |
468 | 489 |
469 // Skip over `covariant` token, if the next token is an identifier or | 490 // Skip over `covariant` token, if the next token is an identifier or |
470 // modifier. | 491 // modifier. |
471 // This enables the case where `covariant` is the name of the parameter: | 492 // This enables the case where `covariant` is the name of the parameter: |
472 // void foo(covariant); | 493 // void foo(covariant); |
473 if (identical(token.stringValue, 'covariant') && | 494 if (identical(token.stringValue, 'covariant') && |
474 (token.next.isIdentifier() || isModifier(token.next))) { | 495 (token.next.isIdentifier() || isModifier(token.next))) { |
475 token = token.next; | 496 token = token.next; |
476 } | 497 } |
477 token = parseModifiers(token); | 498 token = parseModifiers(token); |
478 // TODO(ahe): Validate that there are formal parameters if void. | 499 bool isNamedParameter = type == FormalParameterType.NAMED; |
479 token = parseReturnTypeOpt(token); | 500 |
480 Token thisKeyword = null; | 501 Token thisKeyword = null; |
481 if (optional('this', token)) { | 502 if (inFunctionType && isNamedParameter) { |
482 thisKeyword = token; | 503 token = parseType(token); |
483 // TODO(ahe): Validate field initializers are only used in | 504 token = parseIdentifier(token); |
484 // constructors, and not for function-typed arguments. | 505 } else if (inFunctionType) { |
485 token = expect('.', token.next); | 506 token = parseType(token); |
| 507 if (token.isIdentifier()) { |
| 508 token = parseIdentifier(token); |
| 509 } else { |
| 510 listener.handleNoName(token); |
| 511 } |
| 512 } else { |
| 513 token = parseReturnTypeOpt(token); |
| 514 if (optional('this', token)) { |
| 515 thisKeyword = token; |
| 516 token = expect('.', token.next); |
| 517 } |
| 518 token = parseIdentifier(token); |
486 } | 519 } |
487 token = parseIdentifier(token); | 520 |
| 521 // Generalized function types don't allow inline function types. |
| 522 // The following isn't allowed: |
| 523 // int Function(int bar(String x)). |
488 if (optional('(', token)) { | 524 if (optional('(', token)) { |
| 525 Token inlineFunctionTypeStart = token; |
489 listener.beginFunctionTypedFormalParameter(token); | 526 listener.beginFunctionTypedFormalParameter(token); |
490 listener.handleNoTypeVariables(token); | 527 listener.handleNoTypeVariables(token); |
491 token = parseFormalParameters(token); | 528 token = parseFormalParameters(token); |
492 listener.endFunctionTypedFormalParameter(token); | 529 listener.endFunctionTypedFormalParameter(token); |
| 530 if (inFunctionType) { |
| 531 reportRecoverableError( |
| 532 inlineFunctionTypeStart, ErrorKind.InvalidInlineFunctionType); |
| 533 } |
493 } else if (optional('<', token)) { | 534 } else if (optional('<', token)) { |
| 535 Token inlineFunctionTypeStart = token; |
494 listener.beginFunctionTypedFormalParameter(token); | 536 listener.beginFunctionTypedFormalParameter(token); |
495 token = parseTypeVariablesOpt(token); | 537 token = parseTypeVariablesOpt(token); |
496 token = parseFormalParameters(token); | 538 token = parseFormalParameters(token); |
497 listener.endFunctionTypedFormalParameter(token); | 539 listener.endFunctionTypedFormalParameter(token); |
| 540 if (inFunctionType) { |
| 541 reportRecoverableError( |
| 542 inlineFunctionTypeStart, ErrorKind.InvalidInlineFunctionType); |
| 543 } |
498 } | 544 } |
499 String value = token.stringValue; | 545 String value = token.stringValue; |
500 if ((identical('=', value)) || (identical(':', value))) { | 546 if ((identical('=', value)) || (identical(':', value))) { |
501 // TODO(ahe): Validate that these are only used for optional parameters. | 547 // TODO(ahe): Validate that these are only used for optional parameters. |
502 Token equal = token; | 548 Token equal = token; |
503 token = parseExpression(token.next); | 549 token = parseExpression(token.next); |
504 listener.handleValuedFormalParameter(equal, token); | 550 listener.handleValuedFormalParameter(equal, token); |
505 if (type.isRequired) { | 551 if (type.isRequired) { |
506 reportRecoverableError( | 552 reportRecoverableError( |
507 equal, ErrorKind.RequiredParameterWithDefault); | 553 equal, ErrorKind.RequiredParameterWithDefault); |
508 } else if (type.isPositional && identical(':', value)) { | 554 } else if (type.isPositional && identical(':', value)) { |
509 reportRecoverableError( | 555 reportRecoverableError( |
510 equal, ErrorKind.PositionalParameterWithEquals); | 556 equal, ErrorKind.PositionalParameterWithEquals); |
511 } | 557 } |
512 } | 558 } |
513 listener.endFormalParameter(thisKeyword); | 559 listener.endFormalParameter(thisKeyword); |
514 return token; | 560 return token; |
515 } | 561 } |
516 | 562 |
517 Token parseOptionalFormalParameters(Token token, bool isNamed) { | 563 Token parseOptionalFormalParameters(Token token, bool isNamed, |
| 564 {bool inFunctionType: false}) { |
518 Token begin = token; | 565 Token begin = token; |
519 listener.beginOptionalFormalParameters(begin); | 566 listener.beginOptionalFormalParameters(begin); |
520 assert((isNamed && optional('{', token)) || optional('[', token)); | 567 assert((isNamed && optional('{', token)) || optional('[', token)); |
521 int parameterCount = 0; | 568 int parameterCount = 0; |
522 do { | 569 do { |
523 token = token.next; | 570 token = token.next; |
524 if (isNamed && optional('}', token)) { | 571 if (isNamed && optional('}', token)) { |
525 break; | 572 break; |
526 } else if (!isNamed && optional(']', token)) { | 573 } else if (!isNamed && optional(']', token)) { |
527 break; | 574 break; |
528 } | 575 } |
529 var type = | 576 var type = |
530 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; | 577 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; |
531 token = parseFormalParameter(token, type); | 578 token = |
| 579 parseFormalParameter(token, type, inFunctionType: inFunctionType); |
532 ++parameterCount; | 580 ++parameterCount; |
533 } while (optional(',', token)); | 581 } while (optional(',', token)); |
534 if (parameterCount == 0) { | 582 if (parameterCount == 0) { |
535 reportRecoverableError( | 583 reportRecoverableError( |
536 token, | 584 token, |
537 isNamed | 585 isNamed |
538 ? ErrorKind.EmptyNamedParameterList | 586 ? ErrorKind.EmptyNamedParameterList |
539 : ErrorKind.EmptyOptionalParameterList); | 587 : ErrorKind.EmptyOptionalParameterList); |
540 } | 588 } |
541 listener.endOptionalFormalParameters(parameterCount, begin, token); | 589 listener.endOptionalFormalParameters(parameterCount, begin, token); |
542 if (isNamed) { | 590 if (isNamed) { |
543 return expect('}', token); | 591 return expect('}', token); |
544 } else { | 592 } else { |
545 return expect(']', token); | 593 return expect(']', token); |
546 } | 594 } |
547 } | 595 } |
548 | 596 |
549 Token parseTypeOpt(Token token) { | 597 Token parseTypeOpt(Token token) { |
| 598 if (isGeneralizedFunctionType(token)) { |
| 599 // Function type without return type. |
| 600 return parseType(token); |
| 601 } |
550 Token peek = peekAfterIfType(token); | 602 Token peek = peekAfterIfType(token); |
551 if (peek != null && (peek.isIdentifier() || optional('this', peek))) { | 603 if (peek != null && (peek.isIdentifier() || optional('this', peek))) { |
552 return parseType(token); | 604 return parseType(token); |
553 } | 605 } |
554 listener.handleNoType(token); | 606 listener.handleNoType(token); |
555 return token; | 607 return token; |
556 } | 608 } |
557 | 609 |
558 bool isValidTypeReference(Token token) { | 610 bool isValidTypeReference(Token token) { |
559 final kind = token.kind; | 611 final kind = token.kind; |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
714 token = token.next; | 766 token = token.next; |
715 classKeyword = token; | 767 classKeyword = token; |
716 } | 768 } |
717 assert(optional('class', classKeyword)); | 769 assert(optional('class', classKeyword)); |
718 int modifierCount = 0; | 770 int modifierCount = 0; |
719 if (abstractKeyword != null) { | 771 if (abstractKeyword != null) { |
720 parseModifier(abstractKeyword); | 772 parseModifier(abstractKeyword); |
721 modifierCount++; | 773 modifierCount++; |
722 } | 774 } |
723 listener.handleModifiers(modifierCount); | 775 listener.handleModifiers(modifierCount); |
724 bool isMixinApplication = optional('=', peekAfterType(token)); | 776 bool isMixinApplication = optional('=', peekAfterNominalType(token)); |
725 Token name = token.next; | 777 Token name = token.next; |
726 token = parseIdentifier(name); | 778 token = parseIdentifier(name); |
727 | 779 |
728 if (isMixinApplication) { | 780 if (isMixinApplication) { |
729 listener.beginNamedMixinApplication(begin, name); | 781 listener.beginNamedMixinApplication(begin, name); |
730 } else { | 782 } else { |
731 listener.beginClassDeclaration(begin, name); | 783 listener.beginClassDeclaration(begin, name); |
732 } | 784 } |
733 | 785 |
734 token = parseTypeVariablesOpt(token); | 786 token = parseTypeVariablesOpt(token); |
(...skipping 18 matching lines...) Expand all Loading... |
753 } | 805 } |
754 listener.endNamedMixinApplication(begin, classKeyword, equals, | 806 listener.endNamedMixinApplication(begin, classKeyword, equals, |
755 implementsKeyword, token); | 807 implementsKeyword, token); |
756 return expect(';', token); | 808 return expect(';', token); |
757 } | 809 } |
758 | 810 |
759 Token parseClass(Token token, Token begin, Token classKeyword, Token name) { | 811 Token parseClass(Token token, Token begin, Token classKeyword, Token name) { |
760 Token extendsKeyword; | 812 Token extendsKeyword; |
761 if (optional('extends', token)) { | 813 if (optional('extends', token)) { |
762 extendsKeyword = token; | 814 extendsKeyword = token; |
763 if (optional('with', peekAfterType(token.next))) { | 815 if (optional('with', peekAfterNominalType(token.next))) { |
764 token = parseMixinApplication(token.next); | 816 token = parseMixinApplication(token.next); |
765 } else { | 817 } else { |
766 token = parseType(token.next); | 818 token = parseType(token.next); |
767 } | 819 } |
768 } else { | 820 } else { |
769 extendsKeyword = null; | 821 extendsKeyword = null; |
770 listener.handleNoType(token); | 822 listener.handleNoType(token); |
771 } | 823 } |
772 Token implementsKeyword; | 824 Token implementsKeyword; |
773 int interfacesCount = 0; | 825 int interfacesCount = 0; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
845 value2 == stringValue || | 897 value2 == stringValue || |
846 value3 == stringValue || | 898 value3 == stringValue || |
847 value4 == stringValue; | 899 value4 == stringValue; |
848 } | 900 } |
849 | 901 |
850 bool notEofOrValue(String value, Token token) { | 902 bool notEofOrValue(String value, Token token) { |
851 return !identical(token.kind, EOF_TOKEN) && | 903 return !identical(token.kind, EOF_TOKEN) && |
852 !identical(value, token.stringValue); | 904 !identical(value, token.stringValue); |
853 } | 905 } |
854 | 906 |
| 907 bool isGeneralizedFunctionType(Token token) { |
| 908 return optional('Function', token) && |
| 909 (optional('<', token.next) || optional('(', token.next)); |
| 910 } |
| 911 |
855 Token parseType(Token token) { | 912 Token parseType(Token token) { |
856 Token begin = token; | 913 Token begin = token; |
857 if (isValidTypeReference(token)) { | 914 if (isGeneralizedFunctionType(token)) { |
858 token = parseIdentifier(token); | 915 // A function type without return type. |
859 token = parseQualifiedRestOpt(token); | 916 // Push the non-existing return type first. The loop below will |
| 917 // generate the full type. |
| 918 listener.handleNoType(token); |
| 919 } else if (identical(token.stringValue, 'void') && |
| 920 isGeneralizedFunctionType(token.next)) { |
| 921 listener.handleVoidKeyword(token); |
| 922 token = token.next; |
860 } else { | 923 } else { |
861 token = reportUnrecoverableError(token, ErrorKind.ExpectedType); | 924 if (isValidTypeReference(token)) { |
862 listener.handleInvalidTypeReference(token); | 925 token = parseIdentifier(token); |
| 926 token = parseQualifiedRestOpt(token); |
| 927 } else { |
| 928 token = reportUnrecoverableError(token, ErrorKind.ExpectedType); |
| 929 listener.handleInvalidTypeReference(token); |
| 930 } |
| 931 token = parseTypeArgumentsOpt(token); |
| 932 listener.handleType(begin, token); |
863 } | 933 } |
864 token = parseTypeArgumentsOpt(token); | 934 |
865 listener.endType(begin, token); | 935 // While we see a `Function(` treat the pushed type as return type. |
| 936 // For example: `int Function() Function(int) Function(String x)`. |
| 937 while (isGeneralizedFunctionType(token)) { |
| 938 token = parseFunctionType(token); |
| 939 } |
866 return token; | 940 return token; |
867 } | 941 } |
868 | 942 |
| 943 /// Parses a generalized function type. |
| 944 /// |
| 945 /// The return type must already be pushed. |
| 946 Token parseFunctionType(Token token) { |
| 947 assert(optional('Function', token)); |
| 948 Token functionToken = token; |
| 949 token = token.next; |
| 950 token = parseTypeVariablesOpt(token); |
| 951 token = parseFormalParameters(token, inFunctionType: true); |
| 952 listener.handleFunctionType(functionToken, token); |
| 953 return token; |
| 954 } |
| 955 |
869 Token parseTypeArgumentsOpt(Token token) { | 956 Token parseTypeArgumentsOpt(Token token) { |
870 return parseStuff( | 957 return parseStuff( |
871 token, | 958 token, |
872 (t) => listener.beginTypeArguments(t), | 959 (t) => listener.beginTypeArguments(t), |
873 (t) => parseType(t), | 960 (t) => parseType(t), |
874 (c, bt, et) => listener.endTypeArguments(c, bt, et), | 961 (c, bt, et) => listener.endTypeArguments(c, bt, et), |
875 (t) => listener.handleNoTypeArguments(t)); | 962 (t) => listener.handleNoTypeArguments(t)); |
876 } | 963 } |
877 | 964 |
878 Token parseTypeVariablesOpt(Token token) { | 965 Token parseTypeVariablesOpt(Token token) { |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1075 | 1162 |
1076 if (getOrSet != null) { | 1163 if (getOrSet != null) { |
1077 var kind = (hasModifier || hasType) | 1164 var kind = (hasModifier || hasType) |
1078 ? ErrorKind.ExtraneousModifier | 1165 ? ErrorKind.ExtraneousModifier |
1079 : ErrorKind.ExtraneousModifierReplace; | 1166 : ErrorKind.ExtraneousModifierReplace; |
1080 reportRecoverableError(getOrSet, kind, {'modifier': getOrSet}); | 1167 reportRecoverableError(getOrSet, kind, {'modifier': getOrSet}); |
1081 } | 1168 } |
1082 | 1169 |
1083 if (!hasType) { | 1170 if (!hasType) { |
1084 listener.handleNoType(name); | 1171 listener.handleNoType(name); |
1085 } else if (optional('void', type)) { | 1172 } else if (optional('void', type) && |
| 1173 !isGeneralizedFunctionType(type.next)) { |
1086 listener.handleNoType(name); | 1174 listener.handleNoType(name); |
1087 // TODO(ahe): This error is reported twice, second time is from | 1175 // TODO(ahe): This error is reported twice, second time is from |
1088 // [parseVariablesDeclarationMaybeSemicolon] via | 1176 // [parseVariablesDeclarationMaybeSemicolon] via |
1089 // [PartialFieldListElement.parseNode]. | 1177 // [PartialFieldListElement.parseNode]. |
1090 reportRecoverableError(type, ErrorKind.InvalidVoid); | 1178 reportRecoverableError(type, ErrorKind.InvalidVoid); |
1091 } else { | 1179 } else { |
1092 parseType(type); | 1180 parseType(type); |
1093 if (isVar) { | 1181 if (isVar) { |
1094 reportRecoverableError(modifiers.head, ErrorKind.ExtraneousModifier, | 1182 reportRecoverableError(modifiers.head, ErrorKind.ExtraneousModifier, |
1095 {'modifier': modifiers.head}); | 1183 {'modifier': modifiers.head}); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1211 return listener.handleMemberName(identifiers); | 1299 return listener.handleMemberName(identifiers); |
1212 } else if (optional("=", token) || optional(";", token) || | 1300 } else if (optional("=", token) || optional(";", token) || |
1213 optional(",", token)) { | 1301 optional(",", token)) { |
1214 // A field or abstract getter. | 1302 // A field or abstract getter. |
1215 identifiers = identifiers.prepend(token); | 1303 identifiers = identifiers.prepend(token); |
1216 return listener.handleMemberName(identifiers); | 1304 return listener.handleMemberName(identifiers); |
1217 } else if (isGetter) { | 1305 } else if (isGetter) { |
1218 hasName = true; | 1306 hasName = true; |
1219 } | 1307 } |
1220 identifiers = identifiers.prepend(token); | 1308 identifiers = identifiers.prepend(token); |
1221 if (isValidTypeReference(token)) { | 1309 |
1222 // type ... | 1310 if (!isGeneralizedFunctionType(token)) { |
1223 if (optional('.', token.next)) { | 1311 // Read a potential return type. |
1224 // type '.' ... | 1312 if (isValidTypeReference(token)) { |
1225 if (token.next.next.isIdentifier()) { | 1313 // type ... |
1226 // type '.' identifier | 1314 if (optional('.', token.next)) { |
1227 token = token.next.next; | 1315 // type '.' ... |
| 1316 if (token.next.next.isIdentifier()) { |
| 1317 // type '.' identifier |
| 1318 token = token.next.next; |
| 1319 } |
| 1320 } |
| 1321 if (optional('<', token.next)) { |
| 1322 if (token.next is BeginGroupToken) { |
| 1323 BeginGroupToken beginGroup = token.next; |
| 1324 if (beginGroup.endGroup == null) { |
| 1325 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); |
| 1326 } else { |
| 1327 token = beginGroup.endGroup; |
| 1328 } |
| 1329 } |
1228 } | 1330 } |
1229 } | 1331 } |
1230 if (optional('<', token.next)) { | 1332 token = token.next; |
1231 if (token.next is BeginGroupToken) { | 1333 } |
1232 BeginGroupToken beginGroup = token.next; | 1334 while (isGeneralizedFunctionType(token)) { |
| 1335 token = token.next; |
| 1336 if (optional('<', token)) { |
| 1337 if (token is BeginGroupToken) { |
| 1338 BeginGroupToken beginGroup = token; |
1233 if (beginGroup.endGroup == null) { | 1339 if (beginGroup.endGroup == null) { |
1234 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); | 1340 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); |
1235 } else { | 1341 } else { |
1236 token = beginGroup.endGroup; | 1342 token = beginGroup.endGroup.next; |
1237 } | 1343 } |
1238 } | 1344 } |
1239 } | 1345 } |
| 1346 if (!optional('(', token)) { |
| 1347 if (optional(';', token)) { |
| 1348 reportRecoverableError(token, ErrorKind.ExpectedOpenParens); |
| 1349 } |
| 1350 token = expect("(", token); |
| 1351 } |
| 1352 if (token is BeginGroupToken) { |
| 1353 BeginGroupToken beginGroup = token; |
| 1354 if (beginGroup.endGroup == null) { |
| 1355 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); |
| 1356 } else { |
| 1357 token = beginGroup.endGroup.next; |
| 1358 } |
| 1359 } |
1240 } | 1360 } |
1241 token = token.next; | |
1242 } | 1361 } |
1243 return listener.handleMemberName(const Link<Token>()); | 1362 return listener.handleMemberName(const Link<Token>()); |
1244 } | 1363 } |
1245 | 1364 |
1246 Token parseFieldInitializerOpt(Token token) { | 1365 Token parseFieldInitializerOpt(Token token) { |
1247 if (optional('=', token)) { | 1366 if (optional('=', token)) { |
1248 Token assignment = token; | 1367 Token assignment = token; |
1249 listener.beginFieldInitializer(token); | 1368 listener.beginFieldInitializer(token); |
1250 token = parseExpression(token.next); | 1369 token = parseExpression(token.next); |
1251 listener.endFieldInitializer(assignment); | 1370 listener.endFieldInitializer(assignment); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1346 if (!isModifier(token)) break; | 1465 if (!isModifier(token)) break; |
1347 token = parseModifier(token); | 1466 token = parseModifier(token); |
1348 count++; | 1467 count++; |
1349 } | 1468 } |
1350 listener.handleModifiers(count); | 1469 listener.handleModifiers(count); |
1351 return token; | 1470 return token; |
1352 } | 1471 } |
1353 | 1472 |
1354 /** | 1473 /** |
1355 * Returns the first token after the type starting at [token]. | 1474 * Returns the first token after the type starting at [token]. |
| 1475 * |
1356 * This method assumes that [token] is an identifier (or void). | 1476 * This method assumes that [token] is an identifier (or void). |
1357 * Use [peekAfterIfType] if [token] isn't known to be an identifier. | 1477 * Use [peekAfterIfType] if [token] isn't known to be an identifier. |
1358 */ | 1478 */ |
1359 Token peekAfterType(Token token) { | 1479 Token peekAfterType(Token token) { |
1360 // We are looking at "identifier ...". | 1480 // We are looking at "identifier ...". |
| 1481 Token peek = token; |
| 1482 if (!isGeneralizedFunctionType(token)) { |
| 1483 peek = peekAfterNominalType(token); |
| 1484 } |
| 1485 |
| 1486 // We might have just skipped over the return value of the function type. |
| 1487 // Check again, if we are now at a function type position. |
| 1488 while (isGeneralizedFunctionType(peek)) { |
| 1489 peek = peekAfterFunctionType(peek.next); |
| 1490 } |
| 1491 return peek; |
| 1492 } |
| 1493 |
| 1494 /** |
| 1495 * Returns the first token after the nominal type starting at [token]. |
| 1496 * |
| 1497 * This method assumes that [token] is an identifier (or void). |
| 1498 */ |
| 1499 Token peekAfterNominalType(Token token) { |
1361 Token peek = token.next; | 1500 Token peek = token.next; |
1362 if (identical(peek.kind, PERIOD_TOKEN)) { | 1501 if (identical(peek.kind, PERIOD_TOKEN)) { |
1363 if (peek.next.isIdentifier()) { | 1502 if (peek.next.isIdentifier()) { |
1364 // Look past a library prefix. | 1503 // Look past a library prefix. |
1365 peek = peek.next.next; | 1504 peek = peek.next.next; |
1366 } | 1505 } |
1367 } | 1506 } |
1368 // We are looking at "qualified ...". | 1507 // We are looking at "qualified ...". |
1369 if (identical(peek.kind, LT_TOKEN)) { | 1508 if (identical(peek.kind, LT_TOKEN)) { |
1370 // Possibly generic type. | 1509 // Possibly generic type. |
1371 // We are looking at "qualified '<'". | 1510 // We are looking at "qualified '<'". |
1372 BeginGroupToken beginGroupToken = peek; | 1511 BeginGroupToken beginGroupToken = peek; |
1373 Token gtToken = beginGroupToken.endGroup; | 1512 Token gtToken = beginGroupToken.endGroup; |
1374 if (gtToken != null) { | 1513 if (gtToken != null) { |
1375 // We are looking at "qualified '<' ... '>' ...". | 1514 // We are looking at "qualified '<' ... '>' ...". |
1376 return gtToken.next; | 1515 peek = gtToken.next; |
1377 } | 1516 } |
1378 } | 1517 } |
1379 return peek; | 1518 return peek; |
1380 } | 1519 } |
1381 | 1520 |
| 1521 /** |
| 1522 * Returns the first token after the function type starting at [token]. |
| 1523 * |
| 1524 * The token must be at the token *after* the `Function` token position. That |
| 1525 * is, the return type and the `Function` token must have already been |
| 1526 * skipped. |
| 1527 * |
| 1528 * This function only skips over one function type syntax. |
| 1529 * If necessary, this function must be called multiple times. |
| 1530 * |
| 1531 * Example: |
| 1532 * ``` |
| 1533 * int Function() Function<T>(int) |
| 1534 * ^ ^ |
| 1535 * A call to this function must be either at `(` or at `<`. |
| 1536 * If `token` pointed to the first `(`, then the returned |
| 1537 * token points to the second `Function` token. |
| 1538 */ |
| 1539 Token peekAfterFunctionType(Token token) { |
| 1540 // Possible inputs are: |
| 1541 // ( ... ) |
| 1542 // < ... >( ... ) |
| 1543 |
| 1544 Token peek = token; |
| 1545 // If there is a generic argument to the function, skip over that one first. |
| 1546 if (identical(peek.kind, LT_TOKEN)) { |
| 1547 BeginGroupToken beginGroupToken = peek; |
| 1548 Token closeToken = beginGroupToken.endGroup; |
| 1549 if (closeToken != null) { |
| 1550 peek = closeToken.next; |
| 1551 } |
| 1552 } |
| 1553 |
| 1554 // Now we just need to skip over the formals. |
| 1555 expect('(', peek); |
| 1556 |
| 1557 BeginGroupToken beginGroupToken = peek; |
| 1558 Token closeToken = beginGroupToken.endGroup; |
| 1559 if (closeToken != null) { |
| 1560 peek = closeToken.next; |
| 1561 } |
| 1562 |
| 1563 return peek; |
| 1564 } |
| 1565 |
1382 /** | 1566 /** |
1383 * If [token] is the start of a type, returns the token after that type. | 1567 * If [token] is the start of a type, returns the token after that type. |
1384 * If [token] is not the start of a type, null is returned. | 1568 * If [token] is not the start of a type, null is returned. |
1385 */ | 1569 */ |
1386 Token peekAfterIfType(Token token) { | 1570 Token peekAfterIfType(Token token) { |
1387 if (!optional('void', token) && !token.isIdentifier()) { | 1571 if (!optional('void', token) && !token.isIdentifier()) { |
1388 return null; | 1572 return null; |
1389 } | 1573 } |
1390 return peekAfterType(token); | 1574 return peekAfterType(token); |
1391 } | 1575 } |
(...skipping 1931 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3323 break; | 3507 break; |
3324 } | 3508 } |
3325 if (isRecoverable) { | 3509 if (isRecoverable) { |
3326 listener.handleRecoverableError(token, kind, arguments); | 3510 listener.handleRecoverableError(token, kind, arguments); |
3327 return null; | 3511 return null; |
3328 } else { | 3512 } else { |
3329 return listener.handleUnrecoverableError(token, kind, arguments); | 3513 return listener.handleUnrecoverableError(token, kind, arguments); |
3330 } | 3514 } |
3331 } | 3515 } |
3332 } | 3516 } |
OLD | NEW |