/**
 * Literal expression converters
 *
 * DETERMINISTIC TYPING: Literal types are derived from lexeme form, NOT TypeScript.
 *
 * Numeric literals:
 * - Integer literals (42, 0xFF) → Int32 → inferredType: int
 * - Floating literals (42.0, 3.14, 1e3) → Double → inferredType: double
 *
 * String literals → inferredType: string
 * Boolean literals → inferredType: boolean (handled elsewhere)
 */
import * as ts from "typescript";
import { getSourceSpan } from "./helpers.js";
import { inferNumericKindFromRaw } from "../../types/numeric-helpers.js";
import { resolveAmbientGlobalSourceOwnerByName } from "./ambient-global-source-owner.js";
import { buildSourceBackedConstructorParameterTypes } from "./calls/source-backed-constructor-metadata.js";
/**
 * Derive inferredType from numericIntent (deterministic, no TypeScript).
 */
const deriveTypeFromNumericIntent = (numericIntent) => {
    if (numericIntent === "Int32") {
        return { kind: "referenceType", name: "int" };
    }
    else if (numericIntent === "Double") {
        return { kind: "primitiveType", name: "number" };
    }
    else if (numericIntent === "Int64") {
        return { kind: "referenceType", name: "long" };
    }
    else if (numericIntent === "Single") {
        return { kind: "referenceType", name: "float" };
    }
    else if (numericIntent === "Byte") {
        return { kind: "referenceType", name: "byte" };
    }
    else if (numericIntent === "Int16") {
        return { kind: "referenceType", name: "short" };
    }
    else if (numericIntent === "UInt32") {
        return { kind: "referenceType", name: "uint" };
    }
    else if (numericIntent === "UInt64") {
        return { kind: "referenceType", name: "ulong" };
    }
    else if (numericIntent === "UInt16") {
        return { kind: "referenceType", name: "ushort" };
    }
    else if (numericIntent === "SByte") {
        return { kind: "referenceType", name: "sbyte" };
    }
    // Default to double for unknown
    return { kind: "primitiveType", name: "number" };
};
/**
 * Convert string or numeric literal
 *
 * DETERMINISTIC TYPING: inferredType is derived from the literal value itself,
 * NOT from TypeScript's type checker. This ensures consistent typing regardless
 * of contextual type.
 */
export const convertLiteral = (node, _ctx) => {
    const raw = node.getText();
    const value = ts.isStringLiteral(node) ? node.text : Number(node.text);
    // For numeric literals, derive type from lexeme form
    const numericIntent = typeof value === "number" ? inferNumericKindFromRaw(raw) : undefined;
    // Derive inferredType deterministically (no TypeScript)
    // - String literals → string
    // - Numeric literals with numericIntent → derived from intent
    // - Unknown → undefined (let caller handle)
    const inferredType = typeof value === "string"
        ? { kind: "primitiveType", name: "string" }
        : numericIntent
            ? deriveTypeFromNumericIntent(numericIntent)
            : undefined;
    return {
        kind: "literal",
        value,
        raw,
        inferredType,
        sourceSpan: getSourceSpan(node),
        numericIntent,
    };
};
const splitRegularExpressionLiteral = (raw) => {
    let closingSlash = -1;
    for (let index = raw.length - 1; index > 0; index--) {
        if (raw[index] !== "/")
            continue;
        let backslashCount = 0;
        for (let j = index - 1; j > 0 && raw[j] === "\\"; j--) {
            backslashCount++;
        }
        if (backslashCount % 2 === 0) {
            closingSlash = index;
            break;
        }
    }
    if (closingSlash <= 0) {
        return { pattern: raw, flags: "" };
    }
    return {
        pattern: raw.slice(1, closingSlash),
        flags: raw.slice(closingSlash + 1),
    };
};
export const convertRegularExpressionLiteral = (node, ctx) => {
    const raw = node.getText();
    const { pattern, flags } = splitRegularExpressionLiteral(raw);
    const regExpBinding = ctx.bindings.getBinding("RegExp");
    const resolvedClrType = regExpBinding && regExpBinding.kind === "global"
        ? regExpBinding.type
        : (resolveAmbientGlobalSourceOwnerByName("RegExp", node, ctx, ts.SymbolFlags.Value) ?? undefined);
    const resolvedAssembly = regExpBinding && regExpBinding.kind === "global"
        ? regExpBinding.assembly
        : undefined;
    const args = [
        {
            kind: "literal",
            value: pattern,
            raw: JSON.stringify(pattern),
            inferredType: { kind: "primitiveType", name: "string" },
            sourceSpan: getSourceSpan(node),
        },
    ];
    if (flags !== "") {
        args.push({
            kind: "literal",
            value: flags,
            raw: JSON.stringify(flags),
            inferredType: { kind: "primitiveType", name: "string" },
            sourceSpan: getSourceSpan(node),
        });
    }
    const inferredType = {
        kind: "referenceType",
        name: "RegExp",
        resolvedClrType,
    };
    const sourceBackedConstructorParameterTypes = buildSourceBackedConstructorParameterTypes({
        sourceNode: node,
        callee: {
            kind: "identifier",
            name: "RegExp",
            inferredType,
            resolvedClrType,
            resolvedAssembly,
            sourceSpan: getSourceSpan(node),
        },
        constructedType: inferredType,
        argumentCount: args.length,
        actualArgTypes: args.map((arg) => arg.inferredType),
        ctx,
    });
    return {
        kind: "new",
        callee: {
            kind: "identifier",
            name: "RegExp",
            inferredType: {
                kind: "referenceType",
                name: "RegExp",
                resolvedClrType,
            },
            resolvedClrType,
            resolvedAssembly,
            sourceSpan: getSourceSpan(node),
        },
        arguments: args,
        inferredType,
        parameterTypes: sourceBackedConstructorParameterTypes?.parameterTypes,
        surfaceParameterTypes: sourceBackedConstructorParameterTypes?.surfaceParameterTypes,
        sourceBackedParameterTypes: sourceBackedConstructorParameterTypes?.parameterTypes,
        sourceBackedSurfaceParameterTypes: sourceBackedConstructorParameterTypes?.surfaceParameterTypes,
        sourceBackedRestParameter: sourceBackedConstructorParameterTypes?.restParameter,
        sourceBackedReturnType: inferredType,
        surfaceRestParameter: sourceBackedConstructorParameterTypes?.restParameter,
        sourceSpan: getSourceSpan(node),
    };
};
//# sourceMappingURL=literals.js.map