UNPKG

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