1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! ___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::*;
//!
//! // You can define your own operators.
//! #[derive(Debug, PartialEq, Eq)]
//! 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));
//! ```
//!
//! # Known limitations
//!
//! - [Stacks][Stack] are currently implemented using a fixed-length, actually stack-allocated vectors using [smallvec].
//! Thus the `main` sub-stack is limited to 64 values, and the `alt` sub-stack can only hold up to 8.
//! - _Beware of unwraps!_ This is a proof-of-concept and it is modelled to panic upon errors.
//! Making the library safe for production usage is in the near horizon though.
//! - The possible value types that can be pushed into the [Stack] is not generic nor customizable.
//! Such feature will only be added if someone actually requests it.
//!
//! # 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]: core/stack/struct.Stack.html
//! [Item]: core/item/enum.Item.html
//! [Operator system]: op_systems/
//! [Script]: core/type.Script.html
//! [Machine]: core/machine/struct.Machine.html
//! [LICENSE-APACHE]: https://github.com/aesedepece/scriptful/blob/master/LICENSE-APACHE
//! [LICENSE-MIT]: https://github.com/aesedepece/scriptful/blob/master/LICENSE-MIT
//! [COPYRIGHT]: https://github.com/aesedepece/scriptful/blob/master/COPYRIGHT
//! [smallvec]: https://crates.io/crates/smallvec

#![no_std]
#![doc(html_playground_url = "https://play.rust-lang.org/")]

/// The core of this library.
///
/// Provides all the [`Item`][Item], [`Stack`][Stack], [`Machine`][Machine] and [`Value`][Value] goodness.
///
/// [Item]: item/
/// [Stack]: stack/
/// [Machine]: machine/
/// [Value]: value/
pub mod core;
/// Some ready-to-use operator systems that may be useful for _someone_, _somewhere_, _somewhen_.
pub mod op_systems;

/// Re-exports the most frequently used parts of this library so that they can be used more conveniently.
pub mod prelude {
    pub use crate::core::{item::Item, machine::Machine, stack::Stack, value::Value, Script};
}