123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- import {flowParseAssignableListItemTypes} from "../plugins/flow";
- import {tsParseAssignableListItemTypes, tsParseModifiers} from "../plugins/typescript";
- import {
- eat,
- IdentifierRole,
- match,
- next,
- popTypeContext,
- pushTypeContext,
- } from "../tokenizer/index";
- import {ContextualKeyword} from "../tokenizer/keywords";
- import {TokenType, TokenType as tt} from "../tokenizer/types";
- import {isFlowEnabled, isTypeScriptEnabled, state} from "./base";
- import {parseIdentifier, parseMaybeAssign, parseObj} from "./expression";
- import {expect, unexpected} from "./util";
- export function parseSpread() {
- next();
- parseMaybeAssign(false);
- }
- export function parseRest(isBlockScope) {
- next();
- parseBindingAtom(isBlockScope);
- }
- export function parseBindingIdentifier(isBlockScope) {
- parseIdentifier();
- markPriorBindingIdentifier(isBlockScope);
- }
- export function parseImportedIdentifier() {
- parseIdentifier();
- state.tokens[state.tokens.length - 1].identifierRole = IdentifierRole.ImportDeclaration;
- }
- export function markPriorBindingIdentifier(isBlockScope) {
- let identifierRole;
- if (state.scopeDepth === 0) {
- identifierRole = IdentifierRole.TopLevelDeclaration;
- } else if (isBlockScope) {
- identifierRole = IdentifierRole.BlockScopedDeclaration;
- } else {
- identifierRole = IdentifierRole.FunctionScopedDeclaration;
- }
- state.tokens[state.tokens.length - 1].identifierRole = identifierRole;
- }
- // Parses lvalue (assignable) atom.
- export function parseBindingAtom(isBlockScope) {
- switch (state.type) {
- case tt._this: {
- // In TypeScript, "this" may be the name of a parameter, so allow it.
- const oldIsType = pushTypeContext(0);
- next();
- popTypeContext(oldIsType);
- return;
- }
- case tt._yield:
- case tt.name: {
- state.type = tt.name;
- parseBindingIdentifier(isBlockScope);
- return;
- }
- case tt.bracketL: {
- next();
- parseBindingList(tt.bracketR, isBlockScope, true /* allowEmpty */);
- return;
- }
- case tt.braceL:
- parseObj(true, isBlockScope);
- return;
- default:
- unexpected();
- }
- }
- export function parseBindingList(
- close,
- isBlockScope,
- allowEmpty = false,
- allowModifiers = false,
- contextId = 0,
- ) {
- let first = true;
- let hasRemovedComma = false;
- const firstItemTokenIndex = state.tokens.length;
- while (!eat(close) && !state.error) {
- if (first) {
- first = false;
- } else {
- expect(tt.comma);
- state.tokens[state.tokens.length - 1].contextId = contextId;
- // After a "this" type in TypeScript, we need to set the following comma (if any) to also be
- // a type token so that it will be removed.
- if (!hasRemovedComma && state.tokens[firstItemTokenIndex].isType) {
- state.tokens[state.tokens.length - 1].isType = true;
- hasRemovedComma = true;
- }
- }
- if (allowEmpty && match(tt.comma)) {
- // Empty item; nothing further to parse for this item.
- } else if (eat(close)) {
- break;
- } else if (match(tt.ellipsis)) {
- parseRest(isBlockScope);
- parseAssignableListItemTypes();
- // Support rest element trailing commas allowed by TypeScript <2.9.
- eat(TokenType.comma);
- expect(close);
- break;
- } else {
- parseAssignableListItem(allowModifiers, isBlockScope);
- }
- }
- }
- function parseAssignableListItem(allowModifiers, isBlockScope) {
- if (allowModifiers) {
- tsParseModifiers([
- ContextualKeyword._public,
- ContextualKeyword._protected,
- ContextualKeyword._private,
- ContextualKeyword._readonly,
- ContextualKeyword._override,
- ]);
- }
- parseMaybeDefault(isBlockScope);
- parseAssignableListItemTypes();
- parseMaybeDefault(isBlockScope, true /* leftAlreadyParsed */);
- }
- function parseAssignableListItemTypes() {
- if (isFlowEnabled) {
- flowParseAssignableListItemTypes();
- } else if (isTypeScriptEnabled) {
- tsParseAssignableListItemTypes();
- }
- }
- // Parses assignment pattern around given atom if possible.
- export function parseMaybeDefault(isBlockScope, leftAlreadyParsed = false) {
- if (!leftAlreadyParsed) {
- parseBindingAtom(isBlockScope);
- }
- if (!eat(tt.eq)) {
- return;
- }
- const eqIndex = state.tokens.length - 1;
- parseMaybeAssign();
- state.tokens[eqIndex].rhsEndIndex = state.tokens.length;
- }
|