import type { Program, Value, ComprehensionExpr, RepeatExpr, FoldExpr, IfExpr, MatchExpr } from './program'; import type { Roll } from './dice-expression'; import { type BranchSelection, type DiceTerm, type StructuredDiceTerm } from './evaluator'; import type { RollResult, StructuredDiceRollResult } from './roll-result'; export interface ArithmeticEvent { type: 'arithmetic'; node: DiceTerm; result: RollResult; } export interface StructuredEvent { type: 'structured'; node: StructuredDiceTerm; result: StructuredDiceRollResult; } export interface IterationEnterEvent { type: 'iteration-enter'; node: ComprehensionExpr | RepeatExpr | FoldExpr; index: number; total: number; element?: Value; accumulator?: Value; } export interface IterationExitEvent { type: 'iteration-exit'; node: ComprehensionExpr | RepeatExpr | FoldExpr; index: number; } export interface FilterSkipEvent { type: 'filter-skip'; node: ComprehensionExpr; index: number; element: Value; } export interface SortReorderEvent { type: 'sort-reorder'; node: ComprehensionExpr; sourceToSorted: number[]; } /** * `branch-enter` fires once per evaluated `if` / `match`, after the * condition or scrutinee resolves and before any dice in the selected * arm fire. The matching `branch-exit` fires after the arm's body * returns. The opposite arm is never entered, so it contributes no * events. * * `branch` distinguishes `if-then` / `if-else` / `match-arm` (with the * source-order `armIndex` and `isWildcard` flag for the wildcard arm). * `scrutinee` is present only for value-mode `match` (i.e. `match VAL { … }`); * absent for `if` and for guard-mode `match { … }`. The field is omitted * rather than set to `undefined`, so `'scrutinee' in event` survives a * JSON round-trip as the value-mode discriminator. * * Branch events nest with iteration events on a shared depth stack — * consumers compute "which open branch contains this dice term" by * walking the event stream and maintaining a stack across both * `iteration-enter` / `iteration-exit` and `branch-enter` / `branch-exit`. */ export interface BranchEnterEvent { type: 'branch-enter'; node: IfExpr | MatchExpr; branch: BranchSelection; scrutinee?: Value; } export interface BranchExitEvent { type: 'branch-exit'; node: IfExpr | MatchExpr; } export type ScopeBoundaryEvent = IterationEnterEvent | IterationExitEvent | FilterSkipEvent | SortReorderEvent | BranchEnterEvent | BranchExitEvent; export type ExecutionEvent = ArithmeticEvent | StructuredEvent | ScopeBoundaryEvent; export interface ExecutionLog { draws: number[]; events: ExecutionEvent[]; } export interface RecordRunOptions { parameters?: Record; maxRepeatIterations?: number; /** * Include iteration-boundary events (`iteration-enter`, * `iteration-exit`, `filter-skip`, `sort-reorder`) in `log.events`. * Default `false` — existing replay consumers that expected the log * to contain only `arithmetic` / `structured` events keep working. * Enable for visualizers / debuggers that need lockstep AST walking. */ captureScopeEvents?: boolean; } export declare class ReplayDesyncError extends Error { constructor(message: string); } export declare function recordRun(program: Program, rollFn?: Roll, options?: RecordRunOptions): { value: Value; log: ExecutionLog; }; export declare function replayRun(program: Program, log: ExecutionLog, options?: RecordRunOptions): { value: Value; log: ExecutionLog; }; export declare function logToJSON(log: ExecutionLog): string; export declare function logFromJSON(json: string): ExecutionLog;