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 dart2js.parser; | 5 library dart2js.parser; |
6 | 6 |
7 import '../common.dart'; | 7 import '../common.dart'; |
8 import '../tokens/keyword.dart' show Keyword; | 8 import '../tokens/keyword.dart' show Keyword; |
9 import '../tokens/precedence.dart' show PrecedenceInfo; | 9 import '../tokens/precedence.dart' show PrecedenceInfo; |
10 import '../tokens/precedence_constants.dart' | 10 import '../tokens/precedence_constants.dart' |
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
355 period = token; | 355 period = token; |
356 token = parseIdentifier(token.next); | 356 token = parseIdentifier(token.next); |
357 } | 357 } |
358 token = parseArgumentsOpt(token); | 358 token = parseArgumentsOpt(token); |
359 listener.endMetadata(atToken, period, token); | 359 listener.endMetadata(atToken, period, token); |
360 return token; | 360 return token; |
361 } | 361 } |
362 | 362 |
363 Token parseTypedef(Token token) { | 363 Token parseTypedef(Token token) { |
364 Token typedefKeyword = token; | 364 Token typedefKeyword = token; |
365 listener.beginFunctionTypeAlias(token); | 365 listener.beginTypedef(token); |
366 token = parseReturnTypeOpt(token.next); | 366 Token equals; |
367 token = parseIdentifier(token); | 367 if (optional('=', peekAfterNominalType(token.next))) { |
368 token = parseTypeVariablesOpt(token); | 368 token = parseIdentifier(token.next); |
369 token = parseFormalParameters(token); | 369 token = parseTypeVariablesOpt(token); |
370 listener.endFunctionTypeAlias(typedefKeyword, token); | 370 equals = expect('=', token); |
Johnni Winther
2017/01/02 12:46:53
We are only using [equals] as a marker, but with t
floitsch
2017/01/02 13:48:48
Right. Good catch.
done.
| |
371 token = parseType(equals); | |
372 } else { | |
373 token = parseReturnTypeOpt(token.next); | |
374 token = parseIdentifier(token); | |
375 token = parseTypeVariablesOpt(token); | |
376 token = parseFormalParameters(token); | |
377 } | |
378 listener.endTypedef(typedefKeyword, equals, token); | |
371 return expect(';', token); | 379 return expect(';', token); |
372 } | 380 } |
373 | 381 |
374 Token parseMixinApplication(Token token) { | 382 Token parseMixinApplication(Token token) { |
375 listener.beginMixinApplication(token); | 383 listener.beginMixinApplication(token); |
376 token = parseType(token); | 384 token = parseType(token); |
377 token = expect('with', token); | 385 token = expect('with', token); |
378 token = parseTypeList(token); | 386 token = parseTypeList(token); |
379 listener.endMixinApplication(); | 387 listener.endMixinApplication(); |
380 return token; | 388 return token; |
(...skipping 10 matching lines...) Expand all Loading... | |
391 | 399 |
392 Token parseFormalParametersOpt(Token token) { | 400 Token parseFormalParametersOpt(Token token) { |
393 if (optional('(', token)) { | 401 if (optional('(', token)) { |
394 return parseFormalParameters(token); | 402 return parseFormalParameters(token); |
395 } else { | 403 } else { |
396 listener.handleNoFormalParameters(token); | 404 listener.handleNoFormalParameters(token); |
397 return token; | 405 return token; |
398 } | 406 } |
399 } | 407 } |
400 | 408 |
401 Token parseFormalParameters(Token token) { | 409 /// Parses the formal parameter list of a function. |
410 /// | |
411 /// If [inFunctionType] is true, then the names may be omitted (except for | |
412 /// named arguments). If it is false, then the types may be omitted. | |
413 Token parseFormalParameters(Token token, {bool inFunctionType: false}) { | |
402 Token begin = token; | 414 Token begin = token; |
403 listener.beginFormalParameters(begin); | 415 listener.beginFormalParameters(begin); |
404 expect('(', token); | 416 expect('(', token); |
405 int parameterCount = 0; | 417 int parameterCount = 0; |
406 do { | 418 do { |
407 token = token.next; | 419 token = token.next; |
408 if (optional(')', token)) { | 420 if (optional(')', token)) { |
409 break; | 421 break; |
410 } | 422 } |
411 ++parameterCount; | 423 ++parameterCount; |
412 String value = token.stringValue; | 424 String value = token.stringValue; |
413 if (identical(value, '[')) { | 425 if (identical(value, '[')) { |
414 token = parseOptionalFormalParameters(token, false); | 426 token = parseOptionalFormalParameters( |
427 token, false, inFunctionType: inFunctionType); | |
415 break; | 428 break; |
416 } else if (identical(value, '{')) { | 429 } else if (identical(value, '{')) { |
417 token = parseOptionalFormalParameters(token, true); | 430 token = parseOptionalFormalParameters( |
431 token, true, inFunctionType: inFunctionType); | |
418 break; | 432 break; |
419 } | 433 } |
420 token = parseFormalParameter(token, FormalParameterType.REQUIRED); | 434 token = parseFormalParameter(token, FormalParameterType.REQUIRED, |
435 inFunctionType: inFunctionType); | |
421 } while (optional(',', token)); | 436 } while (optional(',', token)); |
422 listener.endFormalParameters(parameterCount, begin, token); | 437 listener.endFormalParameters(parameterCount, begin, token); |
423 return expect(')', token); | 438 return expect(')', token); |
424 } | 439 } |
425 | 440 |
426 Token parseFormalParameter(Token token, FormalParameterType type) { | 441 Token parseFormalParameter(Token token, FormalParameterType type, |
442 {bool inFunctionType}) { | |
427 token = parseMetadataStar(token, forParameter: true); | 443 token = parseMetadataStar(token, forParameter: true); |
428 listener.beginFormalParameter(token); | 444 listener.beginFormalParameter(token); |
429 token = parseModifiers(token); | 445 token = parseModifiers(token); |
430 // TODO(ahe): Validate that there are formal parameters if void. | 446 bool isNamedParameter = type == FormalParameterType.NAMED; |
431 token = parseReturnTypeOpt(token); | 447 |
432 Token thisKeyword = null; | 448 Token thisKeyword = null; |
433 if (optional('this', token)) { | 449 if (inFunctionType && isNamedParameter) { |
434 thisKeyword = token; | 450 token = parseTypeOpt(token); |
435 // TODO(ahe): Validate field initializers are only used in | 451 token = parseIdentifier(token); |
436 // constructors, and not for function-typed arguments. | 452 } else if (inFunctionType) { |
437 token = expect('.', token.next); | 453 token = parseType(token); |
454 if (token.isIdentifier()) { | |
455 token = parseIdentifier(token); | |
456 } else { | |
457 listener.handleNoName(token); | |
458 } | |
459 } else { | |
460 // TODO(ahe): Validate that there are formal parameters if void. | |
Johnni Winther
2017/01/02 12:46:53
Remove. This is checked in resolution.
floitsch
2017/01/02 13:48:48
Done.
| |
461 token = parseReturnTypeOpt(token); | |
462 if (optional('this', token)) { | |
463 thisKeyword = token; | |
464 // TODO(ahe): Validate field initializers are only used in | |
465 // constructors, and not for function-typed arguments. | |
Johnni Winther
2017/01/02 12:46:53
Ditto.
floitsch
2017/01/02 13:48:48
Done.
| |
466 token = expect('.', token.next); | |
467 } | |
468 token = parseIdentifier(token); | |
438 } | 469 } |
439 token = parseIdentifier(token); | 470 |
440 if (optional('(', token)) { | 471 // Generalized function types don't allow inline function types. |
441 listener.handleNoTypeVariables(token); | 472 // The following isn't allowed: |
442 token = parseFormalParameters(token); | 473 // int Function(int bar(String x)). |
443 listener.handleFunctionTypedFormalParameter(token); | 474 if (!inFunctionType) { |
444 } else if (optional('<', token)) { | 475 if (optional('(', token)) { |
445 token = parseTypeVariablesOpt(token); | 476 listener.handleNoTypeVariables(token); |
446 token = parseFormalParameters(token); | 477 token = parseFormalParameters(token); |
447 listener.handleFunctionTypedFormalParameter(token); | 478 listener.handleFunctionTypedFormalParameter(token); |
479 } else if (optional('<', token)) { | |
480 token = parseTypeVariablesOpt(token); | |
481 token = parseFormalParameters(token); | |
482 listener.handleFunctionTypedFormalParameter(token); | |
483 } | |
448 } | 484 } |
449 String value = token.stringValue; | 485 String value = token.stringValue; |
450 if ((identical('=', value)) || (identical(':', value))) { | 486 if ((identical('=', value)) || (identical(':', value))) { |
451 // TODO(ahe): Validate that these are only used for optional parameters. | 487 // TODO(ahe): Validate that these are only used for optional parameters. |
452 Token equal = token; | 488 Token equal = token; |
453 token = parseExpression(token.next); | 489 token = parseExpression(token.next); |
454 listener.handleValuedFormalParameter(equal, token); | 490 listener.handleValuedFormalParameter(equal, token); |
455 if (type.isRequired) { | 491 if (type.isRequired) { |
456 listener.reportError( | 492 listener.reportError( |
457 equal, MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT); | 493 equal, MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT); |
458 } else if (type.isPositional && identical(':', value)) { | 494 } else if (type.isPositional && identical(':', value)) { |
459 listener.reportError( | 495 listener.reportError( |
460 equal, MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS); | 496 equal, MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS); |
461 } | 497 } |
462 } | 498 } |
463 listener.endFormalParameter(thisKeyword); | 499 listener.endFormalParameter(thisKeyword); |
464 return token; | 500 return token; |
465 } | 501 } |
466 | 502 |
467 Token parseOptionalFormalParameters(Token token, bool isNamed) { | 503 Token parseOptionalFormalParameters(Token token, bool isNamed, |
504 {bool inFunctionType}) { | |
468 Token begin = token; | 505 Token begin = token; |
469 listener.beginOptionalFormalParameters(begin); | 506 listener.beginOptionalFormalParameters(begin); |
470 assert((isNamed && optional('{', token)) || optional('[', token)); | 507 assert((isNamed && optional('{', token)) || optional('[', token)); |
471 int parameterCount = 0; | 508 int parameterCount = 0; |
472 do { | 509 do { |
473 token = token.next; | 510 token = token.next; |
474 if (isNamed && optional('}', token)) { | 511 if (isNamed && optional('}', token)) { |
475 break; | 512 break; |
476 } else if (!isNamed && optional(']', token)) { | 513 } else if (!isNamed && optional(']', token)) { |
477 break; | 514 break; |
478 } | 515 } |
479 var type = | 516 var type = |
480 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; | 517 isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL; |
481 token = parseFormalParameter(token, type); | 518 token = |
519 parseFormalParameter(token, type, inFunctionType: inFunctionType); | |
482 ++parameterCount; | 520 ++parameterCount; |
483 } while (optional(',', token)); | 521 } while (optional(',', token)); |
484 if (parameterCount == 0) { | 522 if (parameterCount == 0) { |
485 listener.reportError( | 523 listener.reportError( |
486 token, | 524 token, |
487 isNamed | 525 isNamed |
488 ? MessageKind.EMPTY_NAMED_PARAMETER_LIST | 526 ? MessageKind.EMPTY_NAMED_PARAMETER_LIST |
489 : MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST); | 527 : MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST); |
490 } | 528 } |
491 listener.endOptionalFormalParameters(parameterCount, begin, token); | 529 listener.endOptionalFormalParameters(parameterCount, begin, token); |
492 if (isNamed) { | 530 if (isNamed) { |
493 return expect('}', token); | 531 return expect('}', token); |
494 } else { | 532 } else { |
495 return expect(']', token); | 533 return expect(']', token); |
496 } | 534 } |
497 } | 535 } |
498 | 536 |
499 Token parseTypeOpt(Token token) { | 537 Token parseTypeOpt(Token token) { |
538 if (isGeneralizedFunctionType(token)) { | |
539 // Function type without return type. | |
540 return parseType(token); | |
541 } | |
500 Token peek = peekAfterIfType(token); | 542 Token peek = peekAfterIfType(token); |
501 if (peek != null && (peek.isIdentifier() || optional('this', peek))) { | 543 if (peek != null && (peek.isIdentifier() || optional('this', peek))) { |
502 return parseType(token); | 544 return parseType(token); |
503 } | 545 } |
504 listener.handleNoType(token); | 546 listener.handleNoType(token); |
505 return token; | 547 return token; |
506 } | 548 } |
507 | 549 |
508 bool isValidTypeReference(Token token) { | 550 bool isValidTypeReference(Token token) { |
509 final kind = token.kind; | 551 final kind = token.kind; |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
654 } | 696 } |
655 | 697 |
656 Token parseClassOrNamedMixinApplication(Token token) { | 698 Token parseClassOrNamedMixinApplication(Token token) { |
657 Token begin = token; | 699 Token begin = token; |
658 Token abstractKeyword; | 700 Token abstractKeyword; |
659 if (optional('abstract', token)) { | 701 if (optional('abstract', token)) { |
660 abstractKeyword = token; | 702 abstractKeyword = token; |
661 token = token.next; | 703 token = token.next; |
662 } | 704 } |
663 Token classKeyword = token; | 705 Token classKeyword = token; |
664 var isMixinApplication = optional('=', peekAfterType(token.next)); | 706 var isMixinApplication = optional('=', peekAfterNominalType(token.next)); |
665 if (isMixinApplication) { | 707 if (isMixinApplication) { |
666 listener.beginNamedMixinApplication(begin); | 708 listener.beginNamedMixinApplication(begin); |
667 } else { | 709 } else { |
668 listener.beginClassDeclaration(begin); | 710 listener.beginClassDeclaration(begin); |
669 } | 711 } |
670 | 712 |
671 int modifierCount = 0; | 713 int modifierCount = 0; |
672 if (abstractKeyword != null) { | 714 if (abstractKeyword != null) { |
673 parseModifier(abstractKeyword); | 715 parseModifier(abstractKeyword); |
674 modifierCount++; | 716 modifierCount++; |
(...skipping 20 matching lines...) Expand all Loading... | |
695 listener.endNamedMixinApplication(classKeyword, implementsKeyword, token); | 737 listener.endNamedMixinApplication(classKeyword, implementsKeyword, token); |
696 return expect(';', token); | 738 return expect(';', token); |
697 } | 739 } |
698 | 740 |
699 Token parseClass(Token begin, Token classKeyword) { | 741 Token parseClass(Token begin, Token classKeyword) { |
700 Token token = parseIdentifier(classKeyword.next); | 742 Token token = parseIdentifier(classKeyword.next); |
701 token = parseTypeVariablesOpt(token); | 743 token = parseTypeVariablesOpt(token); |
702 Token extendsKeyword; | 744 Token extendsKeyword; |
703 if (optional('extends', token)) { | 745 if (optional('extends', token)) { |
704 extendsKeyword = token; | 746 extendsKeyword = token; |
705 if (optional('with', peekAfterType(token.next))) { | 747 if (optional('with', peekAfterNominalType(token.next))) { |
706 token = parseMixinApplication(token.next); | 748 token = parseMixinApplication(token.next); |
707 } else { | 749 } else { |
708 token = parseType(token.next); | 750 token = parseType(token.next); |
709 } | 751 } |
710 } else { | 752 } else { |
711 extendsKeyword = null; | 753 extendsKeyword = null; |
712 listener.handleNoType(token); | 754 listener.handleNoType(token); |
713 } | 755 } |
714 Token implementsKeyword; | 756 Token implementsKeyword; |
715 int interfacesCount = 0; | 757 int interfacesCount = 0; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
793 value2 == stringValue || | 835 value2 == stringValue || |
794 value3 == stringValue || | 836 value3 == stringValue || |
795 value4 == stringValue; | 837 value4 == stringValue; |
796 } | 838 } |
797 | 839 |
798 bool notEofOrValue(String value, Token token) { | 840 bool notEofOrValue(String value, Token token) { |
799 return !identical(token.kind, EOF_TOKEN) && | 841 return !identical(token.kind, EOF_TOKEN) && |
800 !identical(value, token.stringValue); | 842 !identical(value, token.stringValue); |
801 } | 843 } |
802 | 844 |
845 bool isGeneralizedFunctionType(Token token) { | |
846 // TODO(floitsch): don't use string comparison, but the keyword-state | |
847 // table is currently not set up to deal with upper-case characters. | |
848 return (optional('<', token.next) || optional('(', token.next)) && | |
849 token.value == "Function"; | |
850 } | |
851 | |
803 Token parseType(Token token) { | 852 Token parseType(Token token) { |
804 Token begin = token; | 853 Token begin = token; |
805 if (isValidTypeReference(token)) { | 854 if (isGeneralizedFunctionType(token)) { |
806 token = parseIdentifier(token); | 855 // A function type without return type. |
807 token = parseQualifiedRestOpt(token); | 856 // Push the non-existing return type first. The loop below will |
857 // generate the full type. | |
858 listener.handleNoType(token); | |
808 } else { | 859 } else { |
809 token = listener.expectedType(token); | 860 if (isValidTypeReference(token)) { |
861 token = parseIdentifier(token); | |
862 token = parseQualifiedRestOpt(token); | |
863 } else { | |
864 token = listener.expectedType(token); | |
865 } | |
866 token = parseTypeArgumentsOpt(token); | |
867 listener.endType(begin, token); | |
810 } | 868 } |
811 token = parseTypeArgumentsOpt(token); | 869 |
812 listener.endType(begin, token); | 870 // While we see a `Function(` treat the pushed type as return type. |
871 // For example: `int Function() Function(int) Function(String x)`. | |
872 while (isGeneralizedFunctionType(token)) { | |
873 token = parseFunctionType(token); | |
874 } | |
813 return token; | 875 return token; |
814 } | 876 } |
815 | 877 |
878 /// Parses a generalized function type. | |
879 /// | |
880 /// The return type must already be pushed. | |
881 Token parseFunctionType(Token token) { | |
882 // TODO(floitsch): don't use string comparison, but the keyword-state | |
883 // table is currently not set up to deal with upper-case characters. | |
884 if (token.value != "Function") { | |
885 return listener.expected("Function", token); | |
886 } | |
887 Token functionToken = token; | |
888 token = token.next; | |
889 token = parseTypeVariablesOpt(token); | |
890 token = parseFormalParameters(token, inFunctionType: true); | |
891 listener.endFunctionType(functionToken, token); | |
892 return token; | |
893 } | |
894 | |
816 Token parseTypeArgumentsOpt(Token token) { | 895 Token parseTypeArgumentsOpt(Token token) { |
817 return parseStuff( | 896 return parseStuff( |
818 token, | 897 token, |
819 (t) => listener.beginTypeArguments(t), | 898 (t) => listener.beginTypeArguments(t), |
820 (t) => parseType(t), | 899 (t) => parseType(t), |
821 (c, bt, et) => listener.endTypeArguments(c, bt, et), | 900 (c, bt, et) => listener.endTypeArguments(c, bt, et), |
822 (t) => listener.handleNoTypeArguments(t)); | 901 (t) => listener.handleNoTypeArguments(t)); |
823 } | 902 } |
824 | 903 |
825 Token parseTypeVariablesOpt(Token token) { | 904 Token parseTypeVariablesOpt(Token token) { |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1139 identifiers = identifiers.prepend(token); | 1218 identifiers = identifiers.prepend(token); |
1140 return identifiers; | 1219 return identifiers; |
1141 } else if (value == '=' || value == ';' || value == ',') { | 1220 } else if (value == '=' || value == ';' || value == ',') { |
1142 // A field or abstract getter. | 1221 // A field or abstract getter. |
1143 identifiers = identifiers.prepend(token); | 1222 identifiers = identifiers.prepend(token); |
1144 return identifiers; | 1223 return identifiers; |
1145 } else if (isGetter) { | 1224 } else if (isGetter) { |
1146 hasName = true; | 1225 hasName = true; |
1147 } | 1226 } |
1148 identifiers = identifiers.prepend(token); | 1227 identifiers = identifiers.prepend(token); |
1149 if (isValidTypeReference(token)) { | 1228 |
1150 // type ... | 1229 if (!isGeneralizedFunctionType(token)) { |
1151 if (optional('.', token.next)) { | 1230 // Read a potential return type. |
1152 // type '.' ... | 1231 if (isValidTypeReference(token)) { |
1153 if (token.next.next.isIdentifier()) { | 1232 // type ... |
1154 // type '.' identifier | 1233 if (optional('.', token.next)) { |
1155 token = token.next.next; | 1234 // type '.' ... |
1235 if (token.next.next.isIdentifier()) { | |
1236 // type '.' identifier | |
1237 token = token.next.next; | |
1238 } | |
1239 } | |
1240 if (optional('<', token.next)) { | |
1241 if (token.next is BeginGroupToken) { | |
1242 BeginGroupToken beginGroup = token.next; | |
1243 if (beginGroup.endGroup == null) { | |
1244 listener.unmatched(beginGroup); | |
1245 } | |
1246 token = beginGroup.endGroup; | |
1247 } | |
1156 } | 1248 } |
1157 } | 1249 } |
1158 if (optional('<', token.next)) { | 1250 token = token.next; |
1159 if (token.next is BeginGroupToken) { | 1251 } |
1160 BeginGroupToken beginGroup = token.next; | 1252 while (isGeneralizedFunctionType(token)) { |
1253 token = token.next; | |
1254 if (optional('<', token)) { | |
1255 if (token is BeginGroupToken) { | |
1256 BeginGroupToken beginGroup = token; | |
1161 if (beginGroup.endGroup == null) { | 1257 if (beginGroup.endGroup == null) { |
1162 listener.unmatched(beginGroup); | 1258 listener.unmatched(beginGroup); |
1163 } | 1259 } |
1164 token = beginGroup.endGroup; | 1260 token = beginGroup.endGroup.next; |
1165 } | 1261 } |
1166 } | 1262 } |
1263 if (!optional('(', token)) { | |
1264 if (optional(';', token)) { | |
1265 listener.recoverableError(token, "expected '('"); | |
1266 } | |
1267 token = listener.unexpected(token); | |
1268 } | |
1269 if (token is BeginGroupToken) { | |
1270 BeginGroupToken beginGroup = token; | |
1271 if (beginGroup.endGroup == null) { | |
1272 listener.unmatched(beginGroup); | |
1273 } | |
1274 token = beginGroup.endGroup.next; | |
1275 } | |
1167 } | 1276 } |
1168 token = token.next; | |
1169 } | 1277 } |
1170 return const Link<Token>(); | 1278 return const Link<Token>(); |
1171 } | 1279 } |
1172 | 1280 |
1173 Token parseVariableInitializerOpt(Token token) { | 1281 Token parseVariableInitializerOpt(Token token) { |
1174 if (optional('=', token)) { | 1282 if (optional('=', token)) { |
1175 Token assignment = token; | 1283 Token assignment = token; |
1176 listener.beginInitializer(token); | 1284 listener.beginInitializer(token); |
1177 token = parseExpression(token.next); | 1285 token = parseExpression(token.next); |
1178 listener.endInitializer(assignment); | 1286 listener.endInitializer(assignment); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1256 if (!isModifier(token)) break; | 1364 if (!isModifier(token)) break; |
1257 token = parseModifier(token); | 1365 token = parseModifier(token); |
1258 count++; | 1366 count++; |
1259 } | 1367 } |
1260 listener.handleModifiers(count); | 1368 listener.handleModifiers(count); |
1261 return token; | 1369 return token; |
1262 } | 1370 } |
1263 | 1371 |
1264 /** | 1372 /** |
1265 * Returns the first token after the type starting at [token]. | 1373 * Returns the first token after the type starting at [token]. |
1374 * | |
1266 * This method assumes that [token] is an identifier (or void). | 1375 * This method assumes that [token] is an identifier (or void). |
1267 * Use [peekAfterIfType] if [token] isn't known to be an identifier. | 1376 * Use [peekAfterIfType] if [token] isn't known to be an identifier. |
1268 */ | 1377 */ |
1269 Token peekAfterType(Token token) { | 1378 Token peekAfterType(Token token) { |
1270 // We are looking at "identifier ...". | 1379 // We are looking at "identifier ...". |
1380 Token peek = token; | |
1381 if (!isGeneralizedFunctionType(token)) { | |
1382 peek = peekAfterNominalType(token); | |
1383 } | |
1384 | |
1385 // We might have just skipped over the return value of the function type. | |
1386 // Check again, if we are now at a function type position. | |
1387 while (isGeneralizedFunctionType(peek)) { | |
1388 peek = peekAfterFunctionType(peek); | |
1389 } | |
1390 return peek; | |
1391 } | |
1392 | |
1393 /** | |
1394 * Returns the first token after the nominal type starting at [token]. | |
1395 * | |
1396 * This method assumes that [token] is an identifier (or void). | |
1397 */ | |
1398 Token peekAfterNominalType(Token token) { | |
1271 Token peek = token.next; | 1399 Token peek = token.next; |
1272 if (identical(peek.kind, PERIOD_TOKEN)) { | 1400 if (identical(peek.kind, PERIOD_TOKEN)) { |
1273 if (peek.next.isIdentifier()) { | 1401 if (peek.next.isIdentifier()) { |
1274 // Look past a library prefix. | 1402 // Look past a library prefix. |
1275 peek = peek.next.next; | 1403 peek = peek.next.next; |
1276 } | 1404 } |
1277 } | 1405 } |
1278 // We are looking at "qualified ...". | 1406 // We are looking at "qualified ...". |
1279 if (identical(peek.kind, LT_TOKEN)) { | 1407 if (identical(peek.kind, LT_TOKEN)) { |
1280 // Possibly generic type. | 1408 // Possibly generic type. |
1281 // We are looking at "qualified '<'". | 1409 // We are looking at "qualified '<'". |
1282 BeginGroupToken beginGroupToken = peek; | 1410 BeginGroupToken beginGroupToken = peek; |
1283 Token gtToken = beginGroupToken.endGroup; | 1411 Token gtToken = beginGroupToken.endGroup; |
1284 if (gtToken != null) { | 1412 if (gtToken != null) { |
1285 // We are looking at "qualified '<' ... '>' ...". | 1413 // We are looking at "qualified '<' ... '>' ...". |
1286 return gtToken.next; | 1414 peek = gtToken.next; |
1287 } | 1415 } |
1288 } | 1416 } |
1289 return peek; | 1417 return peek; |
1290 } | 1418 } |
1291 | 1419 |
1292 /** | 1420 /** |
1421 * Returns the first token after the function type starting at [token]. | |
1422 * | |
1423 * The token must be at the `Function` token position. That is, the return | |
1424 * type must have already been skipped. | |
1425 * | |
1426 * This function only skips over one function type syntax. | |
1427 * If necessary, this function must be called multiple times. | |
1428 * | |
1429 * Example: | |
1430 * ``` | |
1431 * int Function() Function<T>(int) | |
1432 * ^ ^ | |
1433 * A call to this function must be at one of the `Function` tokens. | |
1434 * If `token` pointed to the first `Function` token, then the returned | |
1435 * token points to the second `Function` token. | |
1436 */ | |
1437 Token peekAfterFunctionType(Token token) { | |
1438 // Possible inputs are: | |
1439 // Function( ... ) | |
1440 // Function< ... >( ... ) | |
1441 | |
1442 Token peek = token.next; // Skip over the Function token. | |
1443 // If there is a generic argument to the function, skip over that one first. | |
1444 if (identical(peek.kind, LT_TOKEN)) { | |
1445 BeginGroupToken beginGroupToken = peek; | |
1446 Token closeToken = beginGroupToken.endGroup; | |
1447 if (closeToken != null) { | |
1448 peek = closeToken.next; | |
1449 } | |
1450 } | |
1451 | |
1452 // Now we just need to skip over the formals. | |
1453 expect('(', peek); | |
1454 | |
1455 BeginGroupToken beginGroupToken = peek; | |
1456 Token closeToken = beginGroupToken.endGroup; | |
1457 if (closeToken != null) { | |
1458 peek = closeToken.next; | |
1459 } | |
1460 | |
1461 return peek; | |
1462 } | |
1463 | |
1464 /** | |
1293 * If [token] is the start of a type, returns the token after that type. | 1465 * If [token] is the start of a type, returns the token after that type. |
1294 * If [token] is not the start of a type, null is returned. | 1466 * If [token] is not the start of a type, null is returned. |
1295 */ | 1467 */ |
1296 Token peekAfterIfType(Token token) { | 1468 Token peekAfterIfType(Token token) { |
1297 if (!optional('void', token) && !token.isIdentifier()) { | 1469 if (!optional('void', token) && !token.isIdentifier()) { |
1298 return null; | 1470 return null; |
1299 } | 1471 } |
1300 return peekAfterType(token); | 1472 return peekAfterType(token); |
1301 } | 1473 } |
1302 | 1474 |
(...skipping 1666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2969 } | 3141 } |
2970 listener.handleContinueStatement(hasTarget, continueKeyword, token); | 3142 listener.handleContinueStatement(hasTarget, continueKeyword, token); |
2971 return expectSemicolon(token); | 3143 return expectSemicolon(token); |
2972 } | 3144 } |
2973 | 3145 |
2974 Token parseEmptyStatement(Token token) { | 3146 Token parseEmptyStatement(Token token) { |
2975 listener.handleEmptyStatement(token); | 3147 listener.handleEmptyStatement(token); |
2976 return expectSemicolon(token); | 3148 return expectSemicolon(token); |
2977 } | 3149 } |
2978 } | 3150 } |
OLD | NEW |