Chromium Code Reviews| 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; |
| 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}) { | |
| 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}) { | |
| 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 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 706 } | 758 } |
| 707 | 759 |
| 708 Token parseClassOrNamedMixinApplication(Token token) { | 760 Token parseClassOrNamedMixinApplication(Token token) { |
| 709 Token begin = token; | 761 Token begin = token; |
| 710 Token abstractKeyword; | 762 Token abstractKeyword; |
| 711 if (optional('abstract', token)) { | 763 if (optional('abstract', token)) { |
| 712 abstractKeyword = token; | 764 abstractKeyword = token; |
| 713 token = token.next; | 765 token = token.next; |
| 714 } | 766 } |
| 715 Token classKeyword = token; | 767 Token classKeyword = token; |
| 716 var isMixinApplication = optional('=', peekAfterType(token.next)); | 768 var isMixinApplication = optional('=', peekAfterNominalType(token.next)); |
| 717 if (isMixinApplication) { | 769 if (isMixinApplication) { |
| 718 listener.beginNamedMixinApplication(begin); | 770 listener.beginNamedMixinApplication(begin); |
| 719 } else { | 771 } else { |
| 720 listener.beginClassDeclaration(begin); | 772 listener.beginClassDeclaration(begin); |
| 721 } | 773 } |
| 722 | 774 |
| 723 int modifierCount = 0; | 775 int modifierCount = 0; |
| 724 if (abstractKeyword != null) { | 776 if (abstractKeyword != null) { |
| 725 parseModifier(abstractKeyword); | 777 parseModifier(abstractKeyword); |
| 726 modifierCount++; | 778 modifierCount++; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 747 listener.endNamedMixinApplication(classKeyword, implementsKeyword, token); | 799 listener.endNamedMixinApplication(classKeyword, implementsKeyword, token); |
| 748 return expect(';', token); | 800 return expect(';', token); |
| 749 } | 801 } |
| 750 | 802 |
| 751 Token parseClass(Token begin, Token classKeyword) { | 803 Token parseClass(Token begin, Token classKeyword) { |
| 752 Token token = parseIdentifier(classKeyword.next); | 804 Token token = parseIdentifier(classKeyword.next); |
| 753 token = parseTypeVariablesOpt(token); | 805 token = parseTypeVariablesOpt(token); |
| 754 Token extendsKeyword; | 806 Token extendsKeyword; |
| 755 if (optional('extends', token)) { | 807 if (optional('extends', token)) { |
| 756 extendsKeyword = token; | 808 extendsKeyword = token; |
| 757 if (optional('with', peekAfterType(token.next))) { | 809 if (optional('with', peekAfterNominalType(token.next))) { |
| 758 token = parseMixinApplication(token.next); | 810 token = parseMixinApplication(token.next); |
| 759 } else { | 811 } else { |
| 760 token = parseType(token.next); | 812 token = parseType(token.next); |
| 761 } | 813 } |
| 762 } else { | 814 } else { |
| 763 extendsKeyword = null; | 815 extendsKeyword = null; |
| 764 listener.handleNoType(token); | 816 listener.handleNoType(token); |
| 765 } | 817 } |
| 766 Token implementsKeyword; | 818 Token implementsKeyword; |
| 767 int interfacesCount = 0; | 819 int interfacesCount = 0; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 838 value2 == stringValue || | 890 value2 == stringValue || |
| 839 value3 == stringValue || | 891 value3 == stringValue || |
| 840 value4 == stringValue; | 892 value4 == stringValue; |
| 841 } | 893 } |
| 842 | 894 |
| 843 bool notEofOrValue(String value, Token token) { | 895 bool notEofOrValue(String value, Token token) { |
| 844 return !identical(token.kind, EOF_TOKEN) && | 896 return !identical(token.kind, EOF_TOKEN) && |
| 845 !identical(value, token.stringValue); | 897 !identical(value, token.stringValue); |
| 846 } | 898 } |
| 847 | 899 |
| 900 bool isGeneralizedFunctionType(Token token) { | |
| 901 return optional('Function', token) && | |
| 902 (optional('<', token.next) || optional('(', token.next)); | |
| 903 } | |
| 904 | |
| 848 Token parseType(Token token) { | 905 Token parseType(Token token) { |
| 849 Token begin = token; | 906 Token begin = token; |
| 850 if (isValidTypeReference(token)) { | 907 if (isGeneralizedFunctionType(token)) { |
| 851 token = parseIdentifier(token); | 908 // A function type without return type. |
| 852 token = parseQualifiedRestOpt(token); | 909 // Push the non-existing return type first. The loop below will |
| 910 // generate the full type. | |
| 911 listener.handleNoType(token); | |
| 912 } else if (identical(token.stringValue, 'void') && | |
| 913 isGeneralizedFunctionType(token.next)) { | |
| 914 listener.handleVoidKeyword(token); | |
| 915 token = token.next; | |
| 853 } else { | 916 } else { |
| 854 token = reportUnrecoverableError(token, ErrorKind.ExpectedType); | 917 if (isValidTypeReference(token)) { |
| 855 listener.handleInvalidTypeReference(token); | 918 token = parseIdentifier(token); |
| 919 token = parseQualifiedRestOpt(token); | |
| 920 } else { | |
| 921 token = reportUnrecoverableError(token, ErrorKind.ExpectedType); | |
| 922 listener.handleInvalidTypeReference(token); | |
| 923 } | |
| 924 token = parseTypeArgumentsOpt(token); | |
| 925 listener.endType(begin, token); | |
| 856 } | 926 } |
| 857 token = parseTypeArgumentsOpt(token); | 927 |
| 858 listener.endType(begin, token); | 928 // While we see a `Function(` treat the pushed type as return type. |
| 929 // For example: `int Function() Function(int) Function(String x)`. | |
| 930 while (isGeneralizedFunctionType(token)) { | |
| 931 token = parseFunctionType(token); | |
| 932 } | |
| 859 return token; | 933 return token; |
| 860 } | 934 } |
| 861 | 935 |
| 936 /// Parses a generalized function type. | |
| 937 /// | |
| 938 /// The return type must already be pushed. | |
| 939 Token parseFunctionType(Token token) { | |
| 940 assert(optional('Function', token)); | |
| 941 Token functionToken = token; | |
| 942 token = token.next; | |
| 943 token = parseTypeVariablesOpt(token); | |
| 944 token = parseFormalParameters(token, inFunctionType: true); | |
| 945 listener.endFunctionType(functionToken, token); | |
| 946 return token; | |
| 947 } | |
| 948 | |
| 862 Token parseTypeArgumentsOpt(Token token) { | 949 Token parseTypeArgumentsOpt(Token token) { |
| 863 return parseStuff( | 950 return parseStuff( |
| 864 token, | 951 token, |
| 865 (t) => listener.beginTypeArguments(t), | 952 (t) => listener.beginTypeArguments(t), |
| 866 (t) => parseType(t), | 953 (t) => parseType(t), |
| 867 (c, bt, et) => listener.endTypeArguments(c, bt, et), | 954 (c, bt, et) => listener.endTypeArguments(c, bt, et), |
| 868 (t) => listener.handleNoTypeArguments(t)); | 955 (t) => listener.handleNoTypeArguments(t)); |
| 869 } | 956 } |
| 870 | 957 |
| 871 Token parseTypeVariablesOpt(Token token) { | 958 Token parseTypeVariablesOpt(Token token) { |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1068 | 1155 |
| 1069 if (getOrSet != null) { | 1156 if (getOrSet != null) { |
| 1070 var kind = (hasModifier || hasType) | 1157 var kind = (hasModifier || hasType) |
| 1071 ? ErrorKind.ExtraneousModifier | 1158 ? ErrorKind.ExtraneousModifier |
| 1072 : ErrorKind.ExtraneousModifierReplace; | 1159 : ErrorKind.ExtraneousModifierReplace; |
| 1073 reportRecoverableError(getOrSet, kind, {'modifier': getOrSet}); | 1160 reportRecoverableError(getOrSet, kind, {'modifier': getOrSet}); |
| 1074 } | 1161 } |
| 1075 | 1162 |
| 1076 if (!hasType) { | 1163 if (!hasType) { |
| 1077 listener.handleNoType(name); | 1164 listener.handleNoType(name); |
| 1078 } else if (optional('void', type)) { | 1165 } else if (optional('void', type) && |
| 1166 !isGeneralizedFunctionType(type.next)) { | |
| 1079 listener.handleNoType(name); | 1167 listener.handleNoType(name); |
| 1080 // TODO(ahe): This error is reported twice, second time is from | 1168 // TODO(ahe): This error is reported twice, second time is from |
| 1081 // [parseVariablesDeclarationMaybeSemicolon] via | 1169 // [parseVariablesDeclarationMaybeSemicolon] via |
| 1082 // [PartialFieldListElement.parseNode]. | 1170 // [PartialFieldListElement.parseNode]. |
| 1083 reportRecoverableError(type, ErrorKind.InvalidVoid); | 1171 reportRecoverableError(type, ErrorKind.InvalidVoid); |
| 1084 } else { | 1172 } else { |
| 1085 parseType(type); | 1173 parseType(type); |
| 1086 if (isVar) { | 1174 if (isVar) { |
| 1087 reportRecoverableError(modifiers.head, ErrorKind.ExtraneousModifier, | 1175 reportRecoverableError(modifiers.head, ErrorKind.ExtraneousModifier, |
| 1088 {'modifier': modifiers.head}); | 1176 {'modifier': modifiers.head}); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1203 return listener.handleMemberName(identifiers); | 1291 return listener.handleMemberName(identifiers); |
| 1204 } else if (optional("=", token) || optional(";", token) || | 1292 } else if (optional("=", token) || optional(";", token) || |
| 1205 optional(",", token)) { | 1293 optional(",", token)) { |
| 1206 // A field or abstract getter. | 1294 // A field or abstract getter. |
| 1207 identifiers = identifiers.prepend(token); | 1295 identifiers = identifiers.prepend(token); |
| 1208 return listener.handleMemberName(identifiers); | 1296 return listener.handleMemberName(identifiers); |
| 1209 } else if (isGetter) { | 1297 } else if (isGetter) { |
| 1210 hasName = true; | 1298 hasName = true; |
| 1211 } | 1299 } |
| 1212 identifiers = identifiers.prepend(token); | 1300 identifiers = identifiers.prepend(token); |
| 1213 if (isValidTypeReference(token)) { | 1301 |
| 1214 // type ... | 1302 if (!isGeneralizedFunctionType(token)) { |
| 1215 if (optional('.', token.next)) { | 1303 // Read a potential return type. |
| 1216 // type '.' ... | 1304 if (isValidTypeReference(token)) { |
| 1217 if (token.next.next.isIdentifier()) { | 1305 // type ... |
| 1218 // type '.' identifier | 1306 if (optional('.', token.next)) { |
| 1219 token = token.next.next; | 1307 // type '.' ... |
| 1308 if (token.next.next.isIdentifier()) { | |
| 1309 // type '.' identifier | |
| 1310 token = token.next.next; | |
| 1311 } | |
| 1312 } | |
| 1313 if (optional('<', token.next)) { | |
| 1314 if (token.next is BeginGroupToken) { | |
| 1315 BeginGroupToken beginGroup = token.next; | |
| 1316 if (beginGroup.endGroup == null) { | |
| 1317 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); | |
| 1318 } else { | |
| 1319 token = beginGroup.endGroup; | |
| 1320 } | |
| 1321 } | |
| 1220 } | 1322 } |
| 1221 } | 1323 } |
| 1222 if (optional('<', token.next)) { | 1324 token = token.next; |
| 1223 if (token.next is BeginGroupToken) { | 1325 } |
| 1224 BeginGroupToken beginGroup = token.next; | 1326 while (isGeneralizedFunctionType(token)) { |
| 1327 token = token.next; | |
| 1328 if (optional('<', token)) { | |
| 1329 if (token is BeginGroupToken) { | |
| 1330 BeginGroupToken beginGroup = token; | |
| 1225 if (beginGroup.endGroup == null) { | 1331 if (beginGroup.endGroup == null) { |
| 1226 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); | 1332 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); |
| 1227 } else { | 1333 } else { |
| 1228 token = beginGroup.endGroup; | 1334 token = beginGroup.endGroup.next; |
| 1229 } | 1335 } |
| 1230 } | 1336 } |
| 1231 } | 1337 } |
| 1338 if (!optional('(', token)) { | |
| 1339 if (optional(';', token)) { | |
| 1340 reportRecoverableError(token, ErrorKind.ExpectedOpenParens); | |
| 1341 } | |
| 1342 token = expect("(", token); | |
| 1343 } | |
| 1344 if (token is BeginGroupToken) { | |
| 1345 BeginGroupToken beginGroup = token; | |
| 1346 if (beginGroup.endGroup == null) { | |
| 1347 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); | |
| 1348 } else { | |
| 1349 token = beginGroup.endGroup.next; | |
| 1350 } | |
| 1351 } | |
| 1232 } | 1352 } |
| 1233 token = token.next; | |
| 1234 } | 1353 } |
| 1235 return listener.handleMemberName(const Link<Token>()); | 1354 return listener.handleMemberName(const Link<Token>()); |
| 1236 } | 1355 } |
| 1237 | 1356 |
| 1238 Token parseFieldInitializerOpt(Token token) { | 1357 Token parseFieldInitializerOpt(Token token) { |
| 1239 if (optional('=', token)) { | 1358 if (optional('=', token)) { |
| 1240 Token assignment = token; | 1359 Token assignment = token; |
| 1241 listener.beginFieldInitializer(token); | 1360 listener.beginFieldInitializer(token); |
| 1242 token = parseExpression(token.next); | 1361 token = parseExpression(token.next); |
| 1243 listener.endFieldInitializer(assignment); | 1362 listener.endFieldInitializer(assignment); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1336 if (!isModifier(token)) break; | 1455 if (!isModifier(token)) break; |
| 1337 token = parseModifier(token); | 1456 token = parseModifier(token); |
| 1338 count++; | 1457 count++; |
| 1339 } | 1458 } |
| 1340 listener.handleModifiers(count); | 1459 listener.handleModifiers(count); |
| 1341 return token; | 1460 return token; |
| 1342 } | 1461 } |
| 1343 | 1462 |
| 1344 /** | 1463 /** |
| 1345 * Returns the first token after the type starting at [token]. | 1464 * Returns the first token after the type starting at [token]. |
| 1465 * | |
| 1346 * This method assumes that [token] is an identifier (or void). | 1466 * This method assumes that [token] is an identifier (or void). |
| 1347 * Use [peekAfterIfType] if [token] isn't known to be an identifier. | 1467 * Use [peekAfterIfType] if [token] isn't known to be an identifier. |
| 1348 */ | 1468 */ |
| 1349 Token peekAfterType(Token token) { | 1469 Token peekAfterType(Token token) { |
| 1350 // We are looking at "identifier ...". | 1470 // We are looking at "identifier ...". |
| 1471 Token peek = token; | |
| 1472 if (!isGeneralizedFunctionType(token)) { | |
| 1473 peek = peekAfterNominalType(token); | |
| 1474 } | |
| 1475 | |
| 1476 // We might have just skipped over the return value of the function type. | |
| 1477 // Check again, if we are now at a function type position. | |
| 1478 while (isGeneralizedFunctionType(peek)) { | |
| 1479 peek = peekAfterFunctionType(peek); | |
| 1480 } | |
| 1481 return peek; | |
| 1482 } | |
| 1483 | |
| 1484 /** | |
| 1485 * Returns the first token after the nominal type starting at [token]. | |
| 1486 * | |
| 1487 * This method assumes that [token] is an identifier (or void). | |
| 1488 */ | |
| 1489 Token peekAfterNominalType(Token token) { | |
| 1351 Token peek = token.next; | 1490 Token peek = token.next; |
| 1352 if (identical(peek.kind, PERIOD_TOKEN)) { | 1491 if (identical(peek.kind, PERIOD_TOKEN)) { |
| 1353 if (peek.next.isIdentifier()) { | 1492 if (peek.next.isIdentifier()) { |
| 1354 // Look past a library prefix. | 1493 // Look past a library prefix. |
| 1355 peek = peek.next.next; | 1494 peek = peek.next.next; |
| 1356 } | 1495 } |
| 1357 } | 1496 } |
| 1358 // We are looking at "qualified ...". | 1497 // We are looking at "qualified ...". |
| 1359 if (identical(peek.kind, LT_TOKEN)) { | 1498 if (identical(peek.kind, LT_TOKEN)) { |
| 1360 // Possibly generic type. | 1499 // Possibly generic type. |
| 1361 // We are looking at "qualified '<'". | 1500 // We are looking at "qualified '<'". |
| 1362 BeginGroupToken beginGroupToken = peek; | 1501 BeginGroupToken beginGroupToken = peek; |
| 1363 Token gtToken = beginGroupToken.endGroup; | 1502 Token gtToken = beginGroupToken.endGroup; |
| 1364 if (gtToken != null) { | 1503 if (gtToken != null) { |
| 1365 // We are looking at "qualified '<' ... '>' ...". | 1504 // We are looking at "qualified '<' ... '>' ...". |
| 1366 return gtToken.next; | 1505 peek = gtToken.next; |
| 1367 } | 1506 } |
| 1368 } | 1507 } |
| 1369 return peek; | 1508 return peek; |
| 1370 } | 1509 } |
| 1371 | 1510 |
| 1511 /** | |
| 1512 * Returns the first token after the function type starting at [token]. | |
| 1513 * | |
| 1514 * The token must be at the `Function` token position. That is, the return | |
| 1515 * type must have already been skipped. | |
| 1516 * | |
| 1517 * This function only skips over one function type syntax. | |
| 1518 * If necessary, this function must be called multiple times. | |
| 1519 * | |
| 1520 * Example: | |
| 1521 * ``` | |
| 1522 * int Function() Function<T>(int) | |
| 1523 * ^ ^ | |
| 1524 * A call to this function must be at one of the `Function` tokens. | |
| 1525 * If `token` pointed to the first `Function` token, then the returned | |
| 1526 * token points to the second `Function` token. | |
|
ahe
2017/02/15 11:50:17
Here's a thought: how about always passing in the
floitsch
2017/02/16 16:30:15
Done.
| |
| 1527 */ | |
| 1528 Token peekAfterFunctionType(Token token) { | |
| 1529 // Possible inputs are: | |
| 1530 // Function( ... ) | |
| 1531 // Function< ... >( ... ) | |
| 1532 | |
| 1533 Token peek = token.next; // Skip over the Function token. | |
| 1534 // If there is a generic argument to the function, skip over that one first. | |
| 1535 if (identical(peek.kind, LT_TOKEN)) { | |
| 1536 BeginGroupToken beginGroupToken = peek; | |
| 1537 Token closeToken = beginGroupToken.endGroup; | |
| 1538 if (closeToken != null) { | |
| 1539 peek = closeToken.next; | |
| 1540 } | |
| 1541 } | |
| 1542 | |
| 1543 // Now we just need to skip over the formals. | |
| 1544 expect('(', peek); | |
| 1545 | |
| 1546 BeginGroupToken beginGroupToken = peek; | |
| 1547 Token closeToken = beginGroupToken.endGroup; | |
| 1548 if (closeToken != null) { | |
| 1549 peek = closeToken.next; | |
| 1550 } | |
| 1551 | |
| 1552 return peek; | |
| 1553 } | |
| 1554 | |
| 1372 /** | 1555 /** |
| 1373 * If [token] is the start of a type, returns the token after that type. | 1556 * 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. | 1557 * If [token] is not the start of a type, null is returned. |
| 1375 */ | 1558 */ |
| 1376 Token peekAfterIfType(Token token) { | 1559 Token peekAfterIfType(Token token) { |
| 1377 if (!optional('void', token) && !token.isIdentifier()) { | 1560 if (!optional('void', token) && !token.isIdentifier()) { |
| 1378 return null; | 1561 return null; |
| 1379 } | 1562 } |
| 1380 return peekAfterType(token); | 1563 return peekAfterType(token); |
| 1381 } | 1564 } |
| (...skipping 1930 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3312 break; | 3495 break; |
| 3313 } | 3496 } |
| 3314 if (isRecoverable) { | 3497 if (isRecoverable) { |
| 3315 listener.handleRecoverableError(token, kind, arguments); | 3498 listener.handleRecoverableError(token, kind, arguments); |
| 3316 return null; | 3499 return null; |
| 3317 } else { | 3500 } else { |
| 3318 return listener.handleUnrecoverableError(token, kind, arguments); | 3501 return listener.handleUnrecoverableError(token, kind, arguments); |
| 3319 } | 3502 } |
| 3320 } | 3503 } |
| 3321 } | 3504 } |
| OLD | NEW |