pub struct MilkEvaluator {
pub(crate) context: MilkContext,
compiled_cache: Vec<(String, Node)>,
}Expand description
Evaluator for Milkdrop expressions.
Fields§
§context: MilkContextExecution context
compiled_cache: Vec<(String, Node)>Compiled expressions cache
Implementations§
Source§impl MilkEvaluator
impl MilkEvaluator
Sourcepub fn eval_equation_list(&mut self, eqs: &[String]) -> EvaluationStats
pub fn eval_equation_list(&mut self, eqs: &[String]) -> EvaluationStats
Evaluate a flat list of equations, joining consecutive
paren-unbalanced lines (MD2 loop(...) idiom). Returns aggregate
stats; the evaluator’s context retains every variable touched by
the run.
Source§impl MilkEvaluator
impl MilkEvaluator
Sourcepub(super) fn preprocess_expression(&mut self, expression: &str) -> String
pub(super) fn preprocess_expression(&mut self, expression: &str) -> String
Pre-process expression to handle auto-initialization and type conversion.
Source§impl MilkEvaluator
impl MilkEvaluator
Sourcepub fn context(&self) -> &MilkContext
pub fn context(&self) -> &MilkContext
Get a reference to the context.
Sourcepub fn context_mut(&mut self) -> &mut MilkContext
pub fn context_mut(&mut self) -> &mut MilkContext
Get a mutable reference to the context.
Sourcepub fn compile(&mut self, expression: &str) -> Result<Node>
pub fn compile(&mut self, expression: &str) -> Result<Node>
Pre-compile an expression into an evalexpr Node that can be evaluated
repeatedly without re-parsing.
Pre-processing (auto-init of undefined variables, integer→float
promotion in assignments, if( → milkif( rewrite) runs as part of
compilation, so any variable referenced in expression is also
registered in self.context as a side effect — exactly like a normal
eval call. This means a context cloned out of this evaluator after a
compile call already contains every var the compiled Node will
look up at evaluation time.
Sourcepub fn eval_per_frame(&mut self, equations: &[String]) -> Result<()>
pub fn eval_per_frame(&mut self, equations: &[String]) -> Result<()>
Evaluate multiple expressions (per-frame equations).
Sourcepub fn eval_per_pixel(
&mut self,
x: f64,
y: f64,
rad: f64,
ang: f64,
equations: &[String],
) -> Result<()>
pub fn eval_per_pixel( &mut self, x: f64, y: f64, rad: f64, ang: f64, equations: &[String], ) -> Result<()>
Evaluate per-pixel equations for a single pixel.
Sourcepub fn compile_batch(&mut self, equations: &[String]) -> Result<Vec<Node>>
pub fn compile_batch(&mut self, equations: &[String]) -> Result<Vec<Node>>
Compile a batch of source strings into reusable Nodes. Use this on
load_preset for custom wave/shape equations, which run hundreds of
times per frame — avoiding per-eval reparse is a 10×+ speedup.
Sourcepub fn eval_compiled(&mut self, node: &Node) -> Result<f64>
pub fn eval_compiled(&mut self, node: &Node) -> Result<f64>
Evaluate a pre-compiled Node against this evaluator’s context. Skips
the regex preprocess that eval() runs every call — variables referenced
in the source string were already auto-initialized at compile() time.
Sourcepub fn eval_per_shape_instance(
&mut self,
instance: ShapeInstance,
compiled: &[Node],
) -> Result<ShapeInstance>
pub fn eval_per_shape_instance( &mut self, instance: ShapeInstance, compiled: &[Node], ) -> Result<ShapeInstance>
Evaluate per-frame equations for one instance of a custom shape
(shapecode_N). Seeds the loop variables (instance, sides,
num_inst) plus the full geometry/colour state, runs the
compiled per-frame Nodes, reads everything back into a fresh
ShapeInstance.
Unlike eval_per_point (which threads state across iterations
within a frame), each shape instance is independent: callers
pass the shape’s scalar block seed every time and instance
changes per call. Persistent state across instances lives in
q* / t* channels, which the context carries.
Sourcepub fn run_per_shape_instance(
&mut self,
instance: ShapeInstance,
block: &CompiledBlock,
) -> Result<ShapeInstance>
pub fn run_per_shape_instance( &mut self, instance: ShapeInstance, block: &CompiledBlock, ) -> Result<ShapeInstance>
Bytecode-aware companion of [eval_per_shape_instance]. Runs the
bytecode VM when [CompiledBlock::bytecode] is Some, otherwise
walks the evalexpr Node list.
Sourcefn seed_shape_instance(ctx: &mut MilkContext, instance: ShapeInstance)
fn seed_shape_instance(ctx: &mut MilkContext, instance: ShapeInstance)
Push the 23 hot-var seed values from instance into ctx.
Sourcefn read_shape_instance(
c: &MilkContext,
instance: ShapeInstance,
) -> ShapeInstance
fn read_shape_instance( c: &MilkContext, instance: ShapeInstance, ) -> ShapeInstance
Companion to [seed_shape_instance] — read every per-instance var
back, falling back to instance.* when a slot is missing.
Sourcepub fn run_per_point_bc(
&mut self,
point: WavePoint,
compiled: &CompiledBytecode,
) -> WavePoint
pub fn run_per_point_bc( &mut self, point: WavePoint, compiled: &CompiledBytecode, ) -> WavePoint
Bytecode counterpart of [eval_per_point]. Skips both the
String → Value::Float wrapping and the recursive operator-tree
walk that evalexpr does for each child node — the bytecode VM
just reads/writes hot slots by index and runs a flat opcode stream.
Sourcepub fn eval_per_point(
&mut self,
point: WavePoint,
compiled: &[Node],
) -> Result<WavePoint>
pub fn eval_per_point( &mut self, point: WavePoint, compiled: &[Node], ) -> Result<WavePoint>
Evaluate per-point equations for one sample inside a custom wave or
shape loop. point carries the input vars (sample, value1,
value2) and the carry-over geometry/colour (x, y, r, g,
b, a). The output echoes the same fields back, read from the
context after the equations ran.
The caller is responsible for seeding the loop on point 0 with the
wave’s base colour and any saved x/y, then threading the previous
point’s output into the next call — this matches MD2’s “trail across
samples within a frame” semantics.
Sourcepub fn eval_assignment(&mut self, expression: &str) -> Result<f64>
pub fn eval_assignment(&mut self, expression: &str) -> Result<f64>
Parse an assignment expression and update context. Returns the assigned value.
Trait Implementations§
Source§impl Clone for MilkEvaluator
Custom Clone impl that skips compiled_cache. The cache is per-call
memoisation for the regex-preprocess path; worker threads (the wave
and warp parallel passes) never re-enter that path — they’re given
pre-compiled Nodes by the caller — so cloning the cache is pure
overhead. The cache can grow into the hundreds of entries on a
long-running engine, so this matters: cloning a 100-entry
Vec<(String, Node)> is ~30 µs that goes away for free.
impl Clone for MilkEvaluator
Custom Clone impl that skips compiled_cache. The cache is per-call
memoisation for the regex-preprocess path; worker threads (the wave
and warp parallel passes) never re-enter that path — they’re given
pre-compiled Nodes by the caller — so cloning the cache is pure
overhead. The cache can grow into the hundreds of entries on a
long-running engine, so this matters: cloning a 100-entry
Vec<(String, Node)> is ~30 µs that goes away for free.