/** * Runtime Value System — The engine's canonical value representation. * * Every value that flows through the formula evaluator is a `RuntimeValue`. * This is a properly tagged discriminated union that all function * implementations operate on directly — no adapter layer. * * ## Design Principles * * 1. **No Date objects** — dates are represented as their Excel serial * number (a plain `number`). Date formatting is an output concern. * 2. **No monkey-patched arrays** — `ArrayValue` is a proper type with * explicit `height`, `width`, and optional origin metadata. * 3. **Reference is a first-class value** — `ReferenceValue` can flow * through the evaluator and be passed to functions. * 4. **Error codes are strict** — `ErrorValue` uses a typed code enum. * 5. **Lambda is a value** — `LambdaValue` is part of the value union. */ import type { BoundExpr } from "../compile/bound-ast.js"; import type { ErrorCode } from "../integration/workbook-snapshot.js"; export declare const enum RVKind { /** Empty cell / blank. Numeric value 0, string value "". */ Blank = 0, /** A number (includes dates as serial numbers). */ Number = 1, /** A string. */ String = 2, /** A boolean (TRUE / FALSE). */ Boolean = 3, /** An error value (#N/A, #VALUE!, etc.). */ Error = 4, /** A 2D array of scalar values. */ Array = 5, /** A cell or area reference (lazy — not yet resolved to values). */ Reference = 6, /** A lambda (closure). */ Lambda = 7 } export interface BlankValue { readonly kind: RVKind.Blank; } export interface NumberValue { readonly kind: RVKind.Number; readonly value: number; } export interface StringValue { readonly kind: RVKind.String; readonly value: string; } export interface BooleanValue { readonly kind: RVKind.Boolean; readonly value: boolean; } export interface ErrorValue { readonly kind: RVKind.Error; readonly code: ErrorCode; } /** * A 2D array of scalar values. * * `rows[r][c]` is a `ScalarValue`. Arrays are always rectangular. * Origin metadata (for implicit intersection) is carried inline. */ export interface ArrayValue { readonly kind: RVKind.Array; /** Rows of scalar values. rows[0] is the first row. */ readonly rows: readonly (readonly ScalarValue[])[]; /** Number of rows. */ readonly height: number; /** Number of columns. */ readonly width: number; /** Origin row in the worksheet (1-based). Used for implicit intersection. */ readonly originRow?: number; /** Origin column in the worksheet (1-based). Used for implicit intersection. */ readonly originCol?: number; /** * Per-cell mask marking cells whose source formula is SUBTOTAL or * AGGREGATE. When a range is passed to an outer SUBTOTAL/AGGREGATE * call, those cells must be skipped so their results are not * double-counted (Excel semantics — standard totals-row behavior). * * Same shape as `rows`: `subtotalMask[r][c]` is true when the cell * should be excluded from outer SUBTOTAL/AGGREGATE aggregation. * Omitted when no cell in the array is a SUBTOTAL/AGGREGATE output. */ readonly subtotalMask?: readonly (readonly boolean[])[]; /** * Per-row mask marking rows whose source worksheet row is hidden. * Used by SUBTOTAL's 1xx-variant codes (101-111) and by AGGREGATE * options 5/7 to skip hidden rows. `hiddenRowMask[r]` is true when * row `r` of the array should be excluded under those semantics. * Omitted when no row in the array is hidden. */ readonly hiddenRowMask?: readonly boolean[]; } /** * The shape of a reference. */ export type RefArea = { readonly sheet: string; readonly top: number; readonly left: number; readonly bottom: number; readonly right: number; }; /** * A reference value that represents one or more areas in the workbook. * * References are first-class values in the new engine — they can be * passed to functions, returned from functions, and stored in variables. * They are resolved to actual values lazily when needed. */ export interface ReferenceValue { readonly kind: RVKind.Reference; /** The areas this reference covers. Usually one, but UNION produces multiple. */ readonly areas: readonly RefArea[]; /** Whether this reference originated from a single-cell ref (A1) vs an area ref (A1:A1). */ readonly singleCell?: boolean; } /** * A lambda closure value. */ export interface LambdaValue { readonly kind: RVKind.Lambda; /** Parameter names (uppercase). */ readonly params: readonly string[]; /** The body expression to evaluate when called. */ readonly body: BoundExpr; /** Captured variable bindings from the enclosing scope. */ readonly closureBindings?: ReadonlyMap; } /** * A scalar value (non-array, non-reference, non-lambda). */ export type ScalarValue = BlankValue | NumberValue | StringValue | BooleanValue | ErrorValue; /** * Any value that can flow through the evaluator. */ export type RuntimeValue = BlankValue | NumberValue | StringValue | BooleanValue | ErrorValue | ArrayValue | ReferenceValue | LambdaValue; /** The singleton blank value. */ export declare const BLANK: BlankValue; /** Common error values. */ export declare const ERRORS: { readonly VALUE: ErrorValue; readonly REF: ErrorValue; readonly NAME: ErrorValue; readonly DIV0: ErrorValue; readonly NA: ErrorValue; readonly NUM: ErrorValue; readonly NULL: ErrorValue; readonly SPILL: ErrorValue; readonly CALC: ErrorValue; }; export declare function rvNumber(value: number): NumberValue; export declare function rvString(value: string): StringValue; export declare function rvBoolean(value: boolean): BooleanValue; export declare function rvError(code: ErrorCode): ErrorValue; export declare function rvArray(rows: ScalarValue[][], originRow?: number, originCol?: number, subtotalMask?: readonly (readonly boolean[])[], hiddenRowMask?: readonly boolean[]): ArrayValue; /** * Fast-path rectangular ArrayValue constructor. * * Callers that have already produced strictly-rectangular `rows` (every * row is the same length — the length they explicitly `new Array(width)` * allocated) can skip the two-pass width-scan + padding loop in * `rvArray`. Examples: `buildRangeArray`, `broadcastBinaryOp`, * `evaluateArrayLiteral`, `TRANSPOSE` — they all know `width` up front. * * Rows MUST be rectangular; passing ragged data will silently surface as * `undefined` cells downstream. */ export declare function rvArrayRect(rows: ScalarValue[][], height: number, width: number, originRow?: number, originCol?: number, subtotalMask?: readonly (readonly boolean[])[], hiddenRowMask?: readonly boolean[]): ArrayValue; export declare function rvRef(sheet: string, top: number, left: number, bottom: number, right: number): ReferenceValue; export declare function rvCellRef(sheet: string, row: number, col: number): ReferenceValue; export declare function rvLambda(params: string[], body: BoundExpr, closureBindings?: ReadonlyMap): LambdaValue; export declare function isError(v: RuntimeValue): v is ErrorValue; export declare function isArray(v: RuntimeValue): v is ArrayValue; export declare function isLambda(v: RuntimeValue): v is LambdaValue; export declare function isScalar(v: RuntimeValue): v is ScalarValue; /** * Coerce a runtime value to a number. * - Blank → 0 * - Number → itself * - Boolean → 1 / 0 * - String → parse or #VALUE! * - Error → propagate */ export declare function toNumberRV(v: RuntimeValue): NumberValue | ErrorValue; /** * Coerce a runtime value to a string. */ export declare function toStringRV(v: RuntimeValue): string; /** * Coerce a runtime value to a boolean. */ export declare function toBooleanRV(v: RuntimeValue): BooleanValue | ErrorValue; /** * Structural equality of scalar values. * * - Different kinds → false * - Number / Boolean / Blank → strict value equality (Blank always equal) * - String → case-insensitive comparison (Excel semantics) * - Error → not equal (errors do not compare equal to each other) */ /** * Three-way compare two scalars that share a kind. * * Returns a negative number if `a < b`, zero if equal, positive if `a > b`. * Returns `NaN` when the kinds differ or cannot be ordered (e.g. errors); * callers decide how to surface the incomparability — sort helpers usually * skip NaN pairs, while comparison operators route to a kind-priority * tiebreak. Strings are compared case-insensitively to match Excel. */ export declare function compareScalarsSameKind(a: ScalarValue, b: ScalarValue): number; export declare function scalarEquals(a: ScalarValue, b: ScalarValue): boolean; /** * Get the top-left scalar from any value (for implicit intersection fallback). */ export declare function topLeft(v: RuntimeValue): ScalarValue; /** * Convert a SnapshotCellValue to a RuntimeValue. */ export declare function fromSnapshotValue(v: number | string | boolean | { error: string; } | null): ScalarValue;