import type { SourceSpan, CommentAttachment } from './source-span'; import type { Identifier } from './program'; export type Sides = number; export type Roll = (sides: Sides) => number; export interface Die { type: 'die'; sides: number; loc?: SourceSpan; comments?: CommentAttachment; } export declare function die(sides: number): Die; export interface DiceReduce { type: 'dice-reduce'; reduceable: DiceReduceable; reducer: DiceReducer; loc?: SourceSpan; comments?: CommentAttachment; } export declare function diceReduce(reduceable: DiceReduceable, reducer: DiceReducer): DiceReduce; export interface CustomDie { type: 'custom-die'; faces: number[]; loc?: SourceSpan; comments?: CommentAttachment; } export declare function customDie(faces: number[]): CustomDie; export type NDiceParam = { kind: 'literal'; value: number; } | { kind: 'variable'; name: Identifier; }; export declare function nDiceLit(value: number): NDiceParam; export declare function nDiceVar(name: string | Identifier): NDiceParam; export interface NDice { type: 'n-dice'; count: NDiceParam; sides: NDiceParam; loc?: SourceSpan; comments?: CommentAttachment; } export declare function nDice(count: NDiceParam, sides: NDiceParam): NDice; export interface StructuredDiceRoll { type: 'structured-dice-roll'; count: NDiceParam; name: Identifier; loc?: SourceSpan; comments?: CommentAttachment; } export declare function structuredDiceRoll(count: NDiceParam, name: string | Identifier): StructuredDiceRoll; /** * The dice-side AST. Now a strict subset of the program-level `Expression` * union — the legacy `Literal` / `BinaryOp` / `UnaryOp` / `DiceVariableRef` * variants were dropped in favor of program-aligned `NumberLiteral` / * `BinaryExpr` / `UnaryExpr` / `VariableRef` (which are interchangeable * here since `Expression` is also a valid payload everywhere `DiceExpression` * appears). */ export type DiceExpression = Die | DiceReduce | CustomDie | NDice | StructuredDiceRoll; export type SimpleReducer = 'sum' | 'min' | 'max' | 'average' | 'median' | 'pool'; export interface CountReducer { type: 'count'; thresholds: Range[]; } export type DiceReducer = SimpleReducer | CountReducer; /** * A heterogeneous list of dice expressions to be reduced. Carried as * `Expression[]` (the unified AST) rather than `DiceExpression[]` so the * dice parser can populate the slots with program-aligned arithmetic / * literal nodes. */ export interface DiceExpressions { type: 'dice-expressions'; exprs: import('./program').Expression[]; } export declare function diceExpressions(...exprs: import('./program').Expression[]): DiceExpressions; export interface DiceListWithFilter { type: 'dice-list-with-filter'; list: DiceFilterable; filters: DiceFilter[]; } export declare function diceListWithFilter(list: DiceFilterable, filters: DiceFilter[]): DiceListWithFilter; export interface DiceListWithMap { type: 'dice-list-with-map'; dice: Sides[]; functor: DiceFunctor; } export declare function diceListWithMap(dice: Sides[], functor: DiceFunctor): DiceListWithMap; /** * Compact representation of N homogeneous dice in a "mapeable" position * (e.g. `Nd6 explode on 6`, `Nd6 reroll on 1`). Materializes individual rolls * at evaluation time rather than at parse time. */ export interface DiceListWithMapHomogeneous { type: 'dice-list-with-map-homogeneous'; count: NDiceParam; sides: NDiceParam; functor: DiceFunctor; } export declare function diceListWithMapHomogeneous(count: NDiceParam, sides: NDiceParam, functor: DiceFunctor): DiceListWithMapHomogeneous; /** * Compact representation of N homogeneous dice in a "reducer" position * (e.g. `Nd6 max`, `Nd6 sum`, `Nd6 count >= 4`). Materializes individual * rolls at evaluation time rather than at parse time. */ export interface HomogeneousDiceExpressions { type: 'homogeneous-dice-expressions'; count: NDiceParam; sides: NDiceParam; } export declare function homogeneousDiceExpressions(count: NDiceParam, sides: NDiceParam): HomogeneousDiceExpressions; /** * Compact representation of N copies of a custom-faced die (e.g. `NdF`) * in a reducer or filterable position. The dice all share `faces`. */ export interface HomogeneousCustomDice { type: 'homogeneous-custom-dice'; count: NDiceParam; faces: number[]; } export declare function homogeneousCustomDice(count: NDiceParam, faces: number[]): HomogeneousCustomDice; /** * A reduceable head that resolves a previously-bound list value at evaluation * time. Used for `$xs sum`, `$rolls max`, etc. where `$xs` / `$rolls` was * bound to a list-typed value (paren-list head or `repeat N { … }` block). */ export interface BindingRefReduceable { type: 'binding-ref-reduceable'; name: Identifier; } export declare function bindingRefReduceable(name: string | Identifier): BindingRefReduceable; export type DiceReduceable = DiceExpressions | DiceListWithFilter | DiceListWithMap | DiceListWithMapHomogeneous | HomogeneousDiceExpressions | HomogeneousCustomDice | BindingRefReduceable; export interface FilterableDiceArray { type: 'filterable-dice-array'; dice: Sides[]; } export declare function filterableDiceArray(dice: Sides[]): FilterableDiceArray; /** Like `DiceExpressions` but in a filter-list position. Carries Expression[]. */ export interface FilterableDiceExpressions { type: 'filterable-dice-expressions'; exprs: import('./program').Expression[]; } export declare function filterableDiceExpressions(...exprs: import('./program').Expression[]): FilterableDiceExpressions; /** * Compact representation of N homogeneous dice in a "filterable" position * (e.g. `Nd6 keep N`, `Nd6 drop N`). Materializes individual rolls at * evaluation time rather than at parse time. */ export interface FilterableHomogeneous { type: 'filterable-homogeneous'; count: NDiceParam; sides: NDiceParam; } export declare function filterableHomogeneous(count: NDiceParam, sides: NDiceParam): FilterableHomogeneous; /** * Compact representation of N copies of a custom-faced die (e.g. `NdF`) * in a filterable position. */ export interface FilterableHomogeneousCustom { type: 'filterable-homogeneous-custom'; count: NDiceParam; faces: number[]; } export declare function filterableHomogeneousCustom(count: NDiceParam, faces: number[]): FilterableHomogeneousCustom; /** * A filterable head that resolves a previously-bound list value at * evaluation time. Used for `$rolls keep highest 1`, `$xs drop lowest 1`, * etc. where the binding was assigned a list-typed value. */ export interface FilterableBindingRef { type: 'filterable-binding-ref'; name: Identifier; } export declare function filterableBindingRef(name: string | Identifier): FilterableBindingRef; /** * A filterable head produced by applying a functor (explode / reroll / * compound / emphasis) to a homogeneous or heterogeneous dice pool. * Materialises into per-original-die totals (each die's post-functor * value) so the filter pipeline ranks dice by their effective totals, * not by individual physical rolls. Lets `4d6 explode on 6 keep 3` * keep the three best per-die totals (each potentially the sum of an * exploded chain). */ export interface FilterableMapeable { type: 'filterable-mapeable'; inner: DiceListWithMap | DiceListWithMapHomogeneous; } export declare function filterableMapeable(inner: DiceListWithMap | DiceListWithMapHomogeneous): FilterableMapeable; export type DiceFilterable = FilterableDiceArray | FilterableDiceExpressions | FilterableHomogeneous | FilterableHomogeneousCustom | FilterableBindingRef | FilterableMapeable; /** * Filter count argument for `drop` / `keep`. * * Accepts any program {@link Expression}: literal (`4d6 drop 1`), variable * reference (`4d6 drop $n`), or arbitrary arithmetic (`4d6 drop ($n - 1)`). * Variables and arithmetic resolve from the evaluator's scope at runtime; * DiceStats throws on non-literal arguments (substitute upstream via * ProgramStats). * * Constructors auto-lift convenience inputs: * - `number` → `numberLiteral(n)` * - `NDiceParam` literal → `numberLiteral` * - `NDiceParam` variable → `variableRef` * - `Expression` passes through unchanged */ export interface Drop { type: 'drop'; dir: FilterDirection; value: import('./program').Expression; } export declare function drop(dir: FilterDirection, value: number | NDiceParam | import('./program').Expression): Drop; export interface Keep { type: 'keep'; dir: FilterDirection; value: import('./program').Expression; } export declare function keep(dir: FilterDirection, value: number | NDiceParam | import('./program').Expression): Keep; export type DiceFilter = Drop | Keep; export interface Explode { type: 'explode'; times: Times; range: Range; } export declare function explode(times: Times, range: Range): Explode; export interface Reroll { type: 'reroll'; times: Times; range: Range; } export declare function reroll(times: Times, range: Range): Reroll; export interface Emphasis { type: 'emphasis'; tieBreaker: 'high' | 'low' | 'reroll'; furthestFrom: number | 'average'; } export declare function emphasis(tieBreaker: 'high' | 'low' | 'reroll', furthestFrom: number | 'average'): Emphasis; export interface Compound { type: 'compound'; times: Times; range: Range; } export declare function compound(times: Times, range: Range): Compound; export interface Combined { type: 'combined'; reroll: Reroll; explode: Explode | Compound; } export declare function combined(reroll: Reroll, explode: Explode | Compound): Combined; export type DiceFunctor = Explode | Reroll | Emphasis | Compound | Combined; export interface Always { type: 'always'; } export declare function always(): Always; export interface UpTo { type: 'up-to'; /** * Iteration cap for the parent functor (`explode N times`, `reroll N times`). * Accepts any program {@link Expression} — literal, variable reference, * or arithmetic. */ value: import('./program').Expression; } export declare function upTo(value: number | NDiceParam | import('./program').Expression): UpTo; export type Times = Always | UpTo; /** * Range value arguments accept any program {@link Expression}. Constructor * helpers accept `number | NDiceParam | Expression` and auto-lift. */ export interface Exact { type: 'exact'; value: import('./program').Expression; } export declare function exact(value: number | NDiceParam | import('./program').Expression): Exact; export interface Between { type: 'between'; minInclusive: import('./program').Expression; maxInclusive: import('./program').Expression; } export declare function between(minInclusive: number | NDiceParam | import('./program').Expression, maxInclusive: number | NDiceParam | import('./program').Expression): Between; export interface ValueOrMore { type: 'value-or-more'; value: import('./program').Expression; } export declare function valueOrMore(value: number | NDiceParam | import('./program').Expression): ValueOrMore; export interface ValueOrLess { type: 'value-or-less'; value: import('./program').Expression; } export declare function valueOrLess(value: number | NDiceParam | import('./program').Expression): ValueOrLess; export interface Composite { type: 'composite'; ranges: Range[]; } export declare function composite(ranges: Range[]): Composite; export interface OnMax { type: 'on-max'; } export declare function onMax(): OnMax; export type Range = Exact | Between | ValueOrMore | ValueOrLess | Composite | OnMax; export type LowHigh = 'low' | 'high'; /** Direction for `keep`/`drop` filters. `'middle'` selects the central * band of a sorted pool; when the inner/outer split is uneven, the low * end loses one more die than the high end. */ export type FilterDirection = LowHigh | 'middle'; export type DiceUnOp = 'negate'; export interface InsufficientSides { type: 'insufficient-sides'; sides: number; } export declare function insufficientSides(sides: number): InsufficientSides; export interface EmptySet { type: 'empty-set'; } export declare function emptySet(): EmptySet; export interface InfiniteReroll { type: 'infinite-reroll'; sides: number; range: Range; } export declare function infiniteReroll(sides: number, range: Range): InfiniteReroll; /** * Static infinite-reroll check skipped because the range carries a * non-literal value (a `$variable` or arithmetic expression). The * evaluator's `maxExplodeIterations` / `maxRerollIterations` caps still * bound runtime behaviour, so this is informational — surfaces in editor * lints and CLI diagnostics so a user who *intends* a finite range can * spot a typo (`explode on $hi` where `$hi` happens to be the die's max). */ export interface UncheckedInfiniteReroll { type: 'unchecked-infinite-reroll'; sides: number; range: Range; } export declare function uncheckedInfiniteReroll(sides: number, range: Range): UncheckedInfiniteReroll; export interface TooManyDrops { type: 'too-many-drops'; available: number; toDrop: number; } export declare function tooManyDrops(available: number, toDrop: number): TooManyDrops; export interface TooManyKeeps { type: 'too-many-keeps'; available: number; toKeep: number; } export declare function tooManyKeeps(available: number, toKeep: number): TooManyKeeps; export interface DropOrKeepShouldBePositive { type: 'drop-or-keep-should-be-positive'; } export declare function dropOrKeepShouldBePositive(): DropOrKeepShouldBePositive; export interface EmptyFaces { type: 'empty-faces'; } export declare function emptyFaces(): EmptyFaces; export type ValidationMessage = InsufficientSides | EmptySet | InfiniteReroll | UncheckedInfiniteReroll | TooManyDrops | TooManyKeeps | DropOrKeepShouldBePositive | EmptyFaces;