export function maybeDisambiguateParenthesis()

in src/powerquery-parser/parser/disambiguation/disambiguationUtils.ts [180:248]


export function maybeDisambiguateParenthesis(state: ParseState, parser: Parser): ParenthesisDisambiguation | undefined {
    const trace: Trace = state.traceManager.entry(
        DisambiguationTraceConstant.Disambiguation,
        maybeDisambiguateParenthesis.name,
    );

    const initialTokenIndex: number = state.tokenIndex;
    const tokens: ReadonlyArray<Token.Token> = state.lexerSnapshot.tokens;
    const totalTokens: number = tokens.length;
    let nestedDepth: number = 1;
    let offsetTokenIndex: number = initialTokenIndex + 1;

    while (offsetTokenIndex < totalTokens) {
        const offsetTokenKind: Token.TokenKind = tokens[offsetTokenIndex].kind;

        if (offsetTokenKind === Token.TokenKind.LeftParenthesis) {
            nestedDepth += 1;
        } else if (offsetTokenKind === Token.TokenKind.RightParenthesis) {
            nestedDepth -= 1;
        }

        let maybeDisambiguation: ParenthesisDisambiguation | undefined = undefined;

        if (nestedDepth === 0) {
            // '(x as number) as number' could either be either case,
            // so we need to consume test if the trailing 'as number' is followed by a FatArrow.
            if (ParseStateUtils.isTokenKind(state, Token.TokenKind.KeywordAs, offsetTokenIndex + 1)) {
                const checkpoint: ParseStateCheckpoint = parser.createCheckpoint(state);
                unsafeMoveTo(state, offsetTokenIndex + 2);

                try {
                    parser.readNullablePrimitiveType(state, parser);
                } catch {
                    parser.restoreCheckpoint(state, checkpoint);

                    if (ParseStateUtils.isOnTokenKind(state, Token.TokenKind.FatArrow)) {
                        return ParenthesisDisambiguation.FunctionExpression;
                    } else {
                        return ParenthesisDisambiguation.ParenthesizedExpression;
                    }
                }

                if (ParseStateUtils.isOnTokenKind(state, Token.TokenKind.FatArrow)) {
                    maybeDisambiguation = ParenthesisDisambiguation.FunctionExpression;
                } else {
                    maybeDisambiguation = ParenthesisDisambiguation.ParenthesizedExpression;
                }

                parser.restoreCheckpoint(state, checkpoint);
            } else if (ParseStateUtils.isTokenKind(state, Token.TokenKind.FatArrow, offsetTokenIndex + 1)) {
                maybeDisambiguation = ParenthesisDisambiguation.FunctionExpression;
            } else {
                maybeDisambiguation = ParenthesisDisambiguation.ParenthesizedExpression;
            }
        }

        if (maybeDisambiguation) {
            trace.exit({ [TraceConstant.Result]: maybeDisambiguation });

            return maybeDisambiguation;
        }

        offsetTokenIndex += 1;
    }

    trace.exit({ [TraceConstant.Result]: undefined });

    return undefined;
}