# Scriptful
___Scriptful_ is a minimalistic `no_std` stack machine for executing domain specific interpreted languages.__
This library is heavily inspired by [FORTH] and [Script][BitcoinScript], the scripting language in Bitcoin.
## General design
The whole library is built around four main concepts:
- __[Stack]__: an ordered sequence of values that can be operated in a [LIFO]-alike way.
- __[Item]__: either a `Value` (a piece of data to be pushed into the stack) or an `Operator` (the descriptor for an action that operates on the topmost items in the stack).
- __[Operator system]__: a function that decides how each operator will mutate a given stack.
- __[Script]__: an ordered sequence of items (values and operators) that can be passed to an operator system for operating on a given stack.
- __[Machine]__: a convenient wrapper around a stack that enables multiple modes of operation.
Using this library is as easy as:
1. Defining your own set of operators, or using any of the ones that come bundled in the [`op_systems`][Operator system] module.
2. Defining your own [operator system][Operator system] function, or using any of the ones that come bundled in the [`op_systems`][Operator system] module.
3. Instantiating a [machine][Machine] with a reference to your operator system.
4. Composing a [script][Script] and running it in the machine.
## Quick example
```rust
use scriptful::prelude::*;
use scriptful::prelude::Value::*;
#[derive(Debug, PartialEq, Eq)]
/// You can define your own operators.
enum MyOperator {
Add,
Equal,
Sub,
}
/// An operator system decides what to do with the stack when each operator is
/// applied on it.
fn my_operator_system(stack: &mut Stack, operator: &MyOperator) {
match operator {
MyOperator::Add => {
let a = stack.pop();
let b = stack.pop();
stack.push(a + b);
}
MyOperator::Equal => {
let a = stack.pop();
let b = stack.pop();
stack.push(Value::Boolean(a == b));
}
MyOperator::Sub => {
let a = stack.pop();
let b = stack.pop();
stack.push(a - b);
}
}
}
// Instantiate the machine with a reference to your operator system.
let mut machine = Machine::new(&my_operator_system);
// Run a script that simply adds `1` and `2`
let result = machine.run_script(&[
Item::Value(Integer(1)),
Item::Value(Integer(2)),
Item::Operator(MyOperator::Add),
]);
// The result should unsurprisingly be `3`
assert_eq!(*result, Integer(3));
```
## License
Scriptful is distributed under the terms of both the MIT license and the Apache License (Version 2.0).
See [LICENSE-APACHE] and [LICENSE-MIT], and [COPYRIGHT] for details.
[FORTH]: https://en.wikipedia.org/wiki/Forth_(programming_language)
[BitcoinScript]: https://en.bitcoin.it/wiki/Script
[LIFO]: https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
[Stack]: https://docs.rs/scriptful/latest/scriptful/core/stack/struct.Stack.html
[Item]: https://docs.rs/scriptful/latest/scriptful/core/item/enum.Item.html
[Operator system]: https://docs.rs/scriptful/latest/scriptful/op_systems/
[Script]: https://docs.rs/scriptful/latest/scriptful/core/type.Script.html
[Machine]: https://docs.rs/scriptful/latest/scriptful/core/machine/struct.Machine.html
[LICENSE-APACHE]: LICENSE-APACHE
[LICENSE-MIT]: LICENSE-MIT
[COPYRIGHT]: COPYRIGHT