import { File } from "../index" ; import { tsAfterParseClassSuper , tsAfterParseVarHead , tsIsDeclarationStart , tsParseAccessModifier , tsParseExportDeclaration , tsParseIdentifierStatement , tsParseImportEqualsDeclaration , tsParseMaybeDecoratorArguments , tsParseModifier , tsStartParseFunctionParams , tsTryParseClassMemberWithIsStatic , tsTryParseExport , tsTryParseExportDefaultExpression , tsTryParseStatementContent , tsTryParseTypeAnnotation , tsTryParseTypeParameters , } from "../plugins/typescript" ; import { eat , lookaheadType , lookaheadTypeAndKeyword , match , next , nextTokenStart , nextTokenStartSince , popTypeContext , pushTypeContext , } from "../tokenizer" ; import { ContextualKeyword } from "../tokenizer/keywords" ; import { TokenType , TokenType as tt } from "../tokenizer/types" ; import { charCodes } from "../util/charcodes" ; import { input , state } from "./base" ; import { parseCallExpressionArguments , parseExprAtom , parseExpression , parseExprSubscripts , parseFunctionBodyAndFinish , parseIdentifier , parseMaybeAssign , parseMethod , parseParenExpression , parsePropertyName , } from "./expression" ; import { parseBindingAtom , parseBindingIdentifier , parseBindingList , parseImportedIdentifier , } from "./lval" ; import { canInsertSemicolon , eatContextual , expect , expectContextual , isContextual , isLineTerminator , semicolon , unexpected , } from "./util" ; export function parseTopLevel ( ) { parseBlockBody ( tt . eof ) ; return new File ( state . tokens ) ; } export function parseStatement ( declaration ) { if ( match ( tt . at ) ) { parseDecorators ( ) ; } parseStatementContent ( declaration ) ; } function parseStatementContent ( declaration ) { if ( true ) { if ( tsTryParseStatementContent ( ) ) { return ; } } const starttype = state . type ; switch ( starttype ) { case tt . _break : case tt . _continue : parseBreakContinueStatement ( ) ; return ; case tt . _debugger : parseDebuggerStatement ( ) ; return ; case tt . _do : parseDoStatement ( ) ; return ; case tt . _for : parseForStatement ( ) ; return ; case tt . _function : if ( lookaheadType ( ) === tt . dot ) break ; if ( ! declaration ) unexpected ( ) ; parseFunctionStatement ( ) ; return ; case tt . _class : if ( ! declaration ) unexpected ( ) ; parseClass ( true ) ; return ; case tt . _if : parseIfStatement ( ) ; return ; case tt . _return : parseReturnStatement ( ) ; return ; case tt . _switch : parseSwitchStatement ( ) ; return ; case tt . _throw : parseThrowStatement ( ) ; return ; case tt . _try : parseTryStatement ( ) ; return ; case tt . _let : case tt . _const : if ( ! declaration ) unexpected ( ) ; case tt . _var : parseVarStatement ( starttype ) ; return ; case tt . _while : parseWhileStatement ( ) ; return ; case tt . braceL : parseBlock ( ) ; return ; case tt . semi : parseEmptyStatement ( ) ; return ; case tt . _export : case tt . _import : { const nextType = lookaheadType ( ) ; if ( nextType === tt . parenL || nextType === tt . dot ) { break ; } next ( ) ; if ( starttype === tt . _import ) { parseImport ( ) ; } else { parseExport ( ) ; } return ; } case tt . name : if ( state . contextualKeyword === ContextualKeyword . _async ) { const functionStart = state . start ; const snapshot = state . snapshot ( ) ; next ( ) ; if ( match ( tt . _function ) && ! canInsertSemicolon ( ) ) { expect ( tt . _function ) ; parseFunction ( functionStart , true ) ; return ; } else { state . restoreFromSnapshot ( snapshot ) ; } } default : break ; } const initialTokensLength = state . tokens . length ; parseExpression ( ) ; let simpleName = - 1 ; if ( state . tokens . length === initialTokensLength + 1 ) { const token = state . tokens [ state . tokens . length - 1 ] ; if ( token . type === tt . name ) { simpleName = token . contextualKeyword ; } } if ( simpleName == - 1 ) { semicolon ( ) ; return ; } if ( eat ( tt . colon ) ) { parseLabeledStatement ( ) ; } else { parseIdentifierStatement ( simpleName ) ; } } export function parseDecorators ( ) { while ( match ( tt . at ) ) { parseDecorator ( ) ; } } function parseDecorator ( ) { next ( ) ; if ( eat ( tt . parenL ) ) { parseExpression ( ) ; expect ( tt . parenR ) ; } else { parseIdentifier ( ) ; while ( eat ( tt . dot ) ) { parseIdentifier ( ) ; } } parseMaybeDecoratorArguments ( ) ; } function parseMaybeDecoratorArguments ( ) { if ( true ) { tsParseMaybeDecoratorArguments ( ) ; } } export function baseParseMaybeDecoratorArguments ( ) { if ( eat ( tt . parenL ) ) { parseCallExpressionArguments ( ) ; } } function parseBreakContinueStatement ( ) { next ( ) ; if ( ! isLineTerminator ( ) ) { parseIdentifier ( ) ; semicolon ( ) ; } } function parseDebuggerStatement ( ) { next ( ) ; semicolon ( ) ; } function parseDoStatement ( ) { next ( ) ; parseStatement ( false ) ; expect ( tt . _while ) ; parseParenExpression ( ) ; eat ( tt . semi ) ; } function parseForStatement ( ) { parseAmbiguousForStatement ( ) ; } function parseAmbiguousForStatement ( ) { next ( ) ; let forAwait = false ; if ( isContextual ( ContextualKeyword . _await ) ) { forAwait = true ; next ( ) ; } expect ( tt . parenL ) ; if ( match ( tt . semi ) ) { if ( forAwait ) { unexpected ( ) ; } parseFor ( ) ; return ; } if ( match ( tt . _var ) || match ( tt . _let ) || match ( tt . _const ) ) { const varKind = state . type ; next ( ) ; parseVar ( true , varKind ) ; if ( match ( tt . _in ) || isContextual ( ContextualKeyword . _of ) ) { parseForIn ( forAwait ) ; return ; } parseFor ( ) ; return ; } parseExpression ( true ) ; if ( match ( tt . _in ) || isContextual ( ContextualKeyword . _of ) ) { parseForIn ( forAwait ) ; return ; } if ( forAwait ) { unexpected ( ) ; } parseFor ( ) ; } function parseFunctionStatement ( ) { const functionStart = state . start ; next ( ) ; parseFunction ( functionStart , true ) ; } function parseIfStatement ( ) { next ( ) ; parseParenExpression ( ) ; parseStatement ( false ) ; if ( eat ( tt . _else ) ) { parseStatement ( false ) ; } } function parseReturnStatement ( ) { next ( ) ; if ( ! isLineTerminator ( ) ) { parseExpression ( ) ; semicolon ( ) ; } } function parseSwitchStatement ( ) { next ( ) ; parseParenExpression ( ) ; expect ( tt . braceL ) ; while ( ! match ( tt . braceR ) && ! state . error ) { if ( match ( tt . _case ) || match ( tt . _default ) ) { const isCase = match ( tt . _case ) ; next ( ) ; if ( isCase ) { parseExpression ( ) ; } expect ( tt . colon ) ; } else { parseStatement ( true ) ; } } next ( ) ; } function parseThrowStatement ( ) { next ( ) ; parseExpression ( ) ; semicolon ( ) ; } function parseCatchClauseParam ( ) { parseBindingAtom ( true ) ; if ( true ) { tsTryParseTypeAnnotation ( ) ; } } function parseTryStatement ( ) { next ( ) ; parseBlock ( ) ; if ( match ( tt . _catch ) ) { next ( ) ; let catchBindingStartTokenIndex = - 1 ; if ( match ( tt . parenL ) ) { catchBindingStartTokenIndex = state . tokens . length ; expect ( tt . parenL ) ; parseCatchClauseParam ( ) ; expect ( tt . parenR ) ; } parseBlock ( ) ; if ( catchBindingStartTokenIndex !== - 1 ) { } } if ( eat ( tt . _finally ) ) { parseBlock ( ) ; } } export function parseVarStatement ( kind ) { next ( ) ; parseVar ( false , kind ) ; semicolon ( ) ; } function parseWhileStatement ( ) { next ( ) ; parseParenExpression ( ) ; parseStatement ( false ) ; } function parseEmptyStatement ( ) { next ( ) ; } function parseLabeledStatement ( ) { parseStatement ( true ) ; } /**
 * Parse a statement starting with an identifier of the given name. Subclasses match on the name
 * to handle statements like "declare".
 */ function parseIdentifierStatement ( contextualKeyword ) { if ( true ) { tsParseIdentifierStatement ( contextualKeyword ) ; } } export function parseBlock ( isFunctionScope = false ) { const startTokenIndex = state . tokens . length ; expect ( tt . braceL ) ; parseBlockBody ( tt . braceR ) ; } export function parseBlockBody ( end ) { while ( ! eat ( end ) && ! state . error ) { parseStatement ( true ) ; } } function parseFor ( ) { expect ( tt . semi ) ; if ( ! match ( tt . semi ) ) { parseExpression ( ) ; } expect ( tt . semi ) ; if ( ! match ( tt . parenR ) ) { parseExpression ( ) ; } expect ( tt . parenR ) ; parseStatement ( false ) ; } function parseForIn ( forAwait ) { if ( forAwait ) { eatContextual ( ContextualKeyword . _of ) ; } else { next ( ) ; } parseExpression ( ) ; expect ( tt . parenR ) ; parseStatement ( false ) ; } function parseVar ( isFor , kind ) { while ( true ) { const isBlockScope = kind === tt . _const || kind === tt . _let ; parseVarHead ( isBlockScope ) ; if ( eat ( tt . eq ) ) { const eqIndex = state . tokens . length - 1 ; parseMaybeAssign ( isFor ) ; state . tokens [ eqIndex ] . rhsEndIndex = state . tokens . length ; } if ( ! eat ( tt . comma ) ) { break ; } } } function parseVarHead ( isBlockScope ) { parseBindingAtom ( isBlockScope ) ; if ( true ) { tsAfterParseVarHead ( ) ; } } export function parseFunction ( functionStart , isStatement , optionalId = false ) { if ( match ( tt . star ) ) { next ( ) ; } if ( isStatement && ! optionalId && ! match ( tt . name ) && ! match ( tt . _yield ) ) { unexpected ( ) ; } let nameScopeStartTokenIndex = - 1 ; if ( match ( tt . name ) ) { if ( ! isStatement ) { nameScopeStartTokenIndex = state . tokens . length ; } parseBindingIdentifier ( false ) ; } parseFunctionParams ( ) ; parseFunctionBodyAndFinish ( functionStart ) ; if ( nameScopeStartTokenIndex !== - 1 ) { } } export function parseFunctionParams ( allowModifiers = false ) { if ( true ) { tsStartParseFunctionParams ( ) ; } expect ( tt . parenL ) ; parseBindingList ( tt . parenR , false , false , allowModifiers ) ; } export function parseClass ( isStatement , optionalId = false ) { next ( ) ; let nameScopeStartTokenIndex = - 1 ; if ( ! isStatement ) { nameScopeStartTokenIndex = state . tokens . length ; } parseClassId ( isStatement , optionalId ) ; parseClassSuper ( ) ; const openBraceIndex = state . tokens . length ; parseClassBody ( ) ; if ( state . error ) { return ; } if ( nameScopeStartTokenIndex !== - 1 ) { const endTokenIndex = state . tokens . length ; } } function isClassProperty ( ) { return match ( tt . eq ) || match ( tt . semi ) || match ( tt . braceR ) || match ( tt . bang ) || match ( tt . colon ) ; } function isClassMethod ( ) { return match ( tt . parenL ) || match ( tt . lessThan ) ; } function parseClassBody ( ) { expect ( tt . braceL ) ; while ( ! eat ( tt . braceR ) && ! state . error ) { if ( eat ( tt . semi ) ) { continue ; } if ( match ( tt . at ) ) { parseDecorator ( ) ; continue ; } const memberStart = state . start ; parseClassMember ( memberStart ) ; } } function parseClassMember ( memberStart ) { if ( true ) { tsParseModifier ( [ ContextualKeyword . _declare ] ) ; tsParseAccessModifier ( ) ; tsParseModifier ( [ ContextualKeyword . _declare ] ) ; } let isStatic = false ; if ( match ( tt . name ) && state . contextualKeyword === ContextualKeyword . _static ) { parseIdentifier ( ) ; if ( isClassMethod ( ) ) { parseClassMethod ( memberStart , false ) ; return ; } else if ( isClassProperty ( ) ) { parseClassProperty ( ) ; return ; } state . tokens [ state . tokens . length - 1 ] . type = tt . _static ; isStatic = true ; if ( match ( tt . braceL ) ) { parseBlock ( ) ; return ; } } parseClassMemberWithIsStatic ( memberStart , isStatic ) ; } function parseClassMemberWithIsStatic ( memberStart , isStatic ) { if ( true ) { if ( tsTryParseClassMemberWithIsStatic ( isStatic ) ) { return ; } } if ( eat ( tt . star ) ) { parseClassPropertyName ( ) ; parseClassMethod ( memberStart , false ) ; return ; } parseClassPropertyName ( ) ; let isConstructor = false ; const token = state . tokens [ state . tokens . length - 1 ] ; if ( token . contextualKeyword === ContextualKeyword . _constructor ) { isConstructor = true ; } parsePostMemberNameModifiers ( ) ; if ( isClassMethod ( ) ) { parseClassMethod ( memberStart , isConstructor ) ; } else if ( isClassProperty ( ) ) { parseClassProperty ( ) ; } else if ( token . contextualKeyword === ContextualKeyword . _async && ! isLineTerminator ( ) ) { state . tokens [ state . tokens . length - 1 ] . type = tt . _async ; const isGenerator = match ( tt . star ) ; if ( isGenerator ) { next ( ) ; } parseClassPropertyName ( ) ; parsePostMemberNameModifiers ( ) ; parseClassMethod ( memberStart , false ) ; } else if ( ( token . contextualKeyword === ContextualKeyword . _get || token . contextualKeyword === ContextualKeyword . _set ) && ! ( isLineTerminator ( ) && match ( tt . star ) ) ) { if ( token . contextualKeyword === ContextualKeyword . _get ) { state . tokens [ state . tokens . length - 1 ] . type = tt . _get ; } else { state . tokens [ state . tokens . length - 1 ] . type = tt . _set ; } parseClassPropertyName ( ) ; parseClassMethod ( memberStart , false ) ; } else if ( isLineTerminator ( ) ) { parseClassProperty ( ) ; } else { unexpected ( ) ; } } function parseClassMethod ( functionStart , isConstructor ) { if ( true ) { tsTryParseTypeParameters ( ) ; } parseMethod ( functionStart , isConstructor ) ; } export function parseClassPropertyName ( ) { parsePropertyName ( ) ; } export function parsePostMemberNameModifiers ( ) { if ( true ) { const oldIsType = pushTypeContext ( 0 ) ; eat ( tt . question ) ; popTypeContext ( oldIsType ) ; } } export function parseClassProperty ( ) { if ( true ) { eat ( tt . bang ) ; tsTryParseTypeAnnotation ( ) ; } if ( match ( tt . eq ) ) { const equalsTokenIndex = state . tokens . length ; next ( ) ; parseMaybeAssign ( ) ; state . tokens [ equalsTokenIndex ] . rhsEndIndex = state . tokens . length ; } semicolon ( ) ; } function parseClassId ( isStatement , optionalId = false ) { if ( ( ! isStatement || optionalId ) && isContextual ( ContextualKeyword . _implements ) ) { return ; } if ( match ( tt . name ) ) { parseBindingIdentifier ( true ) ; } if ( true ) { tsTryParseTypeParameters ( ) ; } } function parseClassSuper ( ) { let hasSuper = false ; if ( eat ( tt . _extends ) ) { parseExprSubscripts ( ) ; hasSuper = true ; } else { hasSuper = false ; } if ( true ) { tsAfterParseClassSuper ( hasSuper ) ; } } export function parseExport ( ) { const exportIndex = state . tokens . length - 1 ; if ( true ) { if ( tsTryParseExport ( ) ) { return ; } } if ( shouldParseExportStar ( ) ) { parseExportStar ( ) ; } else if ( isExportDefaultSpecifier ( ) ) { parseIdentifier ( ) ; if ( match ( tt . comma ) && lookaheadType ( ) === tt . star ) { expect ( tt . comma ) ; expect ( tt . star ) ; expectContextual ( ContextualKeyword . _as ) ; parseIdentifier ( ) ; } else { parseExportSpecifiersMaybe ( ) ; } parseExportFrom ( ) ; } else if ( eat ( tt . _default ) ) { parseExportDefaultExpression ( ) ; } else if ( shouldParseExportDeclaration ( ) ) { parseExportDeclaration ( ) ; } else { parseExportSpecifiers ( ) ; parseExportFrom ( ) ; } state . tokens [ exportIndex ] . rhsEndIndex = state . tokens . length ; } function parseExportDefaultExpression ( ) { if ( true ) { if ( tsTryParseExportDefaultExpression ( ) ) { return ; } } const functionStart = state . start ; if ( eat ( tt . _function ) ) { parseFunction ( functionStart , true , true ) ; } else if ( isContextual ( ContextualKeyword . _async ) && lookaheadType ( ) === tt . _function ) { eatContextual ( ContextualKeyword . _async ) ; eat ( tt . _function ) ; parseFunction ( functionStart , true , true ) ; } else if ( match ( tt . _class ) ) { parseClass ( true , true ) ; } else if ( match ( tt . at ) ) { parseDecorators ( ) ; parseClass ( true , true ) ; } else { parseMaybeAssign ( ) ; semicolon ( ) ; } } function parseExportDeclaration ( ) { if ( true ) { tsParseExportDeclaration ( ) ; } } function isExportDefaultSpecifier ( ) { if ( true && tsIsDeclarationStart ( ) ) { return false ; } if ( match ( tt . name ) ) { return state . contextualKeyword !== ContextualKeyword . _async ; } if ( ! match ( tt . _default ) ) { return false ; } const _next = nextTokenStart ( ) ; const lookahead = lookaheadTypeAndKeyword ( ) ; const hasFrom = lookahead . type === tt . name && lookahead . contextualKeyword === ContextualKeyword . _from ; if ( lookahead . type === tt . comma ) { return true ; } if ( hasFrom ) { const nextAfterFrom = input . charCodeAt ( nextTokenStartSince ( _next + 4 ) ) ; return nextAfterFrom === charCodes . quotationMark || nextAfterFrom === charCodes . apostrophe ; } return false ; } function parseExportSpecifiersMaybe ( ) { if ( eat ( tt . comma ) ) { parseExportSpecifiers ( ) ; } } export function parseExportFrom ( ) { if ( eatContextual ( ContextualKeyword . _from ) ) { parseExprAtom ( ) ; } semicolon ( ) ; } function shouldParseExportStar ( ) { if ( false ) { } else { return match ( tt . star ) ; } } function parseExportStar ( ) { if ( false ) { } else { baseParseExportStar ( ) ; } } export function baseParseExportStar ( ) { expect ( tt . star ) ; if ( isContextual ( ContextualKeyword . _as ) ) { parseExportNamespace ( ) ; } else { parseExportFrom ( ) ; } } function parseExportNamespace ( ) { next ( ) ; state . tokens [ state . tokens . length - 1 ] . type = tt . _as ; parseIdentifier ( ) ; parseExportSpecifiersMaybe ( ) ; parseExportFrom ( ) ; } function shouldParseExportDeclaration ( ) { return ( ( true && tsIsDeclarationStart ( ) ) || state . type === tt . _var || state . type === tt . _const || state . type === tt . _let || state . type === tt . _function || state . type === tt . _class || isContextual ( ContextualKeyword . _async ) || match ( tt . at ) ) ; } export function parseExportSpecifiers ( ) { let first = true ; expect ( tt . braceL ) ; while ( ! eat ( tt . braceR ) && ! state . error ) { if ( first ) { first = false ; } else { expect ( tt . comma ) ; if ( eat ( tt . braceR ) ) { break ; } } parseIdentifier ( ) ; if ( eatContextual ( ContextualKeyword . _as ) ) { parseIdentifier ( ) ; } } } export function parseImport ( ) { if ( true && match ( tt . name ) && lookaheadType ( ) === tt . eq ) { tsParseImportEqualsDeclaration ( ) ; return ; } if ( true ) { eatContextual ( ContextualKeyword . _type ) ; } if ( match ( tt . string ) ) { parseExprAtom ( ) ; } else { parseImportSpecifiers ( ) ; expectContextual ( ContextualKeyword . _from ) ; parseExprAtom ( ) ; } semicolon ( ) ; } function shouldParseDefaultImport ( ) { return match ( tt . name ) ; } function parseImportSpecifierLocal ( ) { parseImportedIdentifier ( ) ; } function parseImportSpecifiers ( ) { let first = true ; if ( shouldParseDefaultImport ( ) ) { parseImportSpecifierLocal ( ) ; if ( ! eat ( tt . comma ) ) return ; } if ( match ( tt . star ) ) { next ( ) ; expectContextual ( ContextualKeyword . _as ) ; parseImportSpecifierLocal ( ) ; return ; } expect ( tt . braceL ) ; while ( ! eat ( tt . braceR ) && ! state . error ) { if ( first ) { first = false ; } else { if ( eat ( tt . colon ) ) { unexpected ( "ES2015 named imports do not destructure. Use another statement for destructuring after the import." ) ; } expect ( tt . comma ) ; if ( eat ( tt . braceR ) ) { break ; } } parseImportSpecifier ( ) ; } } function parseImportSpecifier ( ) { parseImportedIdentifier ( ) ; if ( isContextual ( ContextualKeyword . _as ) ) { next ( ) ; parseImportedIdentifier ( ) ; } }