UNPKG

25.6 kBJavaScriptView Raw
1/* eslint max-len: 0 */
2
3import {
4 eat,
5 lookaheadType,
6 lookaheadTypeAndKeyword,
7 match,
8 next,
9 popTypeContext,
10 pushTypeContext,
11
12} from "../tokenizer/index";
13import {ContextualKeyword} from "../tokenizer/keywords";
14import {TokenType, TokenType as tt} from "../tokenizer/types";
15import {input, state} from "../traverser/base";
16import {
17 baseParseMaybeAssign,
18 baseParseSubscript,
19 baseParseSubscripts,
20 parseArrow,
21 parseArrowExpression,
22 parseCallExpressionArguments,
23 parseExprAtom,
24 parseExpression,
25 parseFunctionBody,
26 parseIdentifier,
27 parseLiteral,
28
29} from "../traverser/expression";
30import {
31 baseParseExportStar,
32 parseExport,
33 parseExportFrom,
34 parseExportSpecifiers,
35 parseFunctionParams,
36 parseImport,
37 parseStatement,
38} from "../traverser/statement";
39import {
40 canInsertSemicolon,
41 eatContextual,
42 expect,
43 expectContextual,
44 isContextual,
45 isLookaheadContextual,
46 semicolon,
47 unexpected,
48} from "../traverser/util";
49
50function isMaybeDefaultImport(lookahead) {
51 return (
52 (lookahead.type === tt.name || !!(lookahead.type & TokenType.IS_KEYWORD)) &&
53 lookahead.contextualKeyword !== ContextualKeyword._from
54 );
55}
56
57function flowParseTypeInitialiser(tok) {
58 const oldIsType = pushTypeContext(0);
59 expect(tok || tt.colon);
60 flowParseType();
61 popTypeContext(oldIsType);
62}
63
64function flowParsePredicate() {
65 expect(tt.modulo);
66 expectContextual(ContextualKeyword._checks);
67 if (eat(tt.parenL)) {
68 parseExpression();
69 expect(tt.parenR);
70 }
71}
72
73function flowParseTypeAndPredicateInitialiser() {
74 const oldIsType = pushTypeContext(0);
75 expect(tt.colon);
76 if (match(tt.modulo)) {
77 flowParsePredicate();
78 } else {
79 flowParseType();
80 if (match(tt.modulo)) {
81 flowParsePredicate();
82 }
83 }
84 popTypeContext(oldIsType);
85}
86
87function flowParseDeclareClass() {
88 next();
89 flowParseInterfaceish(/* isClass */ true);
90}
91
92function flowParseDeclareFunction() {
93 next();
94 parseIdentifier();
95
96 if (match(tt.lessThan)) {
97 flowParseTypeParameterDeclaration();
98 }
99
100 expect(tt.parenL);
101 flowParseFunctionTypeParams();
102 expect(tt.parenR);
103
104 flowParseTypeAndPredicateInitialiser();
105
106 semicolon();
107}
108
109function flowParseDeclare() {
110 if (match(tt._class)) {
111 flowParseDeclareClass();
112 } else if (match(tt._function)) {
113 flowParseDeclareFunction();
114 } else if (match(tt._var)) {
115 flowParseDeclareVariable();
116 } else if (isContextual(ContextualKeyword._module)) {
117 if (lookaheadType() === tt.dot) {
118 flowParseDeclareModuleExports();
119 } else {
120 flowParseDeclareModule();
121 }
122 } else if (isContextual(ContextualKeyword._type)) {
123 flowParseDeclareTypeAlias();
124 } else if (isContextual(ContextualKeyword._opaque)) {
125 flowParseDeclareOpaqueType();
126 } else if (isContextual(ContextualKeyword._interface)) {
127 flowParseDeclareInterface();
128 } else if (match(tt._export)) {
129 flowParseDeclareExportDeclaration();
130 } else {
131 unexpected();
132 }
133}
134
135function flowParseDeclareVariable() {
136 next();
137 flowParseTypeAnnotatableIdentifier();
138 semicolon();
139}
140
141function flowParseDeclareModule() {
142 next();
143
144 if (match(tt.string)) {
145 parseExprAtom();
146 } else {
147 parseIdentifier();
148 }
149
150 expect(tt.braceL);
151 while (!match(tt.braceR) && !state.error) {
152 if (match(tt._import)) {
153 next();
154 parseImport();
155 } else {
156 unexpected();
157 }
158 }
159 expect(tt.braceR);
160}
161
162function flowParseDeclareExportDeclaration() {
163 expect(tt._export);
164
165 if (eat(tt._default)) {
166 if (match(tt._function) || match(tt._class)) {
167 // declare export default class ...
168 // declare export default function ...
169 flowParseDeclare();
170 } else {
171 // declare export default [type];
172 flowParseType();
173 semicolon();
174 }
175 } else if (
176 match(tt._var) || // declare export var ...
177 match(tt._function) || // declare export function ...
178 match(tt._class) || // declare export class ...
179 isContextual(ContextualKeyword._opaque) // declare export opaque ..
180 ) {
181 flowParseDeclare();
182 } else if (
183 match(tt.star) || // declare export * from ''
184 match(tt.braceL) || // declare export {} ...
185 isContextual(ContextualKeyword._interface) || // declare export interface ...
186 isContextual(ContextualKeyword._type) || // declare export type ...
187 isContextual(ContextualKeyword._opaque) // declare export opaque type ...
188 ) {
189 parseExport();
190 } else {
191 unexpected();
192 }
193}
194
195function flowParseDeclareModuleExports() {
196 expectContextual(ContextualKeyword._module);
197 expect(tt.dot);
198 expectContextual(ContextualKeyword._exports);
199 flowParseTypeAnnotation();
200 semicolon();
201}
202
203function flowParseDeclareTypeAlias() {
204 next();
205 flowParseTypeAlias();
206}
207
208function flowParseDeclareOpaqueType() {
209 next();
210 flowParseOpaqueType(true);
211}
212
213function flowParseDeclareInterface() {
214 next();
215 flowParseInterfaceish();
216}
217
218// Interfaces
219
220function flowParseInterfaceish(isClass = false) {
221 flowParseRestrictedIdentifier();
222
223 if (match(tt.lessThan)) {
224 flowParseTypeParameterDeclaration();
225 }
226
227 if (eat(tt._extends)) {
228 do {
229 flowParseInterfaceExtends();
230 } while (!isClass && eat(tt.comma));
231 }
232
233 if (isContextual(ContextualKeyword._mixins)) {
234 next();
235 do {
236 flowParseInterfaceExtends();
237 } while (eat(tt.comma));
238 }
239
240 if (isContextual(ContextualKeyword._implements)) {
241 next();
242 do {
243 flowParseInterfaceExtends();
244 } while (eat(tt.comma));
245 }
246
247 flowParseObjectType(isClass, false, isClass);
248}
249
250function flowParseInterfaceExtends() {
251 flowParseQualifiedTypeIdentifier(false);
252 if (match(tt.lessThan)) {
253 flowParseTypeParameterInstantiation();
254 }
255}
256
257function flowParseInterface() {
258 flowParseInterfaceish();
259}
260
261function flowParseRestrictedIdentifier() {
262 parseIdentifier();
263}
264
265function flowParseTypeAlias() {
266 flowParseRestrictedIdentifier();
267
268 if (match(tt.lessThan)) {
269 flowParseTypeParameterDeclaration();
270 }
271
272 flowParseTypeInitialiser(tt.eq);
273 semicolon();
274}
275
276function flowParseOpaqueType(declare) {
277 expectContextual(ContextualKeyword._type);
278 flowParseRestrictedIdentifier();
279
280 if (match(tt.lessThan)) {
281 flowParseTypeParameterDeclaration();
282 }
283
284 // Parse the supertype
285 if (match(tt.colon)) {
286 flowParseTypeInitialiser(tt.colon);
287 }
288
289 if (!declare) {
290 flowParseTypeInitialiser(tt.eq);
291 }
292 semicolon();
293}
294
295function flowParseTypeParameter() {
296 flowParseVariance();
297 flowParseTypeAnnotatableIdentifier();
298
299 if (eat(tt.eq)) {
300 flowParseType();
301 }
302}
303
304export function flowParseTypeParameterDeclaration() {
305 const oldIsType = pushTypeContext(0);
306 // istanbul ignore else: this condition is already checked at all call sites
307 if (match(tt.lessThan) || match(tt.typeParameterStart)) {
308 next();
309 } else {
310 unexpected();
311 }
312
313 do {
314 flowParseTypeParameter();
315 if (!match(tt.greaterThan)) {
316 expect(tt.comma);
317 }
318 } while (!match(tt.greaterThan) && !state.error);
319 expect(tt.greaterThan);
320 popTypeContext(oldIsType);
321}
322
323function flowParseTypeParameterInstantiation() {
324 const oldIsType = pushTypeContext(0);
325 expect(tt.lessThan);
326 while (!match(tt.greaterThan) && !state.error) {
327 flowParseType();
328 if (!match(tt.greaterThan)) {
329 expect(tt.comma);
330 }
331 }
332 expect(tt.greaterThan);
333 popTypeContext(oldIsType);
334}
335
336function flowParseInterfaceType() {
337 expectContextual(ContextualKeyword._interface);
338 if (eat(tt._extends)) {
339 do {
340 flowParseInterfaceExtends();
341 } while (eat(tt.comma));
342 }
343 flowParseObjectType(false, false, false);
344}
345
346function flowParseObjectPropertyKey() {
347 if (match(tt.num) || match(tt.string)) {
348 parseExprAtom();
349 } else {
350 parseIdentifier();
351 }
352}
353
354function flowParseObjectTypeIndexer() {
355 // Note: bracketL has already been consumed
356 if (lookaheadType() === tt.colon) {
357 flowParseObjectPropertyKey();
358 flowParseTypeInitialiser();
359 } else {
360 flowParseType();
361 }
362 expect(tt.bracketR);
363 flowParseTypeInitialiser();
364}
365
366function flowParseObjectTypeInternalSlot() {
367 // Note: both bracketL have already been consumed
368 flowParseObjectPropertyKey();
369 expect(tt.bracketR);
370 expect(tt.bracketR);
371 if (match(tt.lessThan) || match(tt.parenL)) {
372 flowParseObjectTypeMethodish();
373 } else {
374 eat(tt.question);
375 flowParseTypeInitialiser();
376 }
377}
378
379function flowParseObjectTypeMethodish() {
380 if (match(tt.lessThan)) {
381 flowParseTypeParameterDeclaration();
382 }
383
384 expect(tt.parenL);
385 while (!match(tt.parenR) && !match(tt.ellipsis) && !state.error) {
386 flowParseFunctionTypeParam();
387 if (!match(tt.parenR)) {
388 expect(tt.comma);
389 }
390 }
391
392 if (eat(tt.ellipsis)) {
393 flowParseFunctionTypeParam();
394 }
395 expect(tt.parenR);
396 flowParseTypeInitialiser();
397}
398
399function flowParseObjectTypeCallProperty() {
400 flowParseObjectTypeMethodish();
401}
402
403function flowParseObjectType(allowStatic, allowExact, allowProto) {
404 let endDelim;
405 if (allowExact && match(tt.braceBarL)) {
406 expect(tt.braceBarL);
407 endDelim = tt.braceBarR;
408 } else {
409 expect(tt.braceL);
410 endDelim = tt.braceR;
411 }
412
413 while (!match(endDelim) && !state.error) {
414 if (allowProto && isContextual(ContextualKeyword._proto)) {
415 const lookahead = lookaheadType();
416 if (lookahead !== tt.colon && lookahead !== tt.question) {
417 next();
418 allowStatic = false;
419 }
420 }
421 if (allowStatic && isContextual(ContextualKeyword._static)) {
422 const lookahead = lookaheadType();
423 if (lookahead !== tt.colon && lookahead !== tt.question) {
424 next();
425 }
426 }
427
428 flowParseVariance();
429
430 if (eat(tt.bracketL)) {
431 if (eat(tt.bracketL)) {
432 flowParseObjectTypeInternalSlot();
433 } else {
434 flowParseObjectTypeIndexer();
435 }
436 } else if (match(tt.parenL) || match(tt.lessThan)) {
437 flowParseObjectTypeCallProperty();
438 } else {
439 if (isContextual(ContextualKeyword._get) || isContextual(ContextualKeyword._set)) {
440 const lookahead = lookaheadType();
441 if (lookahead === tt.name || lookahead === tt.string || lookahead === tt.num) {
442 next();
443 }
444 }
445
446 flowParseObjectTypeProperty();
447 }
448
449 flowObjectTypeSemicolon();
450 }
451
452 expect(endDelim);
453}
454
455function flowParseObjectTypeProperty() {
456 if (match(tt.ellipsis)) {
457 expect(tt.ellipsis);
458 if (!eat(tt.comma)) {
459 eat(tt.semi);
460 }
461 // Explicit inexact object syntax.
462 if (match(tt.braceR)) {
463 return;
464 }
465 flowParseType();
466 } else {
467 flowParseObjectPropertyKey();
468 if (match(tt.lessThan) || match(tt.parenL)) {
469 // This is a method property
470 flowParseObjectTypeMethodish();
471 } else {
472 eat(tt.question);
473 flowParseTypeInitialiser();
474 }
475 }
476}
477
478function flowObjectTypeSemicolon() {
479 if (!eat(tt.semi) && !eat(tt.comma) && !match(tt.braceR) && !match(tt.braceBarR)) {
480 unexpected();
481 }
482}
483
484function flowParseQualifiedTypeIdentifier(initialIdAlreadyParsed) {
485 if (!initialIdAlreadyParsed) {
486 parseIdentifier();
487 }
488 while (eat(tt.dot)) {
489 parseIdentifier();
490 }
491}
492
493function flowParseGenericType() {
494 flowParseQualifiedTypeIdentifier(true);
495 if (match(tt.lessThan)) {
496 flowParseTypeParameterInstantiation();
497 }
498}
499
500function flowParseTypeofType() {
501 expect(tt._typeof);
502 flowParsePrimaryType();
503}
504
505function flowParseTupleType() {
506 expect(tt.bracketL);
507 // We allow trailing commas
508 while (state.pos < input.length && !match(tt.bracketR)) {
509 flowParseType();
510 if (match(tt.bracketR)) {
511 break;
512 }
513 expect(tt.comma);
514 }
515 expect(tt.bracketR);
516}
517
518function flowParseFunctionTypeParam() {
519 const lookahead = lookaheadType();
520 if (lookahead === tt.colon || lookahead === tt.question) {
521 parseIdentifier();
522 eat(tt.question);
523 flowParseTypeInitialiser();
524 } else {
525 flowParseType();
526 }
527}
528
529function flowParseFunctionTypeParams() {
530 while (!match(tt.parenR) && !match(tt.ellipsis) && !state.error) {
531 flowParseFunctionTypeParam();
532 if (!match(tt.parenR)) {
533 expect(tt.comma);
534 }
535 }
536 if (eat(tt.ellipsis)) {
537 flowParseFunctionTypeParam();
538 }
539}
540
541// The parsing of types roughly parallels the parsing of expressions, and
542// primary types are kind of like primary expressions...they're the
543// primitives with which other types are constructed.
544function flowParsePrimaryType() {
545 let isGroupedType = false;
546 const oldNoAnonFunctionType = state.noAnonFunctionType;
547
548 switch (state.type) {
549 case tt.name: {
550 if (isContextual(ContextualKeyword._interface)) {
551 flowParseInterfaceType();
552 return;
553 }
554 parseIdentifier();
555 flowParseGenericType();
556 return;
557 }
558
559 case tt.braceL:
560 flowParseObjectType(false, false, false);
561 return;
562
563 case tt.braceBarL:
564 flowParseObjectType(false, true, false);
565 return;
566
567 case tt.bracketL:
568 flowParseTupleType();
569 return;
570
571 case tt.lessThan:
572 flowParseTypeParameterDeclaration();
573 expect(tt.parenL);
574 flowParseFunctionTypeParams();
575 expect(tt.parenR);
576 expect(tt.arrow);
577 flowParseType();
578 return;
579
580 case tt.parenL:
581 next();
582
583 // Check to see if this is actually a grouped type
584 if (!match(tt.parenR) && !match(tt.ellipsis)) {
585 if (match(tt.name)) {
586 const token = lookaheadType();
587 isGroupedType = token !== tt.question && token !== tt.colon;
588 } else {
589 isGroupedType = true;
590 }
591 }
592
593 if (isGroupedType) {
594 state.noAnonFunctionType = false;
595 flowParseType();
596 state.noAnonFunctionType = oldNoAnonFunctionType;
597
598 // A `,` or a `) =>` means this is an anonymous function type
599 if (
600 state.noAnonFunctionType ||
601 !(match(tt.comma) || (match(tt.parenR) && lookaheadType() === tt.arrow))
602 ) {
603 expect(tt.parenR);
604 return;
605 } else {
606 // Eat a comma if there is one
607 eat(tt.comma);
608 }
609 }
610
611 flowParseFunctionTypeParams();
612
613 expect(tt.parenR);
614 expect(tt.arrow);
615 flowParseType();
616 return;
617
618 case tt.minus:
619 next();
620 parseLiteral();
621 return;
622
623 case tt.string:
624 case tt.num:
625 case tt._true:
626 case tt._false:
627 case tt._null:
628 case tt._this:
629 case tt._void:
630 case tt.star:
631 next();
632 return;
633
634 default:
635 if (state.type === tt._typeof) {
636 flowParseTypeofType();
637 return;
638 }
639 }
640
641 unexpected();
642}
643
644function flowParsePostfixType() {
645 flowParsePrimaryType();
646 while (!canInsertSemicolon() && match(tt.bracketL)) {
647 expect(tt.bracketL);
648 expect(tt.bracketR);
649 }
650}
651
652function flowParsePrefixType() {
653 if (eat(tt.question)) {
654 flowParsePrefixType();
655 } else {
656 flowParsePostfixType();
657 }
658}
659
660function flowParseAnonFunctionWithoutParens() {
661 flowParsePrefixType();
662 if (!state.noAnonFunctionType && eat(tt.arrow)) {
663 flowParseType();
664 }
665}
666
667function flowParseIntersectionType() {
668 eat(tt.bitwiseAND);
669 flowParseAnonFunctionWithoutParens();
670 while (eat(tt.bitwiseAND)) {
671 flowParseAnonFunctionWithoutParens();
672 }
673}
674
675function flowParseUnionType() {
676 eat(tt.bitwiseOR);
677 flowParseIntersectionType();
678 while (eat(tt.bitwiseOR)) {
679 flowParseIntersectionType();
680 }
681}
682
683function flowParseType() {
684 flowParseUnionType();
685}
686
687export function flowParseTypeAnnotation() {
688 flowParseTypeInitialiser();
689}
690
691function flowParseTypeAnnotatableIdentifier() {
692 parseIdentifier();
693 if (match(tt.colon)) {
694 flowParseTypeAnnotation();
695 }
696}
697
698export function flowParseVariance() {
699 if (match(tt.plus) || match(tt.minus)) {
700 next();
701 }
702}
703
704// ==================================
705// Overrides
706// ==================================
707
708export function flowParseFunctionBodyAndFinish(
709 functionStart,
710 isGenerator,
711 allowExpressionBody = false,
712 funcContextId,
713) {
714 // For arrow functions, `parseArrow` handles the return type itself.
715 if (!allowExpressionBody && match(tt.colon)) {
716 flowParseTypeAndPredicateInitialiser();
717 }
718
719 parseFunctionBody(functionStart, isGenerator, allowExpressionBody, funcContextId);
720}
721
722export function flowParseSubscript(startPos, noCalls, stopState) {
723 if (match(tt.questionDot) && lookaheadType() === tt.lessThan) {
724 if (noCalls) {
725 stopState.stop = true;
726 return;
727 }
728 next();
729 flowParseTypeParameterInstantiation();
730 expect(tt.parenL);
731 parseCallExpressionArguments();
732 return;
733 } else if (!noCalls && match(tt.lessThan)) {
734 const snapshot = state.snapshot();
735 flowParseTypeParameterInstantiation();
736 expect(tt.parenL);
737 parseCallExpressionArguments();
738 if (state.error) {
739 state.restoreFromSnapshot(snapshot);
740 } else {
741 return;
742 }
743 }
744 baseParseSubscript(startPos, noCalls, stopState);
745}
746
747export function flowStartParseNewArguments() {
748 if (match(tt.lessThan)) {
749 const snapshot = state.snapshot();
750 flowParseTypeParameterInstantiation();
751 if (state.error) {
752 state.restoreFromSnapshot(snapshot);
753 }
754 }
755}
756
757// interfaces
758export function flowTryParseStatement() {
759 if (match(tt.name) && state.contextualKeyword === ContextualKeyword._interface) {
760 const oldIsType = pushTypeContext(0);
761 next();
762 flowParseInterface();
763 popTypeContext(oldIsType);
764 return true;
765 } else {
766 return false;
767 }
768}
769
770// declares, interfaces and type aliases
771export function flowParseIdentifierStatement(contextualKeyword) {
772 if (contextualKeyword === ContextualKeyword._declare) {
773 if (
774 match(tt._class) ||
775 match(tt.name) ||
776 match(tt._function) ||
777 match(tt._var) ||
778 match(tt._export)
779 ) {
780 const oldIsType = pushTypeContext(1);
781 flowParseDeclare();
782 popTypeContext(oldIsType);
783 }
784 } else if (match(tt.name)) {
785 if (contextualKeyword === ContextualKeyword._interface) {
786 const oldIsType = pushTypeContext(1);
787 flowParseInterface();
788 popTypeContext(oldIsType);
789 } else if (contextualKeyword === ContextualKeyword._type) {
790 const oldIsType = pushTypeContext(1);
791 flowParseTypeAlias();
792 popTypeContext(oldIsType);
793 } else if (contextualKeyword === ContextualKeyword._opaque) {
794 const oldIsType = pushTypeContext(1);
795 flowParseOpaqueType(false);
796 popTypeContext(oldIsType);
797 }
798 }
799 semicolon();
800}
801
802// export type
803export function flowShouldParseExportDeclaration() {
804 return (
805 isContextual(ContextualKeyword._type) ||
806 isContextual(ContextualKeyword._interface) ||
807 isContextual(ContextualKeyword._opaque)
808 );
809}
810
811export function flowShouldDisallowExportDefaultSpecifier() {
812 return (
813 match(tt.name) &&
814 (state.contextualKeyword === ContextualKeyword._type ||
815 state.contextualKeyword === ContextualKeyword._interface ||
816 state.contextualKeyword === ContextualKeyword._opaque)
817 );
818}
819
820export function flowParseExportDeclaration() {
821 if (isContextual(ContextualKeyword._type)) {
822 const oldIsType = pushTypeContext(1);
823 next();
824
825 if (match(tt.braceL)) {
826 // export type { foo, bar };
827 parseExportSpecifiers();
828 parseExportFrom();
829 } else {
830 // export type Foo = Bar;
831 flowParseTypeAlias();
832 }
833 popTypeContext(oldIsType);
834 } else if (isContextual(ContextualKeyword._opaque)) {
835 const oldIsType = pushTypeContext(1);
836 next();
837 // export opaque type Foo = Bar;
838 flowParseOpaqueType(false);
839 popTypeContext(oldIsType);
840 } else if (isContextual(ContextualKeyword._interface)) {
841 const oldIsType = pushTypeContext(1);
842 next();
843 flowParseInterface();
844 popTypeContext(oldIsType);
845 } else {
846 parseStatement(true);
847 }
848}
849
850export function flowShouldParseExportStar() {
851 return match(tt.star) || (isContextual(ContextualKeyword._type) && lookaheadType() === tt.star);
852}
853
854export function flowParseExportStar() {
855 if (eatContextual(ContextualKeyword._type)) {
856 const oldIsType = pushTypeContext(2);
857 baseParseExportStar();
858 popTypeContext(oldIsType);
859 } else {
860 baseParseExportStar();
861 }
862}
863
864// parse a the super class type parameters and implements
865export function flowAfterParseClassSuper(hasSuper) {
866 if (hasSuper && match(tt.lessThan)) {
867 flowParseTypeParameterInstantiation();
868 }
869 if (isContextual(ContextualKeyword._implements)) {
870 const oldIsType = pushTypeContext(0);
871 next();
872 state.tokens[state.tokens.length - 1].type = tt._implements;
873 do {
874 flowParseRestrictedIdentifier();
875 if (match(tt.lessThan)) {
876 flowParseTypeParameterInstantiation();
877 }
878 } while (eat(tt.comma));
879 popTypeContext(oldIsType);
880 }
881}
882
883// parse type parameters for object method shorthand
884export function flowStartParseObjPropValue() {
885 // method shorthand
886 if (match(tt.lessThan)) {
887 flowParseTypeParameterDeclaration();
888 if (!match(tt.parenL)) unexpected();
889 }
890}
891
892export function flowParseAssignableListItemTypes() {
893 const oldIsType = pushTypeContext(0);
894 eat(tt.question);
895 if (match(tt.colon)) {
896 flowParseTypeAnnotation();
897 }
898 popTypeContext(oldIsType);
899}
900
901// parse typeof and type imports
902export function flowStartParseImportSpecifiers() {
903 if (match(tt._typeof) || isContextual(ContextualKeyword._type)) {
904 const lh = lookaheadTypeAndKeyword();
905 if (isMaybeDefaultImport(lh) || lh.type === tt.braceL || lh.type === tt.star) {
906 next();
907 }
908 }
909}
910
911// parse import-type/typeof shorthand
912export function flowParseImportSpecifier() {
913 const isTypeKeyword =
914 state.contextualKeyword === ContextualKeyword._type || state.type === tt._typeof;
915 if (isTypeKeyword) {
916 next();
917 } else {
918 parseIdentifier();
919 }
920
921 if (isContextual(ContextualKeyword._as) && !isLookaheadContextual(ContextualKeyword._as)) {
922 parseIdentifier();
923 if (isTypeKeyword && !match(tt.name) && !(state.type & TokenType.IS_KEYWORD)) {
924 // `import {type as ,` or `import {type as }`
925 } else {
926 // `import {type as foo`
927 parseIdentifier();
928 }
929 } else if (isTypeKeyword && (match(tt.name) || !!(state.type & TokenType.IS_KEYWORD))) {
930 // `import {type foo`
931 parseIdentifier();
932 if (eatContextual(ContextualKeyword._as)) {
933 parseIdentifier();
934 }
935 }
936}
937
938// parse function type parameters - function foo<T>() {}
939export function flowStartParseFunctionParams() {
940 // Originally this checked if the method is a getter/setter, but if it was, we'd crash soon
941 // anyway, so don't try to propagate that information.
942 if (match(tt.lessThan)) {
943 const oldIsType = pushTypeContext(0);
944 flowParseTypeParameterDeclaration();
945 popTypeContext(oldIsType);
946 }
947}
948
949// parse flow type annotations on variable declarator heads - let foo: string = bar
950export function flowAfterParseVarHead() {
951 if (match(tt.colon)) {
952 flowParseTypeAnnotation();
953 }
954}
955
956// parse the return type of an async arrow function - let foo = (async (): number => {});
957export function flowStartParseAsyncArrowFromCallExpression() {
958 if (match(tt.colon)) {
959 const oldNoAnonFunctionType = state.noAnonFunctionType;
960 state.noAnonFunctionType = true;
961 flowParseTypeAnnotation();
962 state.noAnonFunctionType = oldNoAnonFunctionType;
963 }
964}
965
966// We need to support type parameter declarations for arrow functions. This
967// is tricky. There are three situations we need to handle
968//
969// 1. This is either JSX or an arrow function. We'll try JSX first. If that
970// fails, we'll try an arrow function. If that fails, we'll throw the JSX
971// error.
972// 2. This is an arrow function. We'll parse the type parameter declaration,
973// parse the rest, make sure the rest is an arrow function, and go from
974// there
975// 3. This is neither. Just call the super method
976export function flowParseMaybeAssign(noIn, isWithinParens) {
977 if (match(tt.lessThan)) {
978 const snapshot = state.snapshot();
979 let wasArrow = baseParseMaybeAssign(noIn, isWithinParens);
980 if (state.error) {
981 state.restoreFromSnapshot(snapshot);
982 state.type = tt.typeParameterStart;
983 } else {
984 return wasArrow;
985 }
986
987 const oldIsType = pushTypeContext(0);
988 flowParseTypeParameterDeclaration();
989 popTypeContext(oldIsType);
990 wasArrow = baseParseMaybeAssign(noIn, isWithinParens);
991 if (wasArrow) {
992 return true;
993 }
994 unexpected();
995 }
996
997 return baseParseMaybeAssign(noIn, isWithinParens);
998}
999
1000// handle return types for arrow functions
1001export function flowParseArrow() {
1002 if (match(tt.colon)) {
1003 const oldIsType = pushTypeContext(0);
1004 const snapshot = state.snapshot();
1005
1006 const oldNoAnonFunctionType = state.noAnonFunctionType;
1007 state.noAnonFunctionType = true;
1008 flowParseTypeAndPredicateInitialiser();
1009 state.noAnonFunctionType = oldNoAnonFunctionType;
1010
1011 if (canInsertSemicolon()) unexpected();
1012 if (!match(tt.arrow)) unexpected();
1013
1014 if (state.error) {
1015 state.restoreFromSnapshot(snapshot);
1016 }
1017 popTypeContext(oldIsType);
1018 }
1019 return eat(tt.arrow);
1020}
1021
1022export function flowParseSubscripts(startPos, noCalls = false) {
1023 if (
1024 state.tokens[state.tokens.length - 1].contextualKeyword === ContextualKeyword._async &&
1025 match(tt.lessThan)
1026 ) {
1027 const snapshot = state.snapshot();
1028 const wasArrow = parseAsyncArrowWithTypeParameters(startPos);
1029 if (wasArrow && !state.error) {
1030 return;
1031 }
1032 state.restoreFromSnapshot(snapshot);
1033 }
1034
1035 baseParseSubscripts(startPos, noCalls);
1036}
1037
1038// Returns true if there was an arrow function here.
1039function parseAsyncArrowWithTypeParameters(startPos) {
1040 state.scopeDepth++;
1041 const startTokenIndex = state.tokens.length;
1042 parseFunctionParams();
1043 if (!parseArrow()) {
1044 return false;
1045 }
1046 parseArrowExpression(startPos, startTokenIndex);
1047 return true;
1048}