pub struct Eval {
pub effect: Option<Effect>,
pub stack: Stack,
pub memory: Memory,
/* private fields */
}Expand description
§The ongoing evaluation of a script
This is the main entry point into this library’s API. To evaluate a script,
you can pass it to Eval::start, then use Eval::run or Eval::step
to advance the evaluation.
§Example
use stack_assembly::Eval;
let script = "1 2 +";
let mut eval = Eval::start(script);
eval.run();
assert_eq!(eval.stack.to_i32_slice(), &[3]);Fields§
§effect: Option<Effect>§The active effect, if one has triggered
Effects moderate the communication between script and host. The effect
itself only relays which effect has triggered, but that may signal to
the host that a different communication channel (like stack or
memory) is ready to be accessed.
Eval::start initializes this field to None. Eval::run and
Eval::step may store an effect here, if the script triggers one. If
that is the case, the host may handle the effect, to allow evaluation
to continue.
§Handling Effects
The host may handle effects however it wishes. But since most effects signal error conditions that the script would not expect to recover from, a well-behaving host must be careful not to handle effects in a way that make reasoning about the script’s behavior difficult.
Abandoning the evaluation and reporting an error in the appropriate
manner, is the only reasonable way to handle most effects. The
exception to that is Effect::Yield, which does not signal an error
condition. A script would expect to continue afterwards.
To make that possible, the host must clear the effect by setting this
field to None.
§Example
use stack_assembly::{Effect, Eval};
// This script increments a number in a loop, yielding control to the
// host every time it did so.
let script = "
0
increment:
1 +
yield
@increment jump
";
let mut eval = Eval::start(script);
// When running the script for the first time, we expect that it has
// incremented the number once, before yielding.
eval.run();
assert_eq!(eval.effect, Some(Effect::Yield));
assert_eq!(eval.stack.to_u32_slice(), &[1]);
// To allow the script to continue, we must clear the effect.
eval.effect = None;
// Since we handled the effect correctly, we can now assume that the
// script has incremented the number a second time, before yielding
// again.
eval.run();
assert_eq!(eval.effect, Some(Effect::Yield));
assert_eq!(eval.stack.to_u32_slice(), &[2]);stack: Stack§The operand stack
StackAssembly’s evaluation model is based on an implicit stack which stores all operands. An operator’s output is pushed to that stack, and any of its inputs are popped from there.
Alongside memory, this field is the primary channel for
communication between script and host.
Most hosts should restrict modifications to this field to when the
script triggers Effect::Yield, and then only do so in a
well-reasoned and documented manner. Anything else might make reasoning
about the script’s behavior very difficult.
None the less, the host has full access to this field, as to not restrict any experimental or non-standard use cases.
memory: Memory§The memory
StackAssembly provides a linear memory that is freely addressable per word.
Alongside stack, this field is the primary channel for
communication between script and host.
Most hosts should restrict modifications to this field to when the
script triggers Effect::Yield, and then only do so in a
well-reasoned and documented manner. Anything else might make reasoning
about the script’s behavior very difficult.
None the less, the host has full access to this field, as to not restrict any experimental or non-standard use cases.
Implementations§
Source§impl Eval
impl Eval
Sourcepub fn start(script: &str) -> Self
pub fn start(script: &str) -> Self
§Start evaluating the provided script
Compile the provided script and return an Eval instance that is ready
for evaluation. To evaluate any operators, you must call Eval::run
or Eval::step.
Sourcepub fn run(&mut self) -> &mut Effect
pub fn run(&mut self) -> &mut Effect
§Advance the evaluation until it triggers an effect
If an effect is currently active (see effect field), do nothing and
return immediately. Otherwise, keep evaluating operators until one
triggers an effect.
If you need more control over the evaluation, consider using
Eval::step instead.
Sourcepub fn step(&mut self)
pub fn step(&mut self)
§Advance the evaluation by one step
If an effect is currently active (see effect field), do nothing and
return immediately. Otherwise, evaluate the next operator. If that
triggers an effect, store that in the effect field.
This function may be used for advancing the evaluation of the script in
a controlled manner. If you just want to keep evaluating until the next
effect, consider using Eval::run instead.