/**
 * Numeric Proof Walk — Statement processing, module processing, and proof pass entry
 *
 * This module handles:
 * - Processing all statements, tracking proven variables
 * - Running the proof pass on modules and aggregating diagnostics
 *
 * CRITICAL: If this pass emits ANY errors, the emitter MUST NOT run.
 */
import { cloneProofContext, withInt32ProofsFromTruthyCondition, getNumericKindFromType, inferNumericKind, } from "./numeric-proof-analysis.js";
import { processExpression } from "./numeric-proof-expression-walk.js";
/**
 * Process a statement, proving numeric narrowings in expressions.
 */
const processStatement = (stmt, ctx) => {
    const processExpr = (expr, c) => processExpression(expr, c, processStatement);
    const processParameters = (parameters) => {
        const paramCtx = {
            ...ctx,
            provenParameters: new Map(ctx.provenParameters),
            provenVariables: new Map(ctx.provenVariables),
        };
        const processedParameters = parameters.map((param) => {
            const processedParam = {
                ...param,
                initializer: param.initializer
                    ? processExpr(param.initializer, paramCtx)
                    : undefined,
            };
            if (param.pattern.kind === "identifierPattern") {
                const numericKind = getNumericKindFromType(param.type);
                if (numericKind !== undefined) {
                    paramCtx.provenParameters.set(param.pattern.name, numericKind);
                }
            }
            return processedParam;
        });
        return [processedParameters, paramCtx];
    };
    switch (stmt.kind) {
        case "variableDeclaration": {
            const processedDeclarations = stmt.declarations.map((d) => {
                const processedInit = d.initializer
                    ? processExpr(d.initializer, ctx)
                    : undefined;
                // Track proven variables from declarations with known numeric kind
                // This includes:
                // 0. Explicit type annotations (authoritative)
                // 1. numericNarrowing with proof (explicit `as int`)
                // 2. Binary/unary expressions that produce known numeric kinds
                // 3. Identifiers with known numeric types
                // We track both const and let (let can be reassigned, but at init we know the type)
                if (d.name.kind === "identifierPattern") {
                    // If a variable has an explicit numeric type annotation, that type is authoritative.
                    // We must not "re-prove" it from the initializer, or we'll incorrectly treat
                    // `let x: long = 1;` as Int32 (because `1` is an Int32 literal by lexeme).
                    const declaredKind = getNumericKindFromType(d.type);
                    if (declaredKind !== undefined) {
                        ctx.provenVariables.set(d.name.name, declaredKind);
                    }
                    else if (d.type === undefined && processedInit !== undefined) {
                        // First check for explicit numericNarrowing
                        if (processedInit.kind === "numericNarrowing" &&
                            processedInit.proof !== undefined) {
                            ctx.provenVariables.set(d.name.name, processedInit.proof.kind);
                        }
                        else {
                            // Otherwise, try to infer the numeric kind from the expression
                            const inferredKind = inferNumericKind(processedInit, ctx);
                            if (inferredKind !== undefined) {
                                ctx.provenVariables.set(d.name.name, inferredKind);
                            }
                        }
                    }
                }
                return {
                    ...d,
                    initializer: processedInit,
                };
            });
            return { ...stmt, declarations: processedDeclarations };
        }
        case "functionDeclaration": {
            const [parameters, paramCtx] = processParameters(stmt.parameters);
            return {
                ...stmt,
                parameters,
                body: processStatement(stmt.body, paramCtx),
            };
        }
        case "classDeclaration": {
            const processedMembers = stmt.members.map((m) => {
                if (m.kind === "methodDeclaration" && m.body) {
                    const [parameters, methodCtx] = processParameters(m.parameters);
                    return {
                        ...m,
                        parameters,
                        body: processStatement(m.body, methodCtx),
                    };
                }
                if (m.kind === "propertyDeclaration") {
                    const setterCtx = {
                        ...ctx,
                        provenParameters: new Map(ctx.provenParameters),
                        provenVariables: new Map(ctx.provenVariables),
                    };
                    if (m.setterParamName) {
                        const setterKind = getNumericKindFromType(m.type);
                        if (setterKind !== undefined) {
                            setterCtx.provenParameters.set(m.setterParamName, setterKind);
                        }
                    }
                    return {
                        ...m,
                        initializer: m.initializer
                            ? processExpr(m.initializer, ctx)
                            : undefined,
                        getterBody: m.getterBody
                            ? processStatement(m.getterBody, ctx)
                            : undefined,
                        setterBody: m.setterBody
                            ? processStatement(m.setterBody, setterCtx)
                            : undefined,
                    };
                }
                if (m.kind === "constructorDeclaration" && m.body) {
                    const [parameters, ctorCtx] = processParameters(m.parameters);
                    return {
                        ...m,
                        parameters,
                        body: processStatement(m.body, ctorCtx),
                    };
                }
                return m;
            });
            return { ...stmt, members: processedMembers };
        }
        case "expressionStatement":
            return {
                ...stmt,
                expression: processExpr(stmt.expression, ctx),
            };
        case "returnStatement":
            return {
                ...stmt,
                expression: stmt.expression
                    ? processExpr(stmt.expression, ctx)
                    : undefined,
            };
        case "ifStatement": {
            const processedCondition = processExpr(stmt.condition, ctx);
            const thenCtx = withInt32ProofsFromTruthyCondition(cloneProofContext(ctx), processedCondition);
            return {
                ...stmt,
                condition: processedCondition,
                thenStatement: processStatement(stmt.thenStatement, thenCtx),
                elseStatement: stmt.elseStatement
                    ? processStatement(stmt.elseStatement, ctx)
                    : undefined,
            };
        }
        case "whileStatement":
            return {
                ...stmt,
                condition: processExpr(stmt.condition, ctx),
                body: processStatement(stmt.body, ctx),
            };
        case "forStatement":
            return {
                ...stmt,
                initializer: stmt.initializer
                    ? stmt.initializer.kind === "variableDeclaration"
                        ? processStatement(stmt.initializer, ctx)
                        : processExpr(stmt.initializer, ctx)
                    : undefined,
                condition: stmt.condition
                    ? processExpr(stmt.condition, ctx)
                    : undefined,
                update: stmt.update ? processExpr(stmt.update, ctx) : undefined,
                body: processStatement(stmt.body, ctx),
            };
        case "forOfStatement":
            return {
                ...stmt,
                expression: processExpr(stmt.expression, ctx),
                body: processStatement(stmt.body, ctx),
            };
        case "forInStatement":
            return {
                ...stmt,
                expression: processExpr(stmt.expression, ctx),
                body: processStatement(stmt.body, ctx),
            };
        case "switchStatement":
            return {
                ...stmt,
                expression: processExpr(stmt.expression, ctx),
                cases: stmt.cases.map((c) => ({
                    ...c,
                    test: c.test ? processExpr(c.test, ctx) : undefined,
                    statements: c.statements.map((s) => processStatement(s, ctx)),
                })),
            };
        case "throwStatement":
            return {
                ...stmt,
                expression: processExpr(stmt.expression, ctx),
            };
        case "tryStatement":
            return {
                ...stmt,
                tryBlock: processStatement(stmt.tryBlock, ctx),
                catchClause: stmt.catchClause
                    ? {
                        ...stmt.catchClause,
                        body: processStatement(stmt.catchClause.body, ctx),
                    }
                    : undefined,
                finallyBlock: stmt.finallyBlock
                    ? processStatement(stmt.finallyBlock, ctx)
                    : undefined,
            };
        case "blockStatement":
            return {
                ...stmt,
                statements: stmt.statements.map((s) => processStatement(s, ctx)),
            };
        case "yieldStatement":
            return {
                ...stmt,
                output: stmt.output ? processExpr(stmt.output, ctx) : undefined,
            };
        case "generatorReturnStatement":
            return {
                ...stmt,
                expression: stmt.expression
                    ? processExpr(stmt.expression, ctx)
                    : undefined,
            };
        default:
            return stmt;
    }
};
/**
 * Run numeric proof pass on a module.
 */
const processModule = (module) => {
    const ctx = {
        filePath: module.filePath,
        diagnostics: [],
        provenVariables: new Map(),
        provenParameters: new Map(),
    };
    const processExpr = (expr, c) => processExpression(expr, c, processStatement);
    const processedBody = module.body.map((stmt) => processStatement(stmt, ctx));
    const processedExports = module.exports.map((exp) => {
        if (exp.kind === "default") {
            return { ...exp, expression: processExpr(exp.expression, ctx) };
        }
        if (exp.kind === "declaration") {
            return { ...exp, declaration: processStatement(exp.declaration, ctx) };
        }
        return exp;
    });
    return {
        ok: ctx.diagnostics.length === 0,
        module: {
            ...module,
            body: processedBody,
            exports: processedExports,
        },
        diagnostics: ctx.diagnostics,
    };
};
/**
 * Run numeric proof validation on all modules.
 *
 * HARD GATE: If any diagnostics are returned, the emitter MUST NOT run.
 * This is not a warning system - unprovable narrowings are compilation errors.
 */
export const runNumericProofPass = (modules) => {
    const processedModules = [];
    const allDiagnostics = [];
    for (const module of modules) {
        const result = processModule(module);
        processedModules.push(result.module);
        allDiagnostics.push(...result.diagnostics);
    }
    return {
        ok: allDiagnostics.length === 0,
        modules: processedModules,
        diagnostics: allDiagnostics,
    };
};
//# sourceMappingURL=numeric-proof-statement-walk.js.map