statement.js 33 KB

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