import { typedParseConditional , typedParseParenItem } from "../plugins/types" ; import { tsParseArrow , tsParseFunctionBodyAndFinish , tsParseMaybeAssign , tsParseSubscript , tsParseType , tsParseTypeAssertion , tsStartParseAsyncArrowFromCallExpression , tsStartParseNewArguments , tsStartParseObjPropValue , } from "../plugins/typescript" ; import { eat , lookaheadCharCode , lookaheadType , match , next , nextTemplateToken , popTypeContext , pushTypeContext , retokenizeSlashAsRegex , } from "../tokenizer/index" ; import { ContextualKeyword } from "../tokenizer/keywords" ; import { TokenType , TokenType as tt } from "../tokenizer/types" ; import { charCodes } from "../util/charcodes" ; import { IS_IDENTIFIER_START } from "../util/identifier" ; import { state } from "./base" ; import { markPriorBindingIdentifier , parseBindingIdentifier , parseMaybeDefault , parseRest , parseSpread , } from "./lval" ; import { parseBlock , parseClass , parseDecorators , parseFunction , parseFunctionParams , } from "./statement" ; import { canInsertSemicolon , eatContextual , expect , hasPrecedingLineBreak , isContextual , unexpected , } from "./util" ; export class StopState { stop : boolean ; constructor ( stop ) { this . stop = stop ; } } export function parseExpression ( noIn = false ) { parseMaybeAssign ( noIn ) ; if ( match ( tt . comma ) ) { while ( eat ( tt . comma ) ) { parseMaybeAssign ( noIn ) ; } } } /**
 * noIn is used when parsing a for loop so that we don't interpret a following "in" as the binary
 * operatior.
 * isWithinParens is used to indicate that we're parsing something that might be a comma expression
 * or might be an arrow function or might be a Flow type assertion (which requires explicit parens).
 * In these cases, we should allow : and ?: after the initial "left" part.
 */ export function parseMaybeAssign ( noIn = false , isWithinParens = false ) { if ( true ) { return tsParseMaybeAssign ( noIn , isWithinParens ) ; } } export function baseParseMaybeAssign ( noIn , isWithinParens ) { if ( match ( tt . _yield ) ) { parseYield ( ) ; return false ; } if ( match ( tt . parenL ) || match ( tt . name ) || match ( tt . _yield ) ) { state . potentialArrowAt = state . start ; } const wasArrow = parseMaybeConditional ( noIn ) ; if ( isWithinParens ) { parseParenItem ( ) ; } if ( state . type & TokenType . IS_ASSIGN ) { next ( ) ; parseMaybeAssign ( noIn ) ; return false ; } return wasArrow ; } function parseMaybeConditional ( noIn ) { const wasArrow = parseExprOps ( noIn ) ; if ( wasArrow ) { return true ; } parseConditional ( noIn ) ; return false ; } function parseConditional ( noIn ) { if ( true ) { typedParseConditional ( noIn ) ; } } export function baseParseConditional ( noIn ) { if ( eat ( tt . question ) ) { parseMaybeAssign ( ) ; expect ( tt . colon ) ; parseMaybeAssign ( noIn ) ; } } function parseExprOps ( noIn ) { const startTokenIndex = state . tokens . length ; const wasArrow = parseMaybeUnary ( ) ; if ( wasArrow ) { return true ; } parseExprOp ( startTokenIndex , - 1 , noIn ) ; return false ; } function parseExprOp ( startTokenIndex , minPrec , noIn ) { if ( true && ( tt . _in & TokenType . PRECEDENCE_MASK ) > minPrec && ! hasPrecedingLineBreak ( ) && eatContextual ( ContextualKeyword . _as ) ) { state . tokens [ state . tokens . length - 1 ] . type = tt . _as ; const oldIsType = pushTypeContext ( 1 ) ; tsParseType ( ) ; popTypeContext ( oldIsType ) ; parseExprOp ( startTokenIndex , minPrec , noIn ) ; return ; } const prec = state . type & TokenType . PRECEDENCE_MASK ; if ( prec > 0 && ( ! noIn || ! match ( tt . _in ) ) ) { if ( prec > minPrec ) { const op = state . type ; next ( ) ; const rhsStartTokenIndex = state . tokens . length ; parseMaybeUnary ( ) ; parseExprOp ( rhsStartTokenIndex , op & TokenType . IS_RIGHT_ASSOCIATIVE ? prec - 1 : prec , noIn ) ; parseExprOp ( startTokenIndex , minPrec , noIn ) ; } } } export function parseMaybeUnary ( ) { if ( true && true && eat ( tt . lessThan ) ) { tsParseTypeAssertion ( ) ; return false ; } if ( state . type & TokenType . IS_PREFIX ) { next ( ) ; parseMaybeUnary ( ) ; return false ; } const wasArrow = parseExprSubscripts ( ) ; if ( wasArrow ) { return true ; } while ( state . type & TokenType . IS_POSTFIX && ! canInsertSemicolon ( ) ) { if ( state . type === tt . preIncDec ) { state . type = tt . postIncDec ; } next ( ) ; } return false ; } export function parseExprSubscripts ( ) { const startTokenIndex = state . tokens . length ; const wasArrow = parseExprAtom ( ) ; if ( wasArrow ) { return true ; } parseSubscripts ( startTokenIndex ) ; return false ; } function parseSubscripts ( startTokenIndex , noCalls = false ) { baseParseSubscripts ( startTokenIndex , noCalls ) ; } export function baseParseSubscripts ( startTokenIndex , noCalls = false ) { const stopState = new StopState ( false ) ; do { parseSubscript ( startTokenIndex , noCalls , stopState ) ; } while ( ! stopState . stop && ! state . error ) ; } function parseSubscript ( startTokenIndex , noCalls , stopState ) { if ( true ) { tsParseSubscript ( startTokenIndex , noCalls , stopState ) ; } } /** Set 'state.stop = true' to indicate that we should stop parsing subscripts. */ export function baseParseSubscript ( startTokenIndex , noCalls , stopState ) { if ( ! noCalls && eat ( tt . doubleColon ) ) { parseNoCallExpr ( ) ; stopState . stop = true ; parseSubscripts ( startTokenIndex , noCalls ) ; } else if ( match ( tt . questionDot ) ) { if ( noCalls && lookaheadType ( ) === tt . parenL ) { stopState . stop = true ; return ; } next ( ) ; state . tokens [ state . tokens . length - 1 ] . subscriptStartIndex = startTokenIndex ; if ( eat ( tt . bracketL ) ) { parseExpression ( ) ; expect ( tt . bracketR ) ; } else if ( eat ( tt . parenL ) ) { parseCallExpressionArguments ( ) ; } else { parseMaybePrivateName ( ) ; } } else if ( eat ( tt . dot ) ) { state . tokens [ state . tokens . length - 1 ] . subscriptStartIndex = startTokenIndex ; parseMaybePrivateName ( ) ; } else if ( eat ( tt . bracketL ) ) { state . tokens [ state . tokens . length - 1 ] . subscriptStartIndex = startTokenIndex ; parseExpression ( ) ; expect ( tt . bracketR ) ; } else if ( ! noCalls && match ( tt . parenL ) ) { if ( atPossibleAsync ( ) ) { const snapshot = state . snapshot ( ) ; const asyncStartTokenIndex = state . tokens . length ; next ( ) ; state . tokens [ state . tokens . length - 1 ] . subscriptStartIndex = startTokenIndex ; parseCallExpressionArguments ( ) ; if ( shouldParseAsyncArrow ( ) ) { state . restoreFromSnapshot ( snapshot ) ; stopState . stop = true ; parseFunctionParams ( ) ; parseAsyncArrowFromCallExpression ( asyncStartTokenIndex ) ; } } else { next ( ) ; state . tokens [ state . tokens . length - 1 ] . subscriptStartIndex = startTokenIndex ; parseCallExpressionArguments ( ) ; } } else if ( match ( tt . backQuote ) ) { parseTemplate ( ) ; } else { stopState . stop = true ; } } export function atPossibleAsync ( ) { return ( state . tokens [ state . tokens . length - 1 ] . contextualKeyword === ContextualKeyword . _async && ! canInsertSemicolon ( ) ) ; } export function parseCallExpressionArguments ( ) { let first = true ; while ( ! eat ( tt . parenR ) && ! state . error ) { if ( first ) { first = false ; } else { expect ( tt . comma ) ; if ( eat ( tt . parenR ) ) { break ; } } parseExprListItem ( false ) ; } } function shouldParseAsyncArrow ( ) { return match ( tt . colon ) || match ( tt . arrow ) ; } function parseAsyncArrowFromCallExpression ( startTokenIndex ) { if ( true ) { tsStartParseAsyncArrowFromCallExpression ( ) ; } expect ( tt . arrow ) ; parseArrowExpression ( startTokenIndex ) ; } function parseNoCallExpr ( ) { const startTokenIndex = state . tokens . length ; parseExprAtom ( ) ; parseSubscripts ( startTokenIndex , true ) ; } export function parseExprAtom ( ) { if ( eat ( tt . modulo ) ) { parseIdentifier ( ) ; return false ; } if ( match ( tt . jsxText ) ) { parseLiteral ( ) ; return false ; } const canBeArrow = state . potentialArrowAt === state . start ; switch ( state . type ) { case tt . slash : case tt . assign : retokenizeSlashAsRegex ( ) ; case tt . _super : case tt . _this : case tt . regexp : case tt . num : case tt . bigint : case tt . decimal : case tt . string : case tt . _null : case tt . _true : case tt . _false : next ( ) ; return false ; case tt . _import : next ( ) ; if ( match ( tt . dot ) ) { state . tokens [ state . tokens . length - 1 ] . type = tt . name ; next ( ) ; parseIdentifier ( ) ; } return false ; case tt . name : { const startTokenIndex = state . tokens . length ; const functionStart = state . start ; const contextualKeyword = state . contextualKeyword ; parseIdentifier ( ) ; if ( contextualKeyword === ContextualKeyword . _await ) { parseAwait ( ) ; return false ; } else if ( contextualKeyword === ContextualKeyword . _async && match ( tt . _function ) && ! canInsertSemicolon ( ) ) { next ( ) ; parseFunction ( functionStart , false ) ; return false ; } else if ( canBeArrow && ! canInsertSemicolon ( ) && contextualKeyword === ContextualKeyword . _async && match ( tt . name ) ) { parseBindingIdentifier ( false ) ; expect ( tt . arrow ) ; parseArrowExpression ( startTokenIndex ) ; return true ; } if ( canBeArrow && ! canInsertSemicolon ( ) && match ( tt . arrow ) ) { markPriorBindingIdentifier ( false ) ; expect ( tt . arrow ) ; parseArrowExpression ( startTokenIndex ) ; return true ; } return false ; } case tt . _do : { next ( ) ; parseBlock ( ) ; return false ; } case tt . parenL : { const wasArrow = parseParenAndDistinguishExpression ( canBeArrow ) ; return wasArrow ; } case tt . bracketL : next ( ) ; parseExprList ( tt . bracketR , true ) ; return false ; case tt . braceL : parseObj ( false , false ) ; return false ; case tt . _function : parseFunctionExpression ( ) ; return false ; case tt . at : parseDecorators ( ) ; case tt . _class : parseClass ( false ) ; return false ; case tt . _new : parseNew ( ) ; return false ; case tt . backQuote : parseTemplate ( ) ; return false ; case tt . doubleColon : { next ( ) ; parseNoCallExpr ( ) ; return false ; } case tt . hash : { const code = lookaheadCharCode ( ) ; if ( IS_IDENTIFIER_START [ code ] || code === charCodes . backslash ) { parseMaybePrivateName ( ) ; } else { next ( ) ; } return false ; } default : unexpected ( ) ; return false ; } } function parseMaybePrivateName ( ) { eat ( tt . hash ) ; parseIdentifier ( ) ; } function parseFunctionExpression ( ) { const functionStart = state . start ; parseIdentifier ( ) ; if ( eat ( tt . dot ) ) { parseIdentifier ( ) ; } parseFunction ( functionStart , false ) ; } export function parseLiteral ( ) { next ( ) ; } export function parseParenExpression ( ) { expect ( tt . parenL ) ; parseExpression ( ) ; expect ( tt . parenR ) ; } function parseParenAndDistinguishExpression ( canBeArrow ) { const snapshot = state . snapshot ( ) ; const startTokenIndex = state . tokens . length ; expect ( tt . parenL ) ; let first = true ; while ( ! match ( tt . parenR ) && ! state . error ) { if ( first ) { first = false ; } else { expect ( tt . comma ) ; if ( match ( tt . parenR ) ) { break ; } } if ( match ( tt . ellipsis ) ) { parseRest ( false ) ; parseParenItem ( ) ; break ; } else { parseMaybeAssign ( false , true ) ; } } expect ( tt . parenR ) ; if ( canBeArrow && shouldParseArrow ( ) ) { const wasArrow = parseArrow ( ) ; if ( wasArrow ) { state . restoreFromSnapshot ( snapshot ) ; parseFunctionParams ( ) ; parseArrow ( ) ; parseArrowExpression ( startTokenIndex ) ; return true ; } } return false ; } function shouldParseArrow ( ) { return match ( tt . colon ) || ! canInsertSemicolon ( ) ; } export function parseArrow ( ) { if ( true ) { return tsParseArrow ( ) ; } } function parseParenItem ( ) { if ( true ) { typedParseParenItem ( ) ; } } function parseNew ( ) { expect ( tt . _new ) ; if ( eat ( tt . dot ) ) { parseIdentifier ( ) ; return ; } parseNoCallExpr ( ) ; eat ( tt . questionDot ) ; parseNewArguments ( ) ; } function parseNewArguments ( ) { if ( true ) { tsStartParseNewArguments ( ) ; } if ( eat ( tt . parenL ) ) { parseExprList ( tt . parenR ) ; } } export function parseTemplate ( ) { nextTemplateToken ( ) ; nextTemplateToken ( ) ; while ( ! match ( tt . backQuote ) && ! state . error ) { expect ( tt . dollarBraceL ) ; parseExpression ( ) ; nextTemplateToken ( ) ; nextTemplateToken ( ) ; } next ( ) ; } export function parseObj ( isPattern , isBlockScope ) { let first = true ; next ( ) ; while ( ! eat ( tt . braceR ) && ! state . error ) { if ( first ) { first = false ; } else { expect ( tt . comma ) ; if ( eat ( tt . braceR ) ) { break ; } } let isGenerator = false ; if ( match ( tt . ellipsis ) ) { const previousIndex = state . tokens . length ; parseSpread ( ) ; if ( isPattern ) { if ( state . tokens . length === previousIndex + 2 ) { markPriorBindingIdentifier ( isBlockScope ) ; } if ( eat ( tt . braceR ) ) { break ; } } continue ; } if ( ! isPattern ) { isGenerator = eat ( tt . star ) ; } if ( ! isPattern && isContextual ( ContextualKeyword . _async ) ) { if ( isGenerator ) unexpected ( ) ; parseIdentifier ( ) ; if ( match ( tt . colon ) || match ( tt . parenL ) || match ( tt . braceR ) || match ( tt . eq ) || match ( tt . comma ) ) { } else { if ( match ( tt . star ) ) { next ( ) ; isGenerator = true ; } parsePropertyName ( ) ; } } else { parsePropertyName ( ) ; } parseObjPropValue ( isPattern , isBlockScope ) ; } } function isGetterOrSetterMethod ( isPattern ) { return ( ! isPattern && ( match ( tt . string ) || match ( tt . num ) || match ( tt . bracketL ) || match ( tt . name ) || ! ! ( state . type & TokenType . IS_KEYWORD ) ) ) ; } function parseObjectMethod ( isPattern ) { const functionStart = state . start ; if ( match ( tt . parenL ) ) { if ( isPattern ) unexpected ( ) ; parseMethod ( functionStart , false ) ; return true ; } if ( isGetterOrSetterMethod ( isPattern ) ) { parsePropertyName ( ) ; parseMethod ( functionStart , false ) ; return true ; } return false ; } function parseObjectProperty ( isPattern , isBlockScope ) { if ( eat ( tt . colon ) ) { if ( isPattern ) { parseMaybeDefault ( isBlockScope ) ; } else { parseMaybeAssign ( false ) ; } return ; } parseMaybeDefault ( isBlockScope , true ) ; } function parseObjPropValue ( isPattern , isBlockScope ) { if ( true ) { tsStartParseObjPropValue ( ) ; } const wasMethod = parseObjectMethod ( isPattern ) ; if ( ! wasMethod ) { parseObjectProperty ( isPattern , isBlockScope ) ; } } export function parsePropertyName ( ) { if ( eat ( tt . bracketL ) ) { parseMaybeAssign ( ) ; expect ( tt . bracketR ) ; } else { if ( match ( tt . num ) || match ( tt . string ) || match ( tt . bigint ) || match ( tt . decimal ) ) { parseExprAtom ( ) ; } else { parseMaybePrivateName ( ) ; } } } export function parseMethod ( functionStart , isConstructor ) { const startTokenIndex = state . tokens . length ; const allowModifiers = isConstructor ; parseFunctionParams ( allowModifiers ) ; parseFunctionBodyAndFinish ( functionStart ) ; const endTokenIndex = state . tokens . length ; } export function parseArrowExpression ( startTokenIndex ) { parseFunctionBody ( true ) ; } export function parseFunctionBodyAndFinish ( functionStart ) { if ( true ) { tsParseFunctionBodyAndFinish ( functionStart ) ; } } export function parseFunctionBody ( allowExpression ) { const isExpression = allowExpression && ! match ( tt . braceL ) ; if ( isExpression ) { parseMaybeAssign ( ) ; } else { parseBlock ( true ) ; } } function parseExprList ( close , allowEmpty = false ) { let first = true ; while ( ! eat ( close ) && ! state . error ) { if ( first ) { first = false ; } else { expect ( tt . comma ) ; if ( eat ( close ) ) break ; } parseExprListItem ( allowEmpty ) ; } } function parseExprListItem ( allowEmpty ) { if ( allowEmpty && match ( tt . comma ) ) { } else if ( match ( tt . ellipsis ) ) { parseSpread ( ) ; parseParenItem ( ) ; } else if ( match ( tt . question ) ) { next ( ) ; } else { parseMaybeAssign ( false , true ) ; } } export function parseIdentifier ( ) { next ( ) ; state . tokens [ state . tokens . length - 1 ] . type = tt . name ; } function parseAwait ( ) { parseMaybeUnary ( ) ; } function parseYield ( ) { next ( ) ; if ( ! match ( tt . semi ) && ! canInsertSemicolon ( ) ) { eat ( tt . star ) ; parseMaybeAssign ( ) ; } }