Skip to main content

Crate stack_assembly

Crate stack_assembly 

Source
Expand description

§StackAssembly

StackAssembly is a minimalist, stack-based, assembly-like programming language. Here’s a small taste:

# Push `0` to the stack.
0

increment:
    # Increment the value on the stack by `1`.
    1 +

    # If the value on the stack is smaller than `255`, jump to `increment:`.
    0 copy 255 <
    @increment
        jump_if

# Looks like we didn't jump to `increment:` that last time, so the value
# must be `255` now.
255 = assert

Please check out the repository on GitHub to learn more about StackAssembly. This documentation, while it contains some information about the language itself, is focused on how to use this library, which contains the StackAssembly interpreter.

§Usage

This library contains the interpreter for StackAssembly. It is intentionally minimalist. You provide a script, and the library gives you an API to evaluate it.

use stack_assembly::{Eval, Script};

let script = Script::compile("1 2 +");

let mut eval = Eval::new();
eval.run(&script);

assert_eq!(eval.operand_stack.to_i32_slice(), &[3]);

Script and Eval are the main entry points to the library’s API.

§Hosts

Eval evaluates scripts in a sandboxed environment, not giving them any access to the system it itself runs on. StackAssembly scripts by themselves cannot do much.

To change that, we need a host. A host is Rust code that uses this library to drive the evaluation of a StackAssembly script. It can choose to provide additional capabilities to the script.

use stack_assembly::{Effect, Eval, Script};

// A script that seems to want to print the value `3`.
let script = Script::compile("
    3 @print jump

    print:
        yield
");

// Start the evaluation and advance it until the script triggers an effect.
let mut eval = Eval::new();
let (effect, _) = eval.run(&script);

// `run` has returned, meaning an effect has triggered. Let's make sure that
// went as expected.
assert_eq!(effect, Effect::Yield);
let Ok(value) = eval.operand_stack.pop() else {
    unreachable!("We know that the script pushes a value before yielding.");
};

// The script calls `yield` at a label named `print`. I guess it expects us
// to print the value then.
println!("{value:?}");

When the script triggers the “yield” effect, this host prints the value that’s currently on top of the stack.

This is just a simple example. A more full-featured host would provide more services in addition to printing values. Such a host could determine which service the script means to request by inspecting which other values it put on the stack, or into memory.

Structs§

Eval
The ongoing evaluation of a script
Memory
A linear memory, freely addressable per word
OperandStack
The operand stack
OperandStackUnderflow
Tried to pop a value from an empty stack
OperatorIndex
Refers to an operator in a script
Script
A compiled script
Value
A unit of data

Enums§

Effect
An event triggered by scripts, to signal a specific condition