export function nn(node, context) {
    if (node === null) {
        throw new Error(`Unexpected null tree-sitter node${context ? ` (${context})` : ''}`);
    }
    return node;
}
export function isIfNode(type, cfgRules) {
    return type === cfgRules.ifNode || cfgRules.ifNodes?.has(type);
}
export function isForNode(type, cfgRules) {
    return cfgRules.forNodes.has(type);
}
export function isWhileNode(type, cfgRules) {
    return type === cfgRules.whileNode || cfgRules.whileNodes?.has(type);
}
export function isSwitchNode(type, cfgRules) {
    return type === cfgRules.switchNode || cfgRules.switchNodes?.has(type);
}
export function isCaseNode(type, cfgRules) {
    return (type === cfgRules.caseNode || type === cfgRules.defaultNode || cfgRules.caseNodes?.has(type));
}
export function isBlockNode(type, cfgRules) {
    return type === 'statement_list' || type === cfgRules.blockNode || cfgRules.blockNodes?.has(type);
}
export function isControlFlow(type, cfgRules) {
    return (isIfNode(type, cfgRules) ||
        (cfgRules.unlessNode && type === cfgRules.unlessNode) ||
        isForNode(type, cfgRules) ||
        isWhileNode(type, cfgRules) ||
        (cfgRules.untilNode && type === cfgRules.untilNode) ||
        (cfgRules.doNode && type === cfgRules.doNode) ||
        (cfgRules.infiniteLoopNode && type === cfgRules.infiniteLoopNode) ||
        isSwitchNode(type, cfgRules) ||
        (cfgRules.tryNode && type === cfgRules.tryNode) ||
        type === cfgRules.returnNode ||
        type === cfgRules.throwNode ||
        type === cfgRules.breakNode ||
        type === cfgRules.continueNode ||
        type === cfgRules.labeledNode);
}
export function effectiveNode(node, cfgRules) {
    if (node.type === 'expression_statement' && node.namedChildCount === 1) {
        const inner = nn(node.namedChild(0));
        if (isControlFlow(inner.type, cfgRules))
            return inner;
    }
    return node;
}
export function registerLabelCtx(S, headerBlock, exitBlock) {
    for (const [, ctx] of Array.from(S.labelMap)) {
        if (!ctx.headerBlock) {
            ctx.headerBlock = headerBlock;
            ctx.exitBlock = exitBlock;
        }
    }
}
export function getBodyStatements(bodyNode, cfgRules) {
    if (!bodyNode)
        return [];
    if (isBlockNode(bodyNode.type, cfgRules)) {
        const stmts = [];
        for (let i = 0; i < bodyNode.namedChildCount; i++) {
            const child = nn(bodyNode.namedChild(i));
            if (child.type === 'statement_list') {
                for (let j = 0; j < child.namedChildCount; j++) {
                    stmts.push(nn(child.namedChild(j)));
                }
            }
            else {
                stmts.push(child);
            }
        }
        return stmts;
    }
    return [bodyNode];
}
export function makeFuncState() {
    const blocks = [];
    const edges = [];
    let nextIndex = 0;
    function makeBlock(type, startLine = null, endLine = null, label = null) {
        const block = { index: nextIndex++, type, startLine, endLine, label };
        blocks.push(block);
        return block;
    }
    function addEdge(source, target, kind) {
        edges.push({ sourceIndex: source.index, targetIndex: target.index, kind });
    }
    const entry = makeBlock('entry');
    const exit = makeBlock('exit');
    const firstBody = makeBlock('body');
    addEdge(entry, firstBody, 'fallthrough');
    return {
        blocks,
        edges,
        makeBlock,
        addEdge,
        entryBlock: entry,
        exitBlock: exit,
        currentBlock: firstBody,
        loopStack: [],
        labelMap: new Map(),
        cfgStack: [],
        funcNode: null,
    };
}
//# sourceMappingURL=cfg-shared.js.map