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

Side by Side Diff: pkg/front_end/lib/src/fasta/parser/parser.dart

Issue 2567133002: Add support for the new function-type syntax. (Closed)
Patch Set: Handle function types with `void` return type. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « pkg/front_end/lib/src/fasta/parser/listener.dart ('k') | pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698