UNPKG

27.8 kBJavaScriptView Raw
1/* eslint max-len: 0 */
2
3import {File} from "../index";
4import {
5 flowAfterParseClassSuper,
6 flowAfterParseVarHead,
7 flowParseExportDeclaration,
8 flowParseExportStar,
9 flowParseIdentifierStatement,
10 flowParseImportSpecifier,
11 flowParseTypeAnnotation,
12 flowParseTypeParameterDeclaration,
13 flowShouldDisallowExportDefaultSpecifier,
14 flowShouldParseExportDeclaration,
15 flowShouldParseExportStar,
16 flowStartParseFunctionParams,
17 flowStartParseImportSpecifiers,
18 flowTryParseStatement,
19} from "../plugins/flow";
20import {
21 tsAfterParseClassSuper,
22 tsAfterParseVarHead,
23 tsIsDeclarationStart,
24 tsParseAccessModifier,
25 tsParseExportDeclaration,
26 tsParseIdentifierStatement,
27 tsParseImportEqualsDeclaration,
28 tsParseMaybeDecoratorArguments,
29 tsStartParseFunctionParams,
30 tsTryParseClassMemberWithIsStatic,
31 tsTryParseExport,
32 tsTryParseExportDefaultExpression,
33 tsTryParseStatementContent,
34 tsTryParseTypeAnnotation,
35 tsTryParseTypeParameters,
36} from "../plugins/typescript";
37import {
38 eat,
39 IdentifierRole,
40 lookaheadType,
41 lookaheadTypeAndKeyword,
42 match,
43 next,
44 popTypeContext,
45 pushTypeContext,
46} from "../tokenizer";
47import {ContextualKeyword} from "../tokenizer/keywords";
48import {Scope} from "../tokenizer/state";
49import { TokenType as tt} from "../tokenizer/types";
50import {getNextContextId, isFlowEnabled, isTypeScriptEnabled, state} from "./base";
51import {
52 parseCallExpressionArguments,
53 parseExprAtom,
54 parseExpression,
55 parseExprSubscripts,
56 parseFunctionBodyAndFinish,
57 parseIdentifier,
58 parseMaybeAssign,
59 parseMethod,
60 parseParenExpression,
61 parsePropertyName,
62} from "./expression";
63import {
64 parseBindingAtom,
65 parseBindingIdentifier,
66 parseBindingList,
67 parseImportedIdentifier,
68} from "./lval";
69import {
70 canInsertSemicolon,
71 eatContextual,
72 expect,
73 expectContextual,
74 isContextual,
75 isLineTerminator,
76 semicolon,
77 unexpected,
78} from "./util";
79
80export function parseTopLevel() {
81 parseBlockBody(tt.eof);
82 state.scopes.push(new Scope(0, state.tokens.length, true));
83 if (state.scopeDepth !== 0) {
84 throw new Error(`Invalid scope depth at end of file: ${state.scopeDepth}`);
85 }
86 return new File(state.tokens, state.scopes);
87}
88
89// Parse a single statement.
90//
91// If expecting a statement and finding a slash operator, parse a
92// regular expression literal. This is to handle cases like
93// `if (foo) /blah/.exec(foo)`, where looking at the previous token
94// does not help.
95
96export function parseStatement(declaration) {
97 if (isFlowEnabled) {
98 if (flowTryParseStatement()) {
99 return;
100 }
101 }
102 if (match(tt.at)) {
103 parseDecorators();
104 }
105 parseStatementContent(declaration);
106}
107
108function parseStatementContent(declaration) {
109 if (isTypeScriptEnabled) {
110 if (tsTryParseStatementContent()) {
111 return;
112 }
113 }
114
115 const starttype = state.type;
116
117 // Most types of statements are recognized by the keyword they
118 // start with. Many are trivial to parse, some require a bit of
119 // complexity.
120
121 switch (starttype) {
122 case tt._break:
123 case tt._continue:
124 parseBreakContinueStatement();
125 return;
126 case tt._debugger:
127 parseDebuggerStatement();
128 return;
129 case tt._do:
130 parseDoStatement();
131 return;
132 case tt._for:
133 parseForStatement();
134 return;
135 case tt._function:
136 if (lookaheadType() === tt.dot) break;
137 if (!declaration) unexpected();
138 parseFunctionStatement();
139 return;
140
141 case tt._class:
142 if (!declaration) unexpected();
143 parseClass(true);
144 return;
145
146 case tt._if:
147 parseIfStatement();
148 return;
149 case tt._return:
150 parseReturnStatement();
151 return;
152 case tt._switch:
153 parseSwitchStatement();
154 return;
155 case tt._throw:
156 parseThrowStatement();
157 return;
158 case tt._try:
159 parseTryStatement();
160 return;
161
162 case tt._let:
163 case tt._const:
164 if (!declaration) unexpected(); // NOTE: falls through to _var
165
166 case tt._var:
167 parseVarStatement(starttype);
168 return;
169
170 case tt._while:
171 parseWhileStatement();
172 return;
173 case tt.braceL:
174 parseBlock();
175 return;
176 case tt.semi:
177 parseEmptyStatement();
178 return;
179 case tt._export:
180 case tt._import: {
181 const nextType = lookaheadType();
182 if (nextType === tt.parenL || nextType === tt.dot) {
183 break;
184 }
185 next();
186 if (starttype === tt._import) {
187 parseImport();
188 } else {
189 parseExport();
190 }
191 return;
192 }
193 case tt.name:
194 if (state.contextualKeyword === ContextualKeyword._async) {
195 const functionStart = state.start;
196 // peek ahead and see if next token is a function
197 const snapshot = state.snapshot();
198 next();
199 if (match(tt._function) && !canInsertSemicolon()) {
200 expect(tt._function);
201 parseFunction(functionStart, true);
202 return;
203 } else {
204 state.restoreFromSnapshot(snapshot);
205 }
206 }
207 default:
208 // Do nothing.
209 break;
210 }
211
212 // If the statement does not start with a statement keyword or a
213 // brace, it's an ExpressionStatement or LabeledStatement. We
214 // simply start parsing an expression, and afterwards, if the
215 // next token is a colon and the expression was a simple
216 // Identifier node, we switch to interpreting it as a label.
217 const initialTokensLength = state.tokens.length;
218 parseExpression();
219 let simpleName = null;
220 if (state.tokens.length === initialTokensLength + 1) {
221 const token = state.tokens[state.tokens.length - 1];
222 if (token.type === tt.name) {
223 simpleName = token.contextualKeyword;
224 }
225 }
226 if (simpleName == null) {
227 semicolon();
228 return;
229 }
230 if (eat(tt.colon)) {
231 parseLabeledStatement();
232 } else {
233 // This was an identifier, so we might want to handle flow/typescript-specific cases.
234 parseIdentifierStatement(simpleName);
235 }
236}
237
238export function parseDecorators() {
239 while (match(tt.at)) {
240 parseDecorator();
241 }
242}
243
244function parseDecorator() {
245 next();
246 if (eat(tt.parenL)) {
247 parseExpression();
248 expect(tt.parenR);
249 } else {
250 parseIdentifier();
251 while (eat(tt.dot)) {
252 parseIdentifier();
253 }
254 }
255 parseMaybeDecoratorArguments();
256}
257
258function parseMaybeDecoratorArguments() {
259 if (isTypeScriptEnabled) {
260 tsParseMaybeDecoratorArguments();
261 } else {
262 baseParseMaybeDecoratorArguments();
263 }
264}
265
266export function baseParseMaybeDecoratorArguments() {
267 if (eat(tt.parenL)) {
268 parseCallExpressionArguments();
269 }
270}
271
272function parseBreakContinueStatement() {
273 next();
274 if (!isLineTerminator()) {
275 parseIdentifier();
276 semicolon();
277 }
278}
279
280function parseDebuggerStatement() {
281 next();
282 semicolon();
283}
284
285function parseDoStatement() {
286 next();
287 parseStatement(false);
288 expect(tt._while);
289 parseParenExpression();
290 eat(tt.semi);
291}
292
293function parseForStatement() {
294 state.scopeDepth++;
295 const startTokenIndex = state.tokens.length;
296 parseAmbiguousForStatement();
297 const endTokenIndex = state.tokens.length;
298 state.scopes.push(new Scope(startTokenIndex, endTokenIndex, false));
299 state.scopeDepth--;
300}
301
302// Disambiguating between a `for` and a `for`/`in` or `for`/`of`
303// loop is non-trivial. Basically, we have to parse the init `var`
304// statement or expression, disallowing the `in` operator (see
305// the second parameter to `parseExpression`), and then check
306// whether the next token is `in` or `of`. When there is no init
307// part (semicolon immediately after the opening parenthesis), it
308// is a regular `for` loop.
309function parseAmbiguousForStatement() {
310 next();
311
312 let forAwait = false;
313 if (isContextual(ContextualKeyword._await)) {
314 forAwait = true;
315 next();
316 }
317 expect(tt.parenL);
318
319 if (match(tt.semi)) {
320 if (forAwait) {
321 unexpected();
322 }
323 parseFor();
324 return;
325 }
326
327 if (match(tt._var) || match(tt._let) || match(tt._const)) {
328 const varKind = state.type;
329 next();
330 parseVar(true, varKind);
331 if (match(tt._in) || isContextual(ContextualKeyword._of)) {
332 parseForIn(forAwait);
333 return;
334 }
335 parseFor();
336 return;
337 }
338
339 parseExpression(true);
340 if (match(tt._in) || isContextual(ContextualKeyword._of)) {
341 parseForIn(forAwait);
342 return;
343 }
344 if (forAwait) {
345 unexpected();
346 }
347 parseFor();
348}
349
350function parseFunctionStatement() {
351 const functionStart = state.start;
352 next();
353 parseFunction(functionStart, true);
354}
355
356function parseIfStatement() {
357 next();
358 parseParenExpression();
359 parseStatement(false);
360 if (eat(tt._else)) {
361 parseStatement(false);
362 }
363}
364
365function parseReturnStatement() {
366 next();
367
368 // In `return` (and `break`/`continue`), the keywords with
369 // optional arguments, we eagerly look for a semicolon or the
370 // possibility to insert one.
371
372 if (!isLineTerminator()) {
373 parseExpression();
374 semicolon();
375 }
376}
377
378function parseSwitchStatement() {
379 next();
380 parseParenExpression();
381 state.scopeDepth++;
382 const startTokenIndex = state.tokens.length;
383 expect(tt.braceL);
384
385 // Don't bother validation; just go through any sequence of cases, defaults, and statements.
386 while (!match(tt.braceR) && !state.error) {
387 if (match(tt._case) || match(tt._default)) {
388 const isCase = match(tt._case);
389 next();
390 if (isCase) {
391 parseExpression();
392 }
393 expect(tt.colon);
394 } else {
395 parseStatement(true);
396 }
397 }
398 next(); // Closing brace
399 const endTokenIndex = state.tokens.length;
400 state.scopes.push(new Scope(startTokenIndex, endTokenIndex, false));
401 state.scopeDepth--;
402}
403
404function parseThrowStatement() {
405 next();
406 parseExpression();
407 semicolon();
408}
409
410function parseTryStatement() {
411 next();
412
413 parseBlock();
414
415 if (match(tt._catch)) {
416 next();
417 let catchBindingStartTokenIndex = null;
418 if (match(tt.parenL)) {
419 state.scopeDepth++;
420 catchBindingStartTokenIndex = state.tokens.length;
421 expect(tt.parenL);
422 parseBindingAtom(true /* isBlockScope */);
423 expect(tt.parenR);
424 }
425 parseBlock();
426 if (catchBindingStartTokenIndex != null) {
427 // We need a special scope for the catch binding which includes the binding itself and the
428 // catch block.
429 const endTokenIndex = state.tokens.length;
430 state.scopes.push(new Scope(catchBindingStartTokenIndex, endTokenIndex, false));
431 state.scopeDepth--;
432 }
433 }
434 if (eat(tt._finally)) {
435 parseBlock();
436 }
437}
438
439export function parseVarStatement(kind) {
440 next();
441 parseVar(false, kind);
442 semicolon();
443}
444
445function parseWhileStatement() {
446 next();
447 parseParenExpression();
448 parseStatement(false);
449}
450
451function parseEmptyStatement() {
452 next();
453}
454
455function parseLabeledStatement() {
456 parseStatement(true);
457}
458
459/**
460 * Parse a statement starting with an identifier of the given name. Subclasses match on the name
461 * to handle statements like "declare".
462 */
463function parseIdentifierStatement(contextualKeyword) {
464 if (isTypeScriptEnabled) {
465 tsParseIdentifierStatement(contextualKeyword);
466 } else if (isFlowEnabled) {
467 flowParseIdentifierStatement(contextualKeyword);
468 } else {
469 semicolon();
470 }
471}
472
473// Parse a semicolon-enclosed block of statements, handling `"use
474// strict"` declarations when `allowStrict` is true (used for
475// function bodies).
476
477export function parseBlock(
478 allowDirectives = false,
479 isFunctionScope = false,
480 contextId = 0,
481) {
482 const startTokenIndex = state.tokens.length;
483 state.scopeDepth++;
484 expect(tt.braceL);
485 if (contextId) {
486 state.tokens[state.tokens.length - 1].contextId = contextId;
487 }
488 parseBlockBody(tt.braceR);
489 if (contextId) {
490 state.tokens[state.tokens.length - 1].contextId = contextId;
491 }
492 const endTokenIndex = state.tokens.length;
493 state.scopes.push(new Scope(startTokenIndex, endTokenIndex, isFunctionScope));
494 state.scopeDepth--;
495}
496
497export function parseBlockBody(end) {
498 while (!eat(end) && !state.error) {
499 parseStatement(true);
500 }
501}
502
503// Parse a regular `for` loop. The disambiguation code in
504// `parseStatement` will already have parsed the init statement or
505// expression.
506
507function parseFor() {
508 expect(tt.semi);
509 if (!match(tt.semi)) {
510 parseExpression();
511 }
512 expect(tt.semi);
513 if (!match(tt.parenR)) {
514 parseExpression();
515 }
516 expect(tt.parenR);
517 parseStatement(false);
518}
519
520// Parse a `for`/`in` and `for`/`of` loop, which are almost
521// same from parser's perspective.
522
523function parseForIn(forAwait) {
524 if (forAwait) {
525 eatContextual(ContextualKeyword._of);
526 } else {
527 next();
528 }
529 parseExpression();
530 expect(tt.parenR);
531 parseStatement(false);
532}
533
534// Parse a list of variable declarations.
535
536function parseVar(isFor, kind) {
537 while (true) {
538 const isBlockScope = kind === tt._const || kind === tt._let;
539 parseVarHead(isBlockScope);
540 if (eat(tt.eq)) {
541 const eqIndex = state.tokens.length - 1;
542 parseMaybeAssign(isFor);
543 state.tokens[eqIndex].rhsEndIndex = state.tokens.length;
544 }
545 if (!eat(tt.comma)) {
546 break;
547 }
548 }
549}
550
551function parseVarHead(isBlockScope) {
552 parseBindingAtom(isBlockScope);
553 if (isTypeScriptEnabled) {
554 tsAfterParseVarHead();
555 } else if (isFlowEnabled) {
556 flowAfterParseVarHead();
557 }
558}
559
560// Parse a function declaration or literal (depending on the
561// `isStatement` parameter).
562
563export function parseFunction(
564 functionStart,
565 isStatement,
566 optionalId = false,
567) {
568 if (match(tt.star)) {
569 next();
570 }
571
572 if (isStatement && !optionalId && !match(tt.name) && !match(tt._yield)) {
573 unexpected();
574 }
575
576 let nameScopeStartTokenIndex = null;
577
578 if (match(tt.name)) {
579 // Expression-style functions should limit their name's scope to the function body, so we make
580 // a new function scope to enforce that.
581 if (!isStatement) {
582 nameScopeStartTokenIndex = state.tokens.length;
583 state.scopeDepth++;
584 }
585 parseBindingIdentifier(false);
586 }
587
588 const startTokenIndex = state.tokens.length;
589 state.scopeDepth++;
590 parseFunctionParams();
591 parseFunctionBodyAndFinish(functionStart);
592 const endTokenIndex = state.tokens.length;
593 // In addition to the block scope of the function body, we need a separate function-style scope
594 // that includes the params.
595 state.scopes.push(new Scope(startTokenIndex, endTokenIndex, true));
596 state.scopeDepth--;
597 if (nameScopeStartTokenIndex !== null) {
598 state.scopes.push(new Scope(nameScopeStartTokenIndex, endTokenIndex, true));
599 state.scopeDepth--;
600 }
601}
602
603export function parseFunctionParams(
604 allowModifiers = false,
605 funcContextId = 0,
606) {
607 if (isTypeScriptEnabled) {
608 tsStartParseFunctionParams();
609 } else if (isFlowEnabled) {
610 flowStartParseFunctionParams();
611 }
612
613 expect(tt.parenL);
614 if (funcContextId) {
615 state.tokens[state.tokens.length - 1].contextId = funcContextId;
616 }
617 parseBindingList(
618 tt.parenR,
619 false /* isBlockScope */,
620 false /* allowEmpty */,
621 allowModifiers,
622 funcContextId,
623 );
624 if (funcContextId) {
625 state.tokens[state.tokens.length - 1].contextId = funcContextId;
626 }
627}
628
629// Parse a class declaration or literal (depending on the
630// `isStatement` parameter).
631
632export function parseClass(isStatement, optionalId = false) {
633 // Put a context ID on the class keyword, the open-brace, and the close-brace, so that later
634 // code can easily navigate to meaningful points on the class.
635 const contextId = getNextContextId();
636
637 next();
638 state.tokens[state.tokens.length - 1].contextId = contextId;
639 state.tokens[state.tokens.length - 1].isExpression = !isStatement;
640 // Like with functions, we declare a special "name scope" from the start of the name to the end
641 // of the class, but only with expression-style classes, to represent the fact that the name is
642 // available to the body of the class but not an outer declaration.
643 let nameScopeStartTokenIndex = null;
644 if (!isStatement) {
645 nameScopeStartTokenIndex = state.tokens.length;
646 state.scopeDepth++;
647 }
648 parseClassId(isStatement, optionalId);
649 parseClassSuper();
650 const openBraceIndex = state.tokens.length;
651 parseClassBody(contextId);
652 if (state.error) {
653 return;
654 }
655 state.tokens[openBraceIndex].contextId = contextId;
656 state.tokens[state.tokens.length - 1].contextId = contextId;
657 if (nameScopeStartTokenIndex !== null) {
658 const endTokenIndex = state.tokens.length;
659 state.scopes.push(new Scope(nameScopeStartTokenIndex, endTokenIndex, false));
660 state.scopeDepth--;
661 }
662}
663
664function isClassProperty() {
665 return match(tt.eq) || match(tt.semi) || match(tt.braceR) || match(tt.bang) || match(tt.colon);
666}
667
668function isClassMethod() {
669 return match(tt.parenL) || match(tt.lessThan);
670}
671
672function parseClassBody(classContextId) {
673 expect(tt.braceL);
674
675 while (!eat(tt.braceR) && !state.error) {
676 if (eat(tt.semi)) {
677 continue;
678 }
679
680 if (match(tt.at)) {
681 parseDecorator();
682 continue;
683 }
684 const memberStart = state.start;
685 parseClassMember(memberStart, classContextId);
686 }
687}
688
689function parseClassMember(memberStart, classContextId) {
690 if (isTypeScriptEnabled) {
691 tsParseAccessModifier();
692 }
693 let isStatic = false;
694 if (match(tt.name) && state.contextualKeyword === ContextualKeyword._static) {
695 parseIdentifier(); // eats 'static'
696 if (isClassMethod()) {
697 parseClassMethod(memberStart, /* isConstructor */ false);
698 return;
699 } else if (isClassProperty()) {
700 parseClassProperty();
701 return;
702 }
703 // otherwise something static
704 state.tokens[state.tokens.length - 1].type = tt._static;
705 isStatic = true;
706 }
707
708 parseClassMemberWithIsStatic(memberStart, isStatic, classContextId);
709}
710
711function parseClassMemberWithIsStatic(
712 memberStart,
713 isStatic,
714 classContextId,
715) {
716 if (isTypeScriptEnabled) {
717 if (tsTryParseClassMemberWithIsStatic(isStatic, classContextId)) {
718 return;
719 }
720 }
721 if (eat(tt.star)) {
722 // a generator
723 parseClassPropertyName(classContextId);
724 parseClassMethod(memberStart, /* isConstructor */ false);
725 return;
726 }
727
728 // Get the identifier name so we can tell if it's actually a keyword like "async", "get", or
729 // "set".
730 parseClassPropertyName(classContextId);
731 let isConstructor = false;
732 const token = state.tokens[state.tokens.length - 1];
733 // We allow "constructor" as either an identifier or a string.
734 if (token.contextualKeyword === ContextualKeyword._constructor) {
735 isConstructor = true;
736 }
737 parsePostMemberNameModifiers();
738
739 if (isClassMethod()) {
740 parseClassMethod(memberStart, isConstructor);
741 } else if (isClassProperty()) {
742 parseClassProperty();
743 } else if (token.contextualKeyword === ContextualKeyword._async && !isLineTerminator()) {
744 state.tokens[state.tokens.length - 1].type = tt._async;
745 // an async method
746 const isGenerator = match(tt.star);
747 if (isGenerator) {
748 next();
749 }
750
751 // The so-called parsed name would have been "async": get the real name.
752 parseClassPropertyName(classContextId);
753 parsePostMemberNameModifiers();
754 parseClassMethod(memberStart, false /* isConstructor */);
755 } else if (
756 (token.contextualKeyword === ContextualKeyword._get ||
757 token.contextualKeyword === ContextualKeyword._set) &&
758 !(isLineTerminator() && match(tt.star))
759 ) {
760 if (token.contextualKeyword === ContextualKeyword._get) {
761 state.tokens[state.tokens.length - 1].type = tt._get;
762 } else {
763 state.tokens[state.tokens.length - 1].type = tt._set;
764 }
765 // `get\n*` is an uninitialized property named 'get' followed by a generator.
766 // a getter or setter
767 // The so-called parsed name would have been "get/set": get the real name.
768 parseClassPropertyName(classContextId);
769 parseClassMethod(memberStart, /* isConstructor */ false);
770 } else if (isLineTerminator()) {
771 // an uninitialized class property (due to ASI, since we don't otherwise recognize the next token)
772 parseClassProperty();
773 } else {
774 unexpected();
775 }
776}
777
778function parseClassMethod(functionStart, isConstructor) {
779 if (isTypeScriptEnabled) {
780 tsTryParseTypeParameters();
781 } else if (isFlowEnabled) {
782 if (match(tt.lessThan)) {
783 flowParseTypeParameterDeclaration();
784 }
785 }
786 parseMethod(functionStart, isConstructor);
787}
788
789// Return the name of the class property, if it is a simple identifier.
790export function parseClassPropertyName(classContextId) {
791 parsePropertyName(classContextId);
792}
793
794export function parsePostMemberNameModifiers() {
795 if (isTypeScriptEnabled) {
796 const oldIsType = pushTypeContext(0);
797 eat(tt.question);
798 popTypeContext(oldIsType);
799 }
800}
801
802export function parseClassProperty() {
803 if (isTypeScriptEnabled) {
804 eat(tt.bang);
805 tsTryParseTypeAnnotation();
806 } else if (isFlowEnabled) {
807 if (match(tt.colon)) {
808 flowParseTypeAnnotation();
809 }
810 }
811
812 if (match(tt.eq)) {
813 const equalsTokenIndex = state.tokens.length;
814 next();
815 parseMaybeAssign();
816 state.tokens[equalsTokenIndex].rhsEndIndex = state.tokens.length;
817 }
818 semicolon();
819}
820
821function parseClassId(isStatement, optionalId = false) {
822 if (
823 isTypeScriptEnabled &&
824 (!isStatement || optionalId) &&
825 isContextual(ContextualKeyword._implements)
826 ) {
827 return;
828 }
829
830 if (match(tt.name)) {
831 parseBindingIdentifier(true);
832 }
833
834 if (isTypeScriptEnabled) {
835 tsTryParseTypeParameters();
836 } else if (isFlowEnabled) {
837 if (match(tt.lessThan)) {
838 flowParseTypeParameterDeclaration();
839 }
840 }
841}
842
843// Returns true if there was a superclass.
844function parseClassSuper() {
845 let hasSuper = false;
846 if (eat(tt._extends)) {
847 parseExprSubscripts();
848 hasSuper = true;
849 } else {
850 hasSuper = false;
851 }
852 if (isTypeScriptEnabled) {
853 tsAfterParseClassSuper(hasSuper);
854 } else if (isFlowEnabled) {
855 flowAfterParseClassSuper(hasSuper);
856 }
857}
858
859// Parses module export declaration.
860
861export function parseExport() {
862 const exportIndex = state.tokens.length - 1;
863 if (isTypeScriptEnabled) {
864 if (tsTryParseExport()) {
865 return;
866 }
867 }
868 // export * from '...'
869 if (shouldParseExportStar()) {
870 parseExportStar();
871 } else if (isExportDefaultSpecifier()) {
872 // export default from
873 parseIdentifier();
874 if (match(tt.comma) && lookaheadType() === tt.star) {
875 expect(tt.comma);
876 expect(tt.star);
877 expectContextual(ContextualKeyword._as);
878 parseIdentifier();
879 } else {
880 parseExportSpecifiersMaybe();
881 }
882 parseExportFrom();
883 } else if (eat(tt._default)) {
884 // export default ...
885 parseExportDefaultExpression();
886 } else if (shouldParseExportDeclaration()) {
887 parseExportDeclaration();
888 } else {
889 // export { x, y as z } [from '...']
890 parseExportSpecifiers();
891 parseExportFrom();
892 }
893 state.tokens[exportIndex].rhsEndIndex = state.tokens.length;
894}
895
896function parseExportDefaultExpression() {
897 if (isTypeScriptEnabled) {
898 if (tsTryParseExportDefaultExpression()) {
899 return;
900 }
901 }
902 const functionStart = state.start;
903 if (eat(tt._function)) {
904 parseFunction(functionStart, true, true);
905 } else if (isContextual(ContextualKeyword._async) && lookaheadType() === tt._function) {
906 // async function declaration
907 eatContextual(ContextualKeyword._async);
908 eat(tt._function);
909 parseFunction(functionStart, true, true);
910 } else if (match(tt._class)) {
911 parseClass(true, true);
912 } else if (match(tt.at)) {
913 parseDecorators();
914 parseClass(true, true);
915 } else {
916 parseMaybeAssign();
917 semicolon();
918 }
919}
920
921function parseExportDeclaration() {
922 if (isTypeScriptEnabled) {
923 tsParseExportDeclaration();
924 } else if (isFlowEnabled) {
925 flowParseExportDeclaration();
926 } else {
927 parseStatement(true);
928 }
929}
930
931function isExportDefaultSpecifier() {
932 if (isTypeScriptEnabled && tsIsDeclarationStart()) {
933 return false;
934 } else if (isFlowEnabled && flowShouldDisallowExportDefaultSpecifier()) {
935 return false;
936 }
937 if (match(tt.name)) {
938 return state.contextualKeyword !== ContextualKeyword._async;
939 }
940
941 if (!match(tt._default)) {
942 return false;
943 }
944
945 const lookahead = lookaheadTypeAndKeyword();
946 return (
947 lookahead.type === tt.comma ||
948 (lookahead.type === tt.name && lookahead.contextualKeyword === ContextualKeyword._from)
949 );
950}
951
952function parseExportSpecifiersMaybe() {
953 if (eat(tt.comma)) {
954 parseExportSpecifiers();
955 }
956}
957
958export function parseExportFrom() {
959 if (eatContextual(ContextualKeyword._from)) {
960 parseExprAtom();
961 }
962 semicolon();
963}
964
965function shouldParseExportStar() {
966 if (isFlowEnabled) {
967 return flowShouldParseExportStar();
968 } else {
969 return match(tt.star);
970 }
971}
972
973function parseExportStar() {
974 if (isFlowEnabled) {
975 flowParseExportStar();
976 } else {
977 baseParseExportStar();
978 }
979}
980
981export function baseParseExportStar() {
982 expect(tt.star);
983
984 if (isContextual(ContextualKeyword._as)) {
985 parseExportNamespace();
986 } else {
987 parseExportFrom();
988 }
989}
990
991function parseExportNamespace() {
992 next();
993 state.tokens[state.tokens.length - 1].type = tt._as;
994 parseIdentifier();
995 parseExportSpecifiersMaybe();
996 parseExportFrom();
997}
998
999function shouldParseExportDeclaration() {
1000 return (
1001 (isTypeScriptEnabled && tsIsDeclarationStart()) ||
1002 (isFlowEnabled && flowShouldParseExportDeclaration()) ||
1003 state.type === tt._var ||
1004 state.type === tt._const ||
1005 state.type === tt._let ||
1006 state.type === tt._function ||
1007 state.type === tt._class ||
1008 isContextual(ContextualKeyword._async) ||
1009 match(tt.at)
1010 );
1011}
1012
1013// Parses a comma-separated list of module exports.
1014export function parseExportSpecifiers() {
1015 let first = true;
1016
1017 // export { x, y as z } [from '...']
1018 expect(tt.braceL);
1019
1020 while (!eat(tt.braceR) && !state.error) {
1021 if (first) {
1022 first = false;
1023 } else {
1024 expect(tt.comma);
1025 if (eat(tt.braceR)) {
1026 break;
1027 }
1028 }
1029
1030 parseIdentifier();
1031 state.tokens[state.tokens.length - 1].identifierRole = IdentifierRole.ExportAccess;
1032 if (eatContextual(ContextualKeyword._as)) {
1033 parseIdentifier();
1034 }
1035 }
1036}
1037
1038// Parses import declaration.
1039
1040export function parseImport() {
1041 if (isTypeScriptEnabled && match(tt.name) && lookaheadType() === tt.eq) {
1042 tsParseImportEqualsDeclaration();
1043 return;
1044 }
1045 if (isTypeScriptEnabled) {
1046 eatContextual(ContextualKeyword._type);
1047 }
1048
1049 // import '...'
1050 if (match(tt.string)) {
1051 parseExprAtom();
1052 } else {
1053 parseImportSpecifiers();
1054 expectContextual(ContextualKeyword._from);
1055 parseExprAtom();
1056 }
1057 semicolon();
1058}
1059
1060// eslint-disable-next-line no-unused-vars
1061function shouldParseDefaultImport() {
1062 return match(tt.name);
1063}
1064
1065function parseImportSpecifierLocal() {
1066 parseImportedIdentifier();
1067}
1068
1069// Parses a comma-separated list of module imports.
1070function parseImportSpecifiers() {
1071 if (isFlowEnabled) {
1072 flowStartParseImportSpecifiers();
1073 }
1074
1075 let first = true;
1076 if (shouldParseDefaultImport()) {
1077 // import defaultObj, { x, y as z } from '...'
1078 parseImportSpecifierLocal();
1079
1080 if (!eat(tt.comma)) return;
1081 }
1082
1083 if (match(tt.star)) {
1084 next();
1085 expectContextual(ContextualKeyword._as);
1086
1087 parseImportSpecifierLocal();
1088
1089 return;
1090 }
1091
1092 expect(tt.braceL);
1093 while (!eat(tt.braceR) && !state.error) {
1094 if (first) {
1095 first = false;
1096 } else {
1097 // Detect an attempt to deep destructure
1098 if (eat(tt.colon)) {
1099 unexpected(
1100 "ES2015 named imports do not destructure. Use another statement for destructuring after the import.",
1101 );
1102 }
1103
1104 expect(tt.comma);
1105 if (eat(tt.braceR)) {
1106 break;
1107 }
1108 }
1109
1110 parseImportSpecifier();
1111 }
1112}
1113
1114function parseImportSpecifier() {
1115 if (isFlowEnabled) {
1116 flowParseImportSpecifier();
1117 return;
1118 }
1119 parseImportedIdentifier();
1120 if (isContextual(ContextualKeyword._as)) {
1121 state.tokens[state.tokens.length - 1].identifierRole = IdentifierRole.ImportAccess;
1122 next();
1123 parseImportedIdentifier();
1124 }
1125}