Eval

Struct Eval 

Source
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

Source

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.

Source

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.

Source

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.

Trait Implementations§

Source§

impl Debug for Eval

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Eval

§

impl RefUnwindSafe for Eval

§

impl Send for Eval

§

impl Sync for Eval

§

impl Unpin for Eval

§

impl UnwindSafe for Eval

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.