Skip to main content

Module const_eval

Module const_eval 

Source
Expand description

Bounded, sandboxed compile-time evaluator for const initializers.

This module is the entire surface added by issue burin-labs/harn#1791. It takes a Harn AST expression that appears on the right-hand side of a const NAME = ... binding and either returns a ConstValue or a ConstEvalError. The evaluator runs entirely inside the parser crate, has zero access to the host or the runtime VM, and enforces three hard caps on every call:

  1. Step budget — every reduction increments a step counter. When the counter exceeds MAX_STEPS (default 100_000), evaluation aborts with ConstEvalErrorKind::StepLimit. The check is performed on every step, not amortized.
  2. Recursion depth — every recursive call into the interpreter increments a depth counter. Exceeding MAX_DEPTH (default 256) aborts with ConstEvalErrorKind::RecursionLimit.
  3. Sandbox denylist — any expression that reaches harness, spawns concurrency, mutates state, performs I/O, calls into a non-allowlisted builtin, references an unknown identifier, or invokes a user-defined function is rejected with ConstEvalErrorKind::SandboxViolation or ConstEvalErrorKind::Disallowed.

The evaluator is allowlist-based: only explicitly permitted node shapes evaluate. Newly added stdlib surface is sandboxed by default.

§Cache key shape

Each successful fold is keyed by:

  • the SHA-256 of the binding’s source-text expression (mirrors what downstream prompt-template specialization would consume), and
  • the tuple (MAX_STEPS, MAX_DEPTH, evaluator_version).

The cache itself is not implemented here — this module just exposes the inputs so a downstream consumer (e.g. compile-time prompt rendering) can wire it up without re-deriving the contract.

Structs§

ConstEvalError
A const-eval failure carries a span (so the typechecker can attribute the diagnostic to the offending sub-expression) and a human-friendly detail.

Enums§

ConstEvalErrorKind
Reason a const-eval call failed. Mapped 1:1 to diagnostic codes:
ConstValue
Stable version tag participating in the cache key. Bump when any observable semantic of the const-evaluator changes. A fully folded compile-time value.

Constants§

MAX_DEPTH
Hard cap on recursion depth into the interpreter. Each eval_node invocation increments the depth counter.
MAX_STEPS
Hard cap on the number of reduction steps performed by a single const_eval call. Checked on every step.

Functions§

const_eval
Public entry point: fold a single AST node into a ConstValue or return a ConstEvalError. The env argument supplies earlier const bindings visible to this expression.
round_float_to_digits
round(x, digits) for floats: half-away-from-zero at the requested decimal place, implemented by scale → f64::round → unscale. Non-finite inputs pass through unchanged. Shared by const folding and the runtime.
round_int_to_digits
round(n, digits) for ints: identity for digits >= 0; negative digits round to the nearest power-of-ten bucket, halves away from zero. Uses exact i128 arithmetic; a result outside the i64 range promotes to float, matching integer arithmetic overflow behavior elsewhere. Shared by const folding and the runtime round builtin so the two cannot drift.

Type Aliases§

ConstEnv
Environment mapping a const name to its already-folded value. The typechecker primes this with bindings encountered earlier in the same file (i.e. const X: int = 1 lets const Y: int = X + 2 resolve).