/** * `each` runtime semantics — Phase 1 PR-2. * * Operational semantics, in order: * 1. Evaluate `in` — for PR-2, this is an identifier looked up in * `env.bindings`. Future PRs may widen to arbitrary expressions. * 2. Determine iteration shape from props (six exclusive cases — see * [[EachShape]]). Mixing shape props is a precondition failure. * 3. For each iteration step: * - Bind iteration variables into a child env. * - Emit one `iter-next` trace event with the primary binding. * - Recursively run children via the reference runner. * - Honor completion: `break` exits loop normally; `continue` proceeds; * `return`/`throw` propagate. * 4. Loop exit completes normally unless propagated. * * `await=true` is recorded as emitter information (it selects `for await` / * `async for` at codegen time) but the observable trace is identical to the * sync pair-mode. * * Pair-mode portability — PR-4 outcome: * The PR-3 differential harness surfaced three TS↔Python divergences in * pair-mode iteration: sync over array-of-pairs (Python `.items()` * AttributeError), async over sync Mapping, and async over empty sync * Mapping (Python `async for` requires `__aiter__`). PR-4 closes all * three by routing both targets through small runtime helpers — KERN * pair-mode is defined to iterate via the abstract operations * [[PairIterator]] (sync) and [[AsyncPairIterator]] (async). Both accept: * - any Mapping (via `.items()` on Python; native destructuring on TS) * - any iterable of `[k, v]` 2-tuples (positional destructure) * - any async iterable yielding `[k, v]` (async case only; sync data * is wrapped at iteration entry) * Production codegen emits `_kern_pairs(src)` / `_kern_async_pairs(src)` * on the Python target; TS uses native iteration since JS handles all * three shapes intrinsically. The observable trace is identical across * targets by construction. * * Out of scope for PR-2 (deferred): * - mutation during iteration (implementation-defined for now) * - non-identifier `in=` expressions * - lazy / infinite iterables (the runner materializes through `for...of`) */ import { type NodeContract } from './index.js'; export type EachShape = 'array' | 'array-indexed' | 'pair-sync' | 'pair-async' | 'entry-key' | 'entry-value'; export interface EachProps { name?: string; index?: string; pairKey?: string; pairValue?: string; entryKey?: string; entryValue?: string; entries?: boolean; await?: boolean; in?: string; type?: string; key?: string; } /** * Detect the iteration shape from props. Returns null if no shape matches OR * if multiple shape-defining props are mixed (which is a precondition failure * in the contract). Pure: never reads bindings or environment. */ export declare function detectEachShape(p: EachProps): EachShape | null; export declare const eachContract: NodeContract; /** Idempotent registration. Test cleanup that clears the registry must re-call. */ export declare function registerEachContract(): void; /** Reset registration flag — only for test cleanup that clears the registry. */ export declare function _resetEachContractForTest(): void;