import { type DiceExpression, type Die, type NDice, type CustomDie, type StructuredDiceRoll, type DiceReduce, type DiceReduceable, type DiceFilterable, diceReduce, diceExpressions, diceListWithFilter, filterableDiceExpressions } from './dice-expression'; export type { Die, NDice, CustomDie, StructuredDiceRoll, DiceReduce, } from './dice-expression'; export { type SourceSpan, type Comment, type CommentAttachment, } from './source-span'; import type { SourceSpan, CommentAttachment } from './source-span'; export interface Program { type: 'program'; statements: Statement[]; comments?: CommentAttachment; } export declare function program(statements: Statement[]): Program; /** * A named identifier node. Used at every position in the AST where a * name appears — both at declaration sites (`Assignment.name`, * `ComprehensionExpr.name`, `FoldExpr.accName`/`elemName`, * `ParameterDeclaration.name`, `DiceDeclaration.name`) and at reference * sites (`VariableRef.name`). * * The `sigil` distinguishes `$`-prefixed variable identifiers from * `@`-prefixed dice identifiers; it's data, not parser-implicit, so * pretty-printers and analyzers don't need to derive it from context. * * `loc` covers the sigil + identifier characters as written in source * (e.g. `$x` is offset/length 2). Parser-built identifiers always * populate it; hand-built identifiers (via the `identifier` helper or * via the auto-lift in constructor functions) leave it undefined. * * Identifiers are not part of the `Expression` union — they're a * structural sub-node that other nodes embed. */ export interface Identifier { type: 'identifier'; /** Bare name, without the sigil prefix. */ name: string; /** Source sigil: `$` for variable identifiers, `@` for dice identifiers. */ sigil: '$' | '@'; loc?: SourceSpan; } export declare function identifier(name: string, sigil?: '$' | '@'): Identifier; /** * Compare identifiers by name and sigil, ignoring `loc`. Useful in * analyses that need to match references to declarations without caring * which source position each came from. */ export declare function identifierEquals(a: Identifier, b: Identifier): boolean; export type Statement = Assignment | ExpressionStatement | ParameterDeclaration | DiceDeclaration; export interface Assignment { type: 'assignment'; /** Binder identifier (`$name`). `sigil` is always `'$'`. */ name: Identifier; value: Expression; loc?: SourceSpan; comments?: CommentAttachment; } export declare function assignment(name: string | Identifier, value: Expression): Assignment; export interface ExpressionStatement { type: 'expression-statement'; expr: Expression; loc?: SourceSpan; comments?: CommentAttachment; } export declare function expressionStatement(expr: Expression): ExpressionStatement; export interface ParameterDeclaration { type: 'parameter-declaration'; /** Binder identifier (`$name`). `sigil` is always `'$'`. */ name: Identifier; spec: ParameterSpec; loc?: SourceSpan; comments?: CommentAttachment; } export interface ParameterSpec { default: ParameterDefault; label?: string; description?: string; min?: number; max?: number; /** Increment of the admissible value grid `{min + k·step}` (numeric defaults * only; requires `min` and `max`; mutually exclusive with `enum`). */ step?: number; enum?: Value[]; /** Display labels for `enum`, index-aligned with it. Present only when the * enum was written in object form (`{ "Label": value }`); for the array form * a consumer derives a label from the value itself. */ enumLabels?: string[]; } export type ParameterDefault = { kind: 'value'; value: Value; } | { kind: 'expression'; expr: Expression; }; export declare function parameterDeclaration(name: string | Identifier, spec: ParameterSpec): ParameterDeclaration; export interface DiceDeclaration { type: 'dice-declaration'; /** Binder identifier (`@name`). `sigil` is always `'@'`. */ name: Identifier; faces: Faces; loc?: SourceSpan; comments?: CommentAttachment; } export type Faces = { kind: 'records'; faces: Array<{ [field: string]: number; }>; } | { kind: 'numbers'; faces: number[]; }; export declare function diceDeclaration(name: string | Identifier, faces: Faces): DiceDeclaration; export type Expression = NumberLiteral | BooleanLiteral | StringLiteral | VariableRef | Die | NDice | CustomDie | StructuredDiceRoll | DiceReduce | BinaryExpr | UnaryExpr | RoundExpr | IfExpr | RecordExpr | ArrayExpr | RepeatExpr | FieldAccess | IndexAccess | SliceAccess | DefaultExpr | MatchExpr | ComprehensionExpr | FoldExpr; export interface NumberLiteral { type: 'number-literal'; value: number; loc?: SourceSpan; comments?: CommentAttachment; } export declare function numberLiteral(value: number): NumberLiteral; export interface BooleanLiteral { type: 'boolean-literal'; value: boolean; loc?: SourceSpan; comments?: CommentAttachment; } export declare function booleanLiteral(value: boolean): BooleanLiteral; export interface StringLiteral { type: 'string-literal'; value: string; loc?: SourceSpan; comments?: CommentAttachment; } export declare function stringLiteral(value: string): StringLiteral; export interface VariableRef { type: 'variable-ref'; /** Reference identifier (`$name`). `sigil` is always `'$'`. */ name: Identifier; loc?: SourceSpan; comments?: CommentAttachment; } export declare function variableRef(name: string | Identifier): VariableRef; export type BinaryOper = 'add' | 'subtract' | 'multiply' | 'divide' | 'eq' | 'neq' | 'gt' | 'lt' | 'gte' | 'lte' | 'and' | 'or'; export interface BinaryExpr { type: 'binary-expr'; op: BinaryOper; left: Expression; right: Expression; loc?: SourceSpan; comments?: CommentAttachment; } export declare function binaryExpr(op: BinaryOper, left: Expression, right: Expression): BinaryExpr; export interface UnaryExpr { type: 'unary-expr'; op: 'negate' | 'not'; expr: Expression; loc?: SourceSpan; comments?: CommentAttachment; } export declare function unaryExpr(op: 'negate' | 'not', expr: Expression): UnaryExpr; export type RoundMode = 'round' | 'round-up' | 'round-down' | 'truncate' | 'round-half-even'; export interface RoundExpr { type: 'round-expr'; mode: RoundMode; expr: Expression; loc?: SourceSpan; comments?: CommentAttachment; } export declare function roundExpr(expr: Expression, mode: RoundMode): RoundExpr; export interface IfExpr { type: 'if-expr'; condition: Expression; then: Expression; else: Expression; loc?: SourceSpan; comments?: CommentAttachment; } export declare function ifExpr(condition: Expression, then: Expression, else_: Expression): IfExpr; export interface RecordField { key: string; value: Expression; comments?: CommentAttachment; } export interface RecordExpr { type: 'record-expr'; fields: RecordField[]; loc?: SourceSpan; comments?: CommentAttachment; } export declare function recordExpr(fields: RecordField[]): RecordExpr; /** * Spread of a list-typed value into an array literal. Only legal as an * element of `ArrayExpr`. Evaluation rule: if `expr` evaluates to a list, * its elements concatenate into the surrounding array; if it evaluates * to a scalar, the evaluator throws. * * For homogeneous-dice operands (`[...3d6]`), the parser lifts the * `NDice` node to a pool-reduced equivalent at construction time so * the operand resolves to a list at evaluation. */ export interface SpreadElement { type: 'spread-element'; expr: Expression; loc?: SourceSpan; } export declare function spreadElement(expr: Expression): SpreadElement; export type ArrayElement = Expression | SpreadElement; export interface ArrayExpr { type: 'array-expr'; elements: ArrayElement[]; loc?: SourceSpan; comments?: CommentAttachment; } export declare function arrayExpr(elements: ArrayElement[]): ArrayExpr; export interface RepeatExpr { type: 'repeat-expr'; count: Expression; body: Statement[]; loc?: SourceSpan; comments?: CommentAttachment; } export declare function repeatExpr(count: Expression, body: Statement[]): RepeatExpr; export interface FieldAccess { type: 'field-access'; object: Expression; field: string; loc?: SourceSpan; comments?: CommentAttachment; } export declare function fieldAccess(object: Expression, field: string): FieldAccess; export interface IndexAccess { type: 'index-access'; object: Expression; index: Expression; loc?: SourceSpan; comments?: CommentAttachment; } export declare function indexAccess(object: Expression, index: Expression): IndexAccess; export interface SliceAccess { type: 'slice-access'; object: Expression; start?: Expression; end?: Expression; loc?: SourceSpan; comments?: CommentAttachment; } export declare function sliceAccess(object: Expression, start: Expression | undefined, end: Expression | undefined): SliceAccess; /** * Missing-value fallback operator: `primary default fallback`. * * Evaluates to `primary`'s value, unless evaluating `primary` produces *no * value* — a missing record field, an out-of-range index, or an undefined * outcome (e.g. division by zero) — in which case it evaluates to `fallback`. * It does NOT swallow other errors (type errors, undefined variables): strict * field access (issue #13) remains the default everywhere; this is the * explicit, local opt-out. Binds tighter than arithmetic, so * `a.x default 0 - b.y default 0` is `(a.x default 0) - (b.y default 0)`. */ export interface DefaultExpr { type: 'default-expr'; primary: Expression; fallback: Expression; loc?: SourceSpan; comments?: CommentAttachment; } export declare function defaultExpr(primary: Expression, fallback: Expression): DefaultExpr; export interface MatchExpr { type: 'match-expr'; value?: Expression; arms: MatchArm[]; loc?: SourceSpan; comments?: CommentAttachment; } export interface MatchArm { pattern: MatchPattern; guard?: Expression; body: Expression; loc?: SourceSpan; comments?: CommentAttachment; } export type MatchPattern = { kind: 'wildcard'; } | { kind: 'expression'; expr: Expression; }; export declare function matchExpr(value: Expression | undefined, arms: MatchArm[]): MatchExpr; export declare function matchArm(pattern: MatchPattern, body: Expression, guard?: Expression): MatchArm; export declare const wildcardPattern: MatchPattern; export declare function expressionPattern(expr: Expression): MatchPattern; export type Aggregator = 'sum' | 'max' | 'min' | 'count' | 'product' | 'average' | 'first' | 'last' | 'sort'; export interface ComprehensionExpr { type: 'comprehension-expr'; /** Loop binder identifier (`$name`). `sigil` is always `'$'`. */ binder: Identifier; source: Expression; filter?: Expression; body?: Expression; aggregator?: Aggregator; by?: Expression; direction?: 'asc' | 'desc'; loc?: SourceSpan; comments?: CommentAttachment; } export interface ComprehensionExprArgs { binder: string | Identifier; source: Expression; filter?: Expression; body?: Expression; aggregator?: Aggregator; by?: Expression; direction?: 'asc' | 'desc'; } export declare function comprehensionExpr(args: ComprehensionExprArgs): ComprehensionExpr; export interface FoldExpr { type: 'fold-expr'; array: Expression; init: Expression; /** Accumulator binder identifier. `sigil` is always `'$'`. */ accName: Identifier; /** Element binder identifier. `sigil` is always `'$'`. */ elemName: Identifier; body: Expression; loc?: SourceSpan; comments?: CommentAttachment; } export interface FoldExprArgs { array: Expression; init: Expression; accName: string | Identifier; elemName: string | Identifier; body: Expression; } export declare function foldExpr(args: FoldExprArgs): FoldExpr; export type Value = number | boolean | string | Value[] | { [key: string]: Value; }; export interface RuntimeError { type: 'runtime-error'; message: string; line?: number; } export declare function runtimeError(message: string, line?: number): RuntimeError; export declare function liftDiceExpression(d: DiceExpression): Expression; export { diceReduce, diceExpressions, diceListWithFilter, filterableDiceExpressions, }; export type { DiceExpression, DiceReduceable, DiceFilterable };