UNPKG

31.3 kBJavaScriptView Raw
1/* @flow */
2
3"use strict";
4
5var _interopRequireDefault = require("babel-runtime/helpers/interop-require-default")["default"];
6
7exports.__esModule = true;
8
9var _tokenizerTypes = require("../tokenizer/types");
10
11var _parser = require("../parser");
12
13var _parser2 = _interopRequireDefault(_parser);
14
15var pp = _parser2["default"].prototype;
16
17pp.flowParseTypeInitialiser = function (tok) {
18 var oldInType = this.state.inType;
19 this.state.inType = true;
20 this.expect(tok || _tokenizerTypes.types.colon);
21 var type = this.flowParseType();
22 this.state.inType = oldInType;
23 return type;
24};
25
26pp.flowParseDeclareClass = function (node) {
27 this.next();
28 this.flowParseInterfaceish(node, true);
29 return this.finishNode(node, "DeclareClass");
30};
31
32pp.flowParseDeclareFunction = function (node) {
33 this.next();
34
35 var id = node.id = this.parseIdentifier();
36
37 var typeNode = this.startNode();
38 var typeContainer = this.startNode();
39
40 if (this.isRelational("<")) {
41 typeNode.typeParameters = this.flowParseTypeParameterDeclaration();
42 } else {
43 typeNode.typeParameters = null;
44 }
45
46 this.expect(_tokenizerTypes.types.parenL);
47 var tmp = this.flowParseFunctionTypeParams();
48 typeNode.params = tmp.params;
49 typeNode.rest = tmp.rest;
50 this.expect(_tokenizerTypes.types.parenR);
51 typeNode.returnType = this.flowParseTypeInitialiser();
52
53 typeContainer.typeAnnotation = this.finishNode(typeNode, "FunctionTypeAnnotation");
54 id.typeAnnotation = this.finishNode(typeContainer, "TypeAnnotation");
55
56 this.finishNode(id, id.type);
57
58 this.semicolon();
59
60 return this.finishNode(node, "DeclareFunction");
61};
62
63pp.flowParseDeclare = function (node) {
64 if (this.match(_tokenizerTypes.types._class)) {
65 return this.flowParseDeclareClass(node);
66 } else if (this.match(_tokenizerTypes.types._function)) {
67 return this.flowParseDeclareFunction(node);
68 } else if (this.match(_tokenizerTypes.types._var)) {
69 return this.flowParseDeclareVariable(node);
70 } else if (this.isContextual("module")) {
71 return this.flowParseDeclareModule(node);
72 } else {
73 this.unexpected();
74 }
75};
76
77pp.flowParseDeclareVariable = function (node) {
78 this.next();
79 node.id = this.flowParseTypeAnnotatableIdentifier();
80 this.semicolon();
81 return this.finishNode(node, "DeclareVariable");
82};
83
84pp.flowParseDeclareModule = function (node) {
85 this.next();
86
87 if (this.match(_tokenizerTypes.types.string)) {
88 node.id = this.parseExprAtom();
89 } else {
90 node.id = this.parseIdentifier();
91 }
92
93 var bodyNode = node.body = this.startNode();
94 var body = bodyNode.body = [];
95 this.expect(_tokenizerTypes.types.braceL);
96 while (!this.match(_tokenizerTypes.types.braceR)) {
97 var node2 = this.startNode();
98
99 // todo: declare check
100 this.next();
101
102 body.push(this.flowParseDeclare(node2));
103 }
104 this.expect(_tokenizerTypes.types.braceR);
105
106 this.finishNode(bodyNode, "BlockStatement");
107 return this.finishNode(node, "DeclareModule");
108};
109
110// Interfaces
111
112pp.flowParseInterfaceish = function (node, allowStatic) {
113 node.id = this.parseIdentifier();
114
115 if (this.isRelational("<")) {
116 node.typeParameters = this.flowParseTypeParameterDeclaration();
117 } else {
118 node.typeParameters = null;
119 }
120
121 node["extends"] = [];
122
123 if (this.eat(_tokenizerTypes.types._extends)) {
124 do {
125 node["extends"].push(this.flowParseInterfaceExtends());
126 } while (this.eat(_tokenizerTypes.types.comma));
127 }
128
129 node.body = this.flowParseObjectType(allowStatic);
130};
131
132pp.flowParseInterfaceExtends = function () {
133 var node = this.startNode();
134
135 node.id = this.parseIdentifier();
136 if (this.isRelational("<")) {
137 node.typeParameters = this.flowParseTypeParameterInstantiation();
138 } else {
139 node.typeParameters = null;
140 }
141
142 return this.finishNode(node, "InterfaceExtends");
143};
144
145pp.flowParseInterface = function (node) {
146 this.flowParseInterfaceish(node, false);
147 return this.finishNode(node, "InterfaceDeclaration");
148};
149
150// Type aliases
151
152pp.flowParseTypeAlias = function (node) {
153 node.id = this.parseIdentifier();
154
155 if (this.isRelational("<")) {
156 node.typeParameters = this.flowParseTypeParameterDeclaration();
157 } else {
158 node.typeParameters = null;
159 }
160
161 node.right = this.flowParseTypeInitialiser(_tokenizerTypes.types.eq);
162 this.semicolon();
163
164 return this.finishNode(node, "TypeAlias");
165};
166
167// Type annotations
168
169pp.flowParseTypeParameterDeclaration = function () {
170 var node = this.startNode();
171 node.params = [];
172
173 this.expectRelational("<");
174 while (!this.isRelational(">")) {
175 node.params.push(this.flowParseTypeAnnotatableIdentifier());
176 if (!this.isRelational(">")) {
177 this.expect(_tokenizerTypes.types.comma);
178 }
179 }
180 this.expectRelational(">");
181
182 return this.finishNode(node, "TypeParameterDeclaration");
183};
184
185pp.flowParseTypeParameterInstantiation = function () {
186 var node = this.startNode(),
187 oldInType = this.state.inType;
188 node.params = [];
189
190 this.state.inType = true;
191
192 this.expectRelational("<");
193 while (!this.isRelational(">")) {
194 node.params.push(this.flowParseType());
195 if (!this.isRelational(">")) {
196 this.expect(_tokenizerTypes.types.comma);
197 }
198 }
199 this.expectRelational(">");
200
201 this.state.inType = oldInType;
202
203 return this.finishNode(node, "TypeParameterInstantiation");
204};
205
206pp.flowParseObjectPropertyKey = function () {
207 return this.match(_tokenizerTypes.types.num) || this.match(_tokenizerTypes.types.string) ? this.parseExprAtom() : this.parseIdentifier(true);
208};
209
210pp.flowParseObjectTypeIndexer = function (node, isStatic) {
211 node["static"] = isStatic;
212
213 this.expect(_tokenizerTypes.types.bracketL);
214 node.id = this.flowParseObjectPropertyKey();
215 node.key = this.flowParseTypeInitialiser();
216 this.expect(_tokenizerTypes.types.bracketR);
217 node.value = this.flowParseTypeInitialiser();
218
219 this.flowObjectTypeSemicolon();
220 return this.finishNode(node, "ObjectTypeIndexer");
221};
222
223pp.flowParseObjectTypeMethodish = function (node) {
224 node.params = [];
225 node.rest = null;
226 node.typeParameters = null;
227
228 if (this.isRelational("<")) {
229 node.typeParameters = this.flowParseTypeParameterDeclaration();
230 }
231
232 this.expect(_tokenizerTypes.types.parenL);
233 while (this.match(_tokenizerTypes.types.name)) {
234 node.params.push(this.flowParseFunctionTypeParam());
235 if (!this.match(_tokenizerTypes.types.parenR)) {
236 this.expect(_tokenizerTypes.types.comma);
237 }
238 }
239
240 if (this.eat(_tokenizerTypes.types.ellipsis)) {
241 node.rest = this.flowParseFunctionTypeParam();
242 }
243 this.expect(_tokenizerTypes.types.parenR);
244 node.returnType = this.flowParseTypeInitialiser();
245
246 return this.finishNode(node, "FunctionTypeAnnotation");
247};
248
249pp.flowParseObjectTypeMethod = function (startPos, startLoc, isStatic, key) {
250 var node = this.startNodeAt(startPos, startLoc);
251 node.value = this.flowParseObjectTypeMethodish(this.startNodeAt(startPos, startLoc));
252 node["static"] = isStatic;
253 node.key = key;
254 node.optional = false;
255 this.flowObjectTypeSemicolon();
256 return this.finishNode(node, "ObjectTypeProperty");
257};
258
259pp.flowParseObjectTypeCallProperty = function (node, isStatic) {
260 var valueNode = this.startNode();
261 node["static"] = isStatic;
262 node.value = this.flowParseObjectTypeMethodish(valueNode);
263 this.flowObjectTypeSemicolon();
264 return this.finishNode(node, "ObjectTypeCallProperty");
265};
266
267pp.flowParseObjectType = function (allowStatic) {
268 var nodeStart = this.startNode();
269 var node = undefined;
270 var propertyKey = undefined;
271 var isStatic = undefined;
272
273 nodeStart.callProperties = [];
274 nodeStart.properties = [];
275 nodeStart.indexers = [];
276
277 this.expect(_tokenizerTypes.types.braceL);
278
279 while (!this.match(_tokenizerTypes.types.braceR)) {
280 var optional = false;
281 var startPos = this.state.start,
282 startLoc = this.state.startLoc;
283 node = this.startNode();
284 if (allowStatic && this.isContextual("static")) {
285 this.next();
286 isStatic = true;
287 }
288
289 if (this.match(_tokenizerTypes.types.bracketL)) {
290 nodeStart.indexers.push(this.flowParseObjectTypeIndexer(node, isStatic));
291 } else if (this.match(_tokenizerTypes.types.parenL) || this.isRelational("<")) {
292 nodeStart.callProperties.push(this.flowParseObjectTypeCallProperty(node, allowStatic));
293 } else {
294 if (isStatic && this.match(_tokenizerTypes.types.colon)) {
295 propertyKey = this.parseIdentifier();
296 } else {
297 propertyKey = this.flowParseObjectPropertyKey();
298 }
299 if (this.isRelational("<") || this.match(_tokenizerTypes.types.parenL)) {
300 // This is a method property
301 nodeStart.properties.push(this.flowParseObjectTypeMethod(startPos, startLoc, isStatic, propertyKey));
302 } else {
303 if (this.eat(_tokenizerTypes.types.question)) {
304 optional = true;
305 }
306 node.key = propertyKey;
307 node.value = this.flowParseTypeInitialiser();
308 node.optional = optional;
309 node["static"] = isStatic;
310 this.flowObjectTypeSemicolon();
311 nodeStart.properties.push(this.finishNode(node, "ObjectTypeProperty"));
312 }
313 }
314 }
315
316 this.expect(_tokenizerTypes.types.braceR);
317
318 return this.finishNode(nodeStart, "ObjectTypeAnnotation");
319};
320
321pp.flowObjectTypeSemicolon = function () {
322 if (!this.eat(_tokenizerTypes.types.semi) && !this.eat(_tokenizerTypes.types.comma) && !this.match(_tokenizerTypes.types.braceR)) {
323 this.unexpected();
324 }
325};
326
327pp.flowParseGenericType = function (startPos, startLoc, id) {
328 var node = this.startNodeAt(startPos, startLoc);
329
330 node.typeParameters = null;
331 node.id = id;
332
333 while (this.eat(_tokenizerTypes.types.dot)) {
334 var node2 = this.startNodeAt(startPos, startLoc);
335 node2.qualification = node.id;
336 node2.id = this.parseIdentifier();
337 node.id = this.finishNode(node2, "QualifiedTypeIdentifier");
338 }
339
340 if (this.isRelational("<")) {
341 node.typeParameters = this.flowParseTypeParameterInstantiation();
342 }
343
344 return this.finishNode(node, "GenericTypeAnnotation");
345};
346
347pp.flowParseTypeofType = function () {
348 var node = this.startNode();
349 this.expect(_tokenizerTypes.types._typeof);
350 node.argument = this.flowParsePrimaryType();
351 return this.finishNode(node, "TypeofTypeAnnotation");
352};
353
354pp.flowParseTupleType = function () {
355 var node = this.startNode();
356 node.types = [];
357 this.expect(_tokenizerTypes.types.bracketL);
358 // We allow trailing commas
359 while (this.state.pos < this.input.length && !this.match(_tokenizerTypes.types.bracketR)) {
360 node.types.push(this.flowParseType());
361 if (this.match(_tokenizerTypes.types.bracketR)) break;
362 this.expect(_tokenizerTypes.types.comma);
363 }
364 this.expect(_tokenizerTypes.types.bracketR);
365 return this.finishNode(node, "TupleTypeAnnotation");
366};
367
368pp.flowParseFunctionTypeParam = function () {
369 var optional = false;
370 var node = this.startNode();
371 node.name = this.parseIdentifier();
372 if (this.eat(_tokenizerTypes.types.question)) {
373 optional = true;
374 }
375 node.optional = optional;
376 node.typeAnnotation = this.flowParseTypeInitialiser();
377 return this.finishNode(node, "FunctionTypeParam");
378};
379
380pp.flowParseFunctionTypeParams = function () {
381 var ret = { params: [], rest: null };
382 while (this.match(_tokenizerTypes.types.name)) {
383 ret.params.push(this.flowParseFunctionTypeParam());
384 if (!this.match(_tokenizerTypes.types.parenR)) {
385 this.expect(_tokenizerTypes.types.comma);
386 }
387 }
388 if (this.eat(_tokenizerTypes.types.ellipsis)) {
389 ret.rest = this.flowParseFunctionTypeParam();
390 }
391 return ret;
392};
393
394pp.flowIdentToTypeAnnotation = function (startPos, startLoc, node, id) {
395 switch (id.name) {
396 case "any":
397 return this.finishNode(node, "AnyTypeAnnotation");
398
399 case "void":
400 return this.finishNode(node, "VoidTypeAnnotation");
401
402 case "bool":
403 case "boolean":
404 return this.finishNode(node, "BooleanTypeAnnotation");
405
406 case "mixed":
407 return this.finishNode(node, "MixedTypeAnnotation");
408
409 case "number":
410 return this.finishNode(node, "NumberTypeAnnotation");
411
412 case "string":
413 return this.finishNode(node, "StringTypeAnnotation");
414
415 default:
416 return this.flowParseGenericType(startPos, startLoc, id);
417 }
418};
419
420// The parsing of types roughly parallels the parsing of expressions, and
421// primary types are kind of like primary expressions...they're the
422// primitives with which other types are constructed.
423pp.flowParsePrimaryType = function () {
424 var startPos = this.state.start,
425 startLoc = this.state.startLoc;
426 var node = this.startNode();
427 var tmp = undefined;
428 var type = undefined;
429 var isGroupedType = false;
430
431 switch (this.state.type) {
432 case _tokenizerTypes.types.name:
433 return this.flowIdentToTypeAnnotation(startPos, startLoc, node, this.parseIdentifier());
434
435 case _tokenizerTypes.types.braceL:
436 return this.flowParseObjectType();
437
438 case _tokenizerTypes.types.bracketL:
439 return this.flowParseTupleType();
440
441 case _tokenizerTypes.types.relational:
442 if (this.state.value === "<") {
443 node.typeParameters = this.flowParseTypeParameterDeclaration();
444 this.expect(_tokenizerTypes.types.parenL);
445 tmp = this.flowParseFunctionTypeParams();
446 node.params = tmp.params;
447 node.rest = tmp.rest;
448 this.expect(_tokenizerTypes.types.parenR);
449
450 this.expect(_tokenizerTypes.types.arrow);
451
452 node.returnType = this.flowParseType();
453
454 return this.finishNode(node, "FunctionTypeAnnotation");
455 }
456
457 case _tokenizerTypes.types.parenL:
458 this.next();
459
460 // Check to see if this is actually a grouped type
461 if (!this.match(_tokenizerTypes.types.parenR) && !this.match(_tokenizerTypes.types.ellipsis)) {
462 if (this.match(_tokenizerTypes.types.name)) {
463 var token = this.lookahead().type;
464 isGroupedType = token !== _tokenizerTypes.types.question && token !== _tokenizerTypes.types.colon;
465 } else {
466 isGroupedType = true;
467 }
468 }
469
470 if (isGroupedType) {
471 type = this.flowParseType();
472 this.expect(_tokenizerTypes.types.parenR);
473
474 // If we see a => next then someone was probably confused about
475 // function types, so we can provide a better error message
476 if (this.eat(_tokenizerTypes.types.arrow)) {
477 this.raise(node, "Unexpected token =>. It looks like " + "you are trying to write a function type, but you ended up " + "writing a grouped type followed by an =>, which is a syntax " + "error. Remember, function type parameters are named so function " + "types look like (name1: type1, name2: type2) => returnType. You " + "probably wrote (type1) => returnType");
478 }
479
480 return type;
481 }
482
483 tmp = this.flowParseFunctionTypeParams();
484 node.params = tmp.params;
485 node.rest = tmp.rest;
486
487 this.expect(_tokenizerTypes.types.parenR);
488
489 this.expect(_tokenizerTypes.types.arrow);
490
491 node.returnType = this.flowParseType();
492 node.typeParameters = null;
493
494 return this.finishNode(node, "FunctionTypeAnnotation");
495
496 case _tokenizerTypes.types.string:
497 node.value = this.state.value;
498 this.addExtra(node, "rawValue", node.value);
499 this.addExtra(node, "raw", this.input.slice(this.state.start, this.state.end));
500 this.next();
501 return this.finishNode(node, "StringLiteralTypeAnnotation");
502
503 case _tokenizerTypes.types._true:case _tokenizerTypes.types._false:
504 node.value = this.match(_tokenizerTypes.types._true);
505 this.next();
506 return this.finishNode(node, "BooleanLiteralTypeAnnotation");
507
508 case _tokenizerTypes.types.num:
509 node.value = this.state.value;
510 this.addExtra(node, "rawValue", node.value);
511 this.addExtra(node, "raw", this.input.slice(this.state.start, this.state.end));
512 this.next();
513 return this.finishNode(node, "NumericLiteralTypeAnnotation");
514
515 default:
516 if (this.state.type.keyword === "typeof") {
517 return this.flowParseTypeofType();
518 }
519 }
520
521 this.unexpected();
522};
523
524pp.flowParsePostfixType = function () {
525 var node = this.startNode();
526 var type = node.elementType = this.flowParsePrimaryType();
527 if (this.match(_tokenizerTypes.types.bracketL)) {
528 this.expect(_tokenizerTypes.types.bracketL);
529 this.expect(_tokenizerTypes.types.bracketR);
530 return this.finishNode(node, "ArrayTypeAnnotation");
531 } else {
532 return type;
533 }
534};
535
536pp.flowParsePrefixType = function () {
537 var node = this.startNode();
538 if (this.eat(_tokenizerTypes.types.question)) {
539 node.typeAnnotation = this.flowParsePrefixType();
540 return this.finishNode(node, "NullableTypeAnnotation");
541 } else {
542 return this.flowParsePostfixType();
543 }
544};
545
546pp.flowParseIntersectionType = function () {
547 var node = this.startNode();
548 var type = this.flowParsePrefixType();
549 node.types = [type];
550 while (this.eat(_tokenizerTypes.types.bitwiseAND)) {
551 node.types.push(this.flowParsePrefixType());
552 }
553 return node.types.length === 1 ? type : this.finishNode(node, "IntersectionTypeAnnotation");
554};
555
556pp.flowParseUnionType = function () {
557 var node = this.startNode();
558 var type = this.flowParseIntersectionType();
559 node.types = [type];
560 while (this.eat(_tokenizerTypes.types.bitwiseOR)) {
561 node.types.push(this.flowParseIntersectionType());
562 }
563 return node.types.length === 1 ? type : this.finishNode(node, "UnionTypeAnnotation");
564};
565
566pp.flowParseType = function () {
567 var oldInType = this.state.inType;
568 this.state.inType = true;
569 var type = this.flowParseUnionType();
570 this.state.inType = oldInType;
571 return type;
572};
573
574pp.flowParseTypeAnnotation = function () {
575 var node = this.startNode();
576 node.typeAnnotation = this.flowParseTypeInitialiser();
577 return this.finishNode(node, "TypeAnnotation");
578};
579
580pp.flowParseTypeAnnotatableIdentifier = function (requireTypeAnnotation, canBeOptionalParam) {
581 var ident = this.parseIdentifier();
582 var isOptionalParam = false;
583
584 if (canBeOptionalParam && this.eat(_tokenizerTypes.types.question)) {
585 this.expect(_tokenizerTypes.types.question);
586 isOptionalParam = true;
587 }
588
589 if (requireTypeAnnotation || this.match(_tokenizerTypes.types.colon)) {
590 ident.typeAnnotation = this.flowParseTypeAnnotation();
591 this.finishNode(ident, ident.type);
592 }
593
594 if (isOptionalParam) {
595 ident.optional = true;
596 this.finishNode(ident, ident.type);
597 }
598
599 return ident;
600};
601
602exports["default"] = function (instance) {
603 // plain function return types: function name(): string {}
604 instance.extend("parseFunctionBody", function (inner) {
605 return function (node, allowExpression) {
606 if (this.match(_tokenizerTypes.types.colon) && !allowExpression) {
607 // if allowExpression is true then we're parsing an arrow function and if
608 // there's a return type then it's been handled elsewhere
609 node.returnType = this.flowParseTypeAnnotation();
610 }
611
612 return inner.call(this, node, allowExpression);
613 };
614 });
615
616 // interfaces
617 instance.extend("parseStatement", function (inner) {
618 return function (declaration, topLevel) {
619 // strict mode handling of `interface` since it's a reserved word
620 if (this.state.strict && this.match(_tokenizerTypes.types.name) && this.state.value === "interface") {
621 var node = this.startNode();
622 this.next();
623 return this.flowParseInterface(node);
624 } else {
625 return inner.call(this, declaration, topLevel);
626 }
627 };
628 });
629
630 // declares, interfaces and type aliases
631 instance.extend("parseExpressionStatement", function (inner) {
632 return function (node, expr) {
633 if (expr.type === "Identifier") {
634 if (expr.name === "declare") {
635 if (this.match(_tokenizerTypes.types._class) || this.match(_tokenizerTypes.types.name) || this.match(_tokenizerTypes.types._function) || this.match(_tokenizerTypes.types._var)) {
636 return this.flowParseDeclare(node);
637 }
638 } else if (this.match(_tokenizerTypes.types.name)) {
639 if (expr.name === "interface") {
640 return this.flowParseInterface(node);
641 } else if (expr.name === "type") {
642 return this.flowParseTypeAlias(node);
643 }
644 }
645 }
646
647 return inner.call(this, node, expr);
648 };
649 });
650
651 // export type
652 instance.extend("shouldParseExportDeclaration", function (inner) {
653 return function () {
654 return this.isContextual("type") || inner.call(this);
655 };
656 });
657
658 instance.extend("parseParenItem", function () {
659 return function (node, startLoc, startPos, forceArrow /*:: ?*/) {
660 var canBeArrow = this.state.potentialArrowAt = startPos;
661 if (this.match(_tokenizerTypes.types.colon)) {
662 var typeCastNode = this.startNodeAt(startLoc, startPos);
663 typeCastNode.expression = node;
664 typeCastNode.typeAnnotation = this.flowParseTypeAnnotation();
665
666 if (forceArrow && !this.match(_tokenizerTypes.types.arrow)) {
667 this.unexpected();
668 }
669
670 if (canBeArrow && this.eat(_tokenizerTypes.types.arrow)) {
671 // ((lol): number => {});
672 var func = this.parseArrowExpression(this.startNodeAt(startLoc, startPos), [node]);
673 func.returnType = typeCastNode.typeAnnotation;
674 return func;
675 } else {
676 return this.finishNode(typeCastNode, "TypeCastExpression");
677 }
678 } else {
679 return node;
680 }
681 };
682 });
683
684 instance.extend("parseExport", function (inner) {
685 return function (node) {
686 node = inner.call(this, node);
687 if (node.type === "ExportNamedDeclaration") {
688 node.exportKind = node.exportKind || "value";
689 }
690 return node;
691 };
692 });
693
694 instance.extend("parseExportDeclaration", function (inner) {
695 return function (node) {
696 if (this.isContextual("type")) {
697 node.exportKind = "type";
698
699 var declarationNode = this.startNode();
700 this.next();
701
702 if (this.match(_tokenizerTypes.types.braceL)) {
703 // export type { foo, bar };
704 node.specifiers = this.parseExportSpecifiers();
705 this.parseExportFrom(node);
706 return null;
707 } else {
708 // export type Foo = Bar;
709 return this.flowParseTypeAlias(declarationNode);
710 }
711 } else {
712 return inner.call(this, node);
713 }
714 };
715 });
716
717 instance.extend("parseClassId", function (inner) {
718 return function (node) {
719 inner.apply(this, arguments);
720 if (this.isRelational("<")) {
721 node.typeParameters = this.flowParseTypeParameterDeclaration();
722 }
723 };
724 });
725
726 // don't consider `void` to be a keyword as then it'll use the void token type
727 // and set startExpr
728 instance.extend("isKeyword", function (inner) {
729 return function (name) {
730 if (this.state.inType && name === "void") {
731 return false;
732 } else {
733 return inner.call(this, name);
734 }
735 };
736 });
737
738 // ensure that inside flow types, we bypass the jsx parser plugin
739 instance.extend("readToken", function (inner) {
740 return function (code) {
741 if (this.state.inType && (code === 62 || code === 60)) {
742 return this.finishOp(_tokenizerTypes.types.relational, 1);
743 } else {
744 return inner.call(this, code);
745 }
746 };
747 });
748
749 // don't lex any token as a jsx one inside a flow type
750 instance.extend("jsx_readToken", function (inner) {
751 return function () {
752 if (!this.state.inType) return inner.call(this);
753 };
754 });
755
756 function typeCastToParameter(node) {
757 node.expression.typeAnnotation = node.typeAnnotation;
758 return node.expression;
759 }
760
761 // turn type casts that we found in function parameter head into type annotated params
762 instance.extend("toAssignableList", function (inner) {
763 return function (exprList, isBinding) {
764 for (var i = 0; i < exprList.length; i++) {
765 var expr = exprList[i];
766 if (expr && expr.type === "TypeCastExpression") {
767 exprList[i] = typeCastToParameter(expr);
768 }
769 }
770 return inner.call(this, exprList, isBinding);
771 };
772 });
773
774 // this is a list of nodes, from something like a call expression, we need to filter the
775 // type casts that we've found that are illegal in this context
776 instance.extend("toReferencedList", function () {
777 return function (exprList) {
778 for (var i = 0; i < exprList.length; i++) {
779 var expr = exprList[i];
780 if (expr && expr._exprListItem && expr.type === "TypeCastExpression") {
781 this.raise(expr.start, "Unexpected type cast");
782 }
783 }
784
785 return exprList;
786 };
787 });
788
789 // parse an item inside a expression list eg. `(NODE, NODE)` where NODE represents
790 // the position where this function is cal;ed
791 instance.extend("parseExprListItem", function (inner) {
792 return function (allowEmpty, refShorthandDefaultPos) {
793 var container = this.startNode();
794 var node = inner.call(this, allowEmpty, refShorthandDefaultPos);
795 if (this.match(_tokenizerTypes.types.colon)) {
796 container._exprListItem = true;
797 container.expression = node;
798 container.typeAnnotation = this.flowParseTypeAnnotation();
799 return this.finishNode(container, "TypeCastExpression");
800 } else {
801 return node;
802 }
803 };
804 });
805
806 // parse class property type annotations
807 instance.extend("parseClassProperty", function (inner) {
808 return function (node) {
809 if (this.match(_tokenizerTypes.types.colon)) {
810 node.typeAnnotation = this.flowParseTypeAnnotation();
811 }
812 return inner.call(this, node);
813 };
814 });
815
816 // determine whether or not we're currently in the position where a class property would appear
817 instance.extend("isClassProperty", function (inner) {
818 return function () {
819 return this.match(_tokenizerTypes.types.colon) || inner.call(this);
820 };
821 });
822
823 // parse type parameters for class methods
824 instance.extend("parseClassMethod", function () {
825 return function (classBody, method, isGenerator, isAsync) {
826 if (this.isRelational("<")) {
827 method.typeParameters = this.flowParseTypeParameterDeclaration();
828 }
829 this.parseMethod(method, isGenerator, isAsync);
830 classBody.body.push(this.finishNode(method, "ClassMethod"));
831 };
832 });
833
834 // parse a the super class type parameters and implements
835 instance.extend("parseClassSuper", function (inner) {
836 return function (node, isStatement) {
837 inner.call(this, node, isStatement);
838 if (node.superClass && this.isRelational("<")) {
839 node.superTypeParameters = this.flowParseTypeParameterInstantiation();
840 }
841 if (this.isContextual("implements")) {
842 this.next();
843 var implemented = node["implements"] = [];
844 do {
845 var _node = this.startNode();
846 _node.id = this.parseIdentifier();
847 if (this.isRelational("<")) {
848 _node.typeParameters = this.flowParseTypeParameterInstantiation();
849 } else {
850 _node.typeParameters = null;
851 }
852 implemented.push(this.finishNode(_node, "ClassImplements"));
853 } while (this.eat(_tokenizerTypes.types.comma));
854 }
855 };
856 });
857
858 // parse type parameters for object method shorthand
859 instance.extend("parseObjPropValue", function (inner) {
860 return function (prop) {
861 var typeParameters = undefined;
862
863 // method shorthand
864 if (this.isRelational("<")) {
865 typeParameters = this.flowParseTypeParameterDeclaration();
866 if (!this.match(_tokenizerTypes.types.parenL)) this.unexpected();
867 }
868
869 inner.apply(this, arguments);
870
871 // add typeParameters if we found them
872 if (typeParameters) {
873 (prop.value || prop).typeParameters = typeParameters;
874 }
875 };
876 });
877
878 instance.extend("parseAssignableListItemTypes", function () {
879 return function (param) {
880 if (this.eat(_tokenizerTypes.types.question)) {
881 param.optional = true;
882 }
883 if (this.match(_tokenizerTypes.types.colon)) {
884 param.typeAnnotation = this.flowParseTypeAnnotation();
885 }
886 this.finishNode(param, param.type);
887 return param;
888 };
889 });
890
891 // parse typeof and type imports
892 instance.extend("parseImportSpecifiers", function (inner) {
893 return function (node) {
894 node.importKind = "value";
895
896 var kind = null;
897 if (this.match(_tokenizerTypes.types._typeof)) {
898 kind = "typeof";
899 } else if (this.isContextual("type")) {
900 kind = "type";
901 }
902 if (kind) {
903 var lh = this.lookahead();
904 if (lh.type === _tokenizerTypes.types.name && lh.value !== "from" || lh.type === _tokenizerTypes.types.braceL || lh.type === _tokenizerTypes.types.star) {
905 this.next();
906 node.importKind = kind;
907 }
908 }
909
910 inner.call(this, node);
911 };
912 });
913
914 // parse function type parameters - function foo<T>() {}
915 instance.extend("parseFunctionParams", function (inner) {
916 return function (node) {
917 if (this.isRelational("<")) {
918 node.typeParameters = this.flowParseTypeParameterDeclaration();
919 }
920 inner.call(this, node);
921 };
922 });
923
924 // parse flow type annotations on variable declarator heads - let foo: string = bar
925 instance.extend("parseVarHead", function (inner) {
926 return function (decl) {
927 inner.call(this, decl);
928 if (this.match(_tokenizerTypes.types.colon)) {
929 decl.id.typeAnnotation = this.flowParseTypeAnnotation();
930 this.finishNode(decl.id, decl.id.type);
931 }
932 };
933 });
934
935 // parse the return type of an async arrow function - let foo = (async (): number => {});
936 instance.extend("parseAsyncArrowFromCallExpression", function (inner) {
937 return function (node, call) {
938 if (this.match(_tokenizerTypes.types.colon)) {
939 node.returnType = this.flowParseTypeAnnotation();
940 }
941
942 return inner.call(this, node, call);
943 };
944 });
945
946 // todo description
947 instance.extend("shouldParseAsyncArrow", function (inner) {
948 return function () {
949 return this.match(_tokenizerTypes.types.colon) || inner.call(this);
950 };
951 });
952
953 // handle return types for arrow functions
954 instance.extend("parseParenAndDistinguishExpression", function (inner) {
955 return function (startPos, startLoc, canBeArrow, isAsync) {
956 startPos = startPos || this.state.start;
957 startLoc = startLoc || this.state.startLoc;
958
959 if (canBeArrow && this.lookahead().type === _tokenizerTypes.types.parenR) {
960 // let foo = (): number => {};
961 this.expect(_tokenizerTypes.types.parenL);
962 this.expect(_tokenizerTypes.types.parenR);
963
964 var node = this.startNodeAt(startPos, startLoc);
965 if (this.match(_tokenizerTypes.types.colon)) node.returnType = this.flowParseTypeAnnotation();
966 this.expect(_tokenizerTypes.types.arrow);
967 return this.parseArrowExpression(node, [], isAsync);
968 } else {
969 // let foo = (foo): number => {};
970 var node = inner.call(this, startPos, startLoc, canBeArrow, isAsync);
971
972 if (this.match(_tokenizerTypes.types.colon)) {
973 var state = this.state.clone();
974 try {
975 return this.parseParenItem(node, startPos, startLoc, true);
976 } catch (err) {
977 if (err instanceof SyntaxError) {
978 this.state = state;
979 return node;
980 } else {
981 throw err;
982 }
983 }
984 } else {
985 return node;
986 }
987 }
988 };
989 });
990};
991
992module.exports = exports["default"];
\No newline at end of file