diff --git a/Cargo.toml b/Cargo.toml
index e69f2e1..df6ee70 100755
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,3 +1,13 @@
+cargo-features = ["profile-rustflags"]
+
[workspace]
resolver = "2"
members = ["mycelium", "decomposer", "hyphae", "organelle"]
+
+[profile.release]
+opt-level = 3
+strip = true
+lto = true
+codegen-units = 1
+panic = "abort"
+rustflags = [ "-Zlocation-detail=none", "-Zfmt-debug=none" ]
diff --git a/hyphae/src/heap.rs b/hyphae/src/heap.rs
index 46f4aab..b3d1ce4 100644
--- a/hyphae/src/heap.rs
+++ b/hyphae/src/heap.rs
@@ -15,15 +15,20 @@
* along with this program. If not, see .
*/
+use crate::serializer::DeserializerControlCode;
+
use core::ops::{Index, Deref, DerefMut};
use core::ptr::NonNull;
+use alloc::{vec, vec::Vec};
use alloc::rc::Rc;
-use alloc::vec::Vec;
use alloc::boxed::Box;
use alloc::fmt::Debug;
-use organelle::Number;
+use organelle::{Number, Fraction, SymbolicNumber, Float, ScientificNotation};
+
+const US: usize = (usize::BITS / 8) as usize;
+const IS: usize = (isize::BITS / 8) as usize;
/* NOTE
* decided not to implement a cache or a singleton heap manager
@@ -141,40 +146,6 @@ impl Gc {
}
}
-#[derive(PartialEq, Debug)]
-pub enum Datum {
- Number(Number),
- Bool(bool),
- Cons(Cons),
- Char(u8),
- String(Vec),
- Vector(Vec>),
- ByteVector(Vec),
- None
-}
-
-// implemented by hand to force deep copy on Cons datum
-impl Clone for Datum {
- fn clone(&self) -> Datum {
- match self {
- Datum::Number(n) => Datum::Number(n.clone()),
- Datum::Bool(n) => Datum::Bool(n.clone()),
- Datum::Cons(n) => Datum::Cons(n.deep_copy()),
- Datum::Char(n) => Datum::Char(n.clone()),
- Datum::String(n) => Datum::String(n.clone()),
- Datum::Vector(n) =>
- Datum::Vector(n.clone()),
- Datum::ByteVector(n) =>
- Datum::ByteVector(n.clone()),
- Datum::None => Datum::None,
- }
- }
-
- fn clone_from(&mut self, source: &Self) {
- *self = source.clone();
- }
-}
-
#[derive(Clone, PartialEq, Debug)]
pub struct Cons(pub Option>, pub Option>);
@@ -293,6 +264,260 @@ impl Index for Cons {
}
}
+#[derive(PartialEq, Debug)]
+pub enum Datum {
+ Number(Number),
+ Bool(bool),
+ Cons(Cons),
+ Char(u8),
+ String(Vec),
+ Vector(Vec>),
+ ByteVector(Vec),
+ None
+}
+
+// implemented by hand to force deep copy on Cons datum
+impl Clone for Datum {
+ fn clone(&self) -> Datum {
+ match self {
+ Datum::Number(n) => Datum::Number(n.clone()),
+ Datum::Bool(n) => Datum::Bool(n.clone()),
+ Datum::Cons(n) => Datum::Cons(n.deep_copy()),
+ Datum::Char(n) => Datum::Char(n.clone()),
+ Datum::String(n) => Datum::String(n.clone()),
+ Datum::Vector(n) =>
+ Datum::Vector(n.clone()),
+ Datum::ByteVector(n) =>
+ Datum::ByteVector(n.clone()),
+ Datum::None => Datum::None,
+ }
+ }
+
+ fn clone_from(&mut self, source: &Self) {
+ *self = source.clone();
+ }
+}
+
+impl Into> for Datum {
+ fn into(self) -> Vec {
+ match self {
+ Datum::Number(n) => {
+ let mut out: Vec = vec![];
+ match n {
+ Number::Sci(num) => {
+ out.push(DeserializerControlCode::SciNumber as u8);
+ for ele in num.0.to_be_bytes().iter() {
+ out.push(*ele);
+ }
+ for ele in num.1.to_be_bytes().iter() {
+ out.push(*ele);
+ }
+ out
+ },
+ Number::Flt(num) => {
+ out.push(DeserializerControlCode::FltNumber as u8);
+ for ele in num.0.to_be_bytes().iter() {
+ out.push(*ele);
+ }
+ out
+ },
+ Number::Fra(num) => {
+ out.push(DeserializerControlCode::FraNumber as u8);
+ for ele in num.0.to_be_bytes().iter() {
+ out.push(*ele);
+ }
+ for ele in num.1.to_be_bytes().iter() {
+ out.push(*ele);
+ }
+ out
+ },
+ Number::Sym(num) => {
+ match num {
+ SymbolicNumber::Inf => out.push(DeserializerControlCode::SymInf as u8),
+ SymbolicNumber::NaN => out.push(DeserializerControlCode::SymNan as u8),
+ SymbolicNumber::NegInf => out.push(DeserializerControlCode::SymNegInf as u8),
+ SymbolicNumber::NegNan => out.push(DeserializerControlCode::SymNegNan as u8),
+ }
+ out
+ }
+ }
+ },
+ Datum::Bool(b) if !b => vec![DeserializerControlCode::BoolFalse as u8],
+ Datum::Bool(b) if b => vec![DeserializerControlCode::BoolTrue as u8],
+ Datum::Bool(_) => panic!("rustc somehow has a third bool!"),
+ Datum::Cons(c) => {
+ if let Some(lop) = &c.0 {
+ if let Some(rop) = &c.1 {
+ let mut out = vec![DeserializerControlCode::FullCons as u8];
+ out.append(&mut (*lop.deref()).clone().into());
+ out.append(&mut (*rop.deref()).clone().into());
+ out
+ } else {
+ let mut out = vec![DeserializerControlCode::LeftCons as u8];
+ out.append(&mut (*lop.deref()).clone().into());
+ out
+ }
+ } else {
+ if let Some(rop) = &c.1 {
+ let mut out = vec![DeserializerControlCode::RightCons as u8];
+ out.append(&mut (*rop.deref()).clone().into());
+ out
+ } else {
+ vec![DeserializerControlCode::EmptyCons as u8]
+ }
+ }
+ },
+ Datum::Char(c) => vec![DeserializerControlCode::Char as u8, c],
+ Datum::String(c) => {
+ let mut v = vec![DeserializerControlCode::String as u8];
+ v.append(&mut c.len().to_be_bytes().to_vec());
+ v.append(&mut c.clone());
+ v
+ },
+ Datum::ByteVector(c) => {
+ let mut v = vec![DeserializerControlCode::ByteVec as u8];
+ v.append(&mut c.len().to_be_bytes().to_vec());
+ v.append(&mut c.clone());
+ v
+ },
+ Datum::Vector(c) => {
+ let mut v = vec![DeserializerControlCode::Vector as u8];
+ v.append(&mut c.len().to_be_bytes().to_vec());
+ c.iter().for_each(|i| v.append(&mut (*i.deref()).clone().into()));
+ v
+ },
+ Datum::None => vec![],
+ }
+ }
+}
+
+impl TryFrom<&[u8]> for Datum {
+ type Error = &'static str;
+ fn try_from(value: &[u8]) -> Result {
+ match DeserializerControlCode::try_from(value[0])? {
+ // this entire block goes away when we finish redoing organelle
+ DeserializerControlCode::SymInf =>
+ Ok(Datum::Number(Number::Sym(SymbolicNumber::Inf))),
+ DeserializerControlCode::SymNan =>
+ Ok(Datum::Number(Number::Sym(SymbolicNumber::NaN))),
+ DeserializerControlCode::SymNegInf =>
+ Ok(Datum::Number(Number::Sym(SymbolicNumber::NegInf))),
+ DeserializerControlCode::SymNegNan =>
+ Ok(Datum::Number(Number::Sym(SymbolicNumber::NegNan))),
+ DeserializerControlCode::SciNumber if value.len() >= 1 + 4 + IS => {
+ let i = f32::from_be_bytes(value[1..5].try_into().unwrap());
+ let j = isize::from_be_bytes(value[5..(5 + IS)].try_into().unwrap());
+ Ok(Datum::Number(Number::Sci(ScientificNotation(i, j))))
+ },
+ DeserializerControlCode::FltNumber if value.len() >= 9 => {
+ let i = f64::from_be_bytes(value[1..9].try_into().unwrap());
+ Ok(Datum::Number(Number::Flt(Float(i))))
+ },
+ DeserializerControlCode::FraNumber if value.len() >= 1 + (IS * 2) => {
+ let i = isize::from_be_bytes(value[1..(1 + IS)].try_into().unwrap());
+ let j = isize::from_be_bytes(value[(1 + IS)..(1 + IS + IS)].try_into().unwrap());
+ Ok(Datum::Number(Number::Fra(Fraction(i, j))))
+ },
+
+ DeserializerControlCode::BoolFalse => Ok(Datum::Bool(false)),
+ DeserializerControlCode::BoolTrue => Ok(Datum::Bool(true)),
+
+ DeserializerControlCode::EmptyCons if value.len() >= 1 =>
+ Ok(Datum::Cons(Cons(None, None))),
+
+ DeserializerControlCode::Char if value.len() >= 2 =>
+ Ok(Datum::Char(value[1])),
+
+ DeserializerControlCode::String if value.len() >= 1 + US => {
+ let len = usize::from_be_bytes(value[1..(1 + US)].try_into().unwrap());
+ if len < 1 {
+ Ok(Datum::String(vec![]))
+ } else if value.len() - (1 + US) < len {
+ Err("String vector backing is corrupted or truncated!")
+ } else {
+ Ok(Datum::String(value[(1 + US)..(1 + US + len)].to_vec()))
+ }
+ },
+
+ DeserializerControlCode::ByteVec if value.len() >= 1 + US => {
+ let len = usize::from_be_bytes(value[1..(1 + US)].try_into().unwrap());
+ if len < 1 {
+ Ok(Datum::ByteVector(vec![]))
+ } else if value.len() - (1 + US) < len {
+ Err("ByteVector vector backing is corrupted or truncated!")
+ } else {
+ Ok(Datum::ByteVector(value[(1 + US)..(1 + US + len)].to_vec()))
+ }
+ },
+
+ DeserializerControlCode::Vector if value.len() >= 1 + US => {
+ let len = usize::from_be_bytes(value[1..(1 + US)].try_into().unwrap());
+ if len < 1 {
+ Ok(Datum::Vector(vec![]))
+ } else {
+ let mut cursor: usize = 1 + US;
+ let mut ovec: Vec> = vec![];
+ for _ in 0..len {
+ ovec.push(Datum::try_from(&value[cursor..])?.into());
+ cursor += ovec.last().unwrap().byte_length();
+ }
+ Ok(Datum::Vector(ovec))
+ }
+ },
+
+ DeserializerControlCode::LeftCons if value.len() >= 2 =>
+ Ok(Datum::Cons(Cons(Some(Datum::try_from(&value[1..])?.into()), None))),
+ DeserializerControlCode::RightCons if value.len() >= 2 =>
+ Ok(Datum::Cons(Cons(None, Some(Datum::try_from(&value[1..])?.into())))),
+ DeserializerControlCode::FullCons if value.len() >= 3 => {
+ let lop = Datum::try_from(&value[1..])?;
+ let next = 1 + lop.byte_length();
+ let rop = Datum::try_from(&value[next..])?;
+ Ok(Datum::Cons(Cons(Some(lop.into()), Some(rop.into()))))
+ }
+
+ _ => Err("Deserializer Control Code not valid in this context")
+ }
+ }
+}
+
+impl Datum {
+ pub fn byte_length(&self) -> usize {
+ match self {
+ Datum::None => 0,
+ Datum::Bool(_) => 1,
+ Datum::Char(_) => 2,
+ // This will need to change with organelle
+ Datum::Number(n) => match n {
+ Number::Sym(_) => 1 as usize,
+ Number::Flt(_) => 1 + 8 as usize,
+ Number::Sci(_) => 1 + 4 + (isize::BITS / 8) as usize,
+ Number::Fra(_) => 1 + ((usize::BITS / 8) * 2) as usize,
+ },
+ Datum::String(s) => 1 + US + s.len(),
+ Datum::ByteVector(s) => 1 + US + s.len(),
+ Datum::Vector(s) => {
+ let mut c = 1 + US;
+ for i in s.iter() {
+ c += i.byte_length();
+ }
+ c
+ },
+ Datum::Cons(c) => {
+ let mut size = 1;
+ c.0.as_ref().and_then(|x| {
+ size += x.byte_length();
+ Some(())
+ });
+ c.1.as_ref().and_then(|x| {
+ size += x.byte_length();
+ Some(())
+ });
+ size
+ },
+ }
+ }
+}
#[cfg(test)]
mod tests {
@@ -362,4 +587,28 @@ mod tests {
drop(reference_holder);
assert!(!*(*copied_data).0);
}
+
+ #[test]
+ fn serialize_deserialize_datum_tests() {
+ let cases = vec![
+ Datum::Number("2/3".parse::().unwrap()),
+ Datum::Number("-4/5".parse::().unwrap()),
+ Datum::Number("2e45".parse::().unwrap()),
+ Datum::Number("1.2432566".parse::().unwrap()),
+ Datum::Number("+inf.0".parse::().unwrap()),
+ Datum::Cons(Cons(Some(Datum::Bool(true).into()), Some(Datum::Bool(false).into()))),
+ Datum::Cons(Cons(None, Some(Datum::Bool(true).into()))),
+ Datum::Cons(Cons(Some(Datum::Bool(true).into()), None)),
+ Datum::Cons(Cons(None, None)),
+ Datum::Cons(Cons(Some(Datum::Cons(Cons(None, Some(Datum::Bool(false).into()))).into()), None)),
+ Datum::Vector(vec![Datum::Bool(true).into(), Datum::Bool(true).into(), Datum::Bool(false).into()]),
+ Datum::Vector(vec![]),
+ Datum::Vector(vec![Datum::Vector(vec![Datum::Bool(true).into()]).into(), Datum::Bool(false).into()]),
+ ];
+
+ for i in cases.iter() {
+ let j: Vec = i.clone().into();
+ assert_eq!(*i, Datum::try_from(j.as_slice()).unwrap());
+ }
+ }
}
diff --git a/hyphae/src/lib.rs b/hyphae/src/lib.rs
index fe4ed14..6fda5d2 100644
--- a/hyphae/src/lib.rs
+++ b/hyphae/src/lib.rs
@@ -21,7 +21,7 @@ pub mod hmap;
pub mod stackstack;
pub mod instr;
pub mod vm;
-pub mod util;
+pub mod serializer;
pub mod heap;
extern crate alloc;
diff --git a/hyphae/src/util.rs b/hyphae/src/serializer.rs
similarity index 69%
rename from hyphae/src/util.rs
rename to hyphae/src/serializer.rs
index e699424..c3cd48b 100644
--- a/hyphae/src/util.rs
+++ b/hyphae/src/serializer.rs
@@ -16,6 +16,7 @@
*/
use crate::instr::Operation;
+use crate::heap::Datum;
use alloc::vec::Vec;
use alloc::vec;
@@ -23,6 +24,31 @@ use alloc::vec;
use core::ops::Index;
use core::mem::transmute;
+
+#[repr(u8)]
+#[derive(Debug, Clone, PartialEq)]
+pub enum DeserializerControlCode {
+ SciNumber = 0x00,
+ FltNumber = 0x01,
+ FraNumber = 0x02,
+ SymInf = 0x03,
+ SymNan = 0x04,
+ SymNegInf = 0x05,
+ SymNegNan = 0x06,
+ BoolFalse = 0x07,
+ BoolTrue = 0x08,
+ Char = 0x09,
+ String = 0x0A,
+ ByteVec = 0x0B,
+ Vector = 0x0C,
+ EmptyCons = 0x0D,
+ LeftCons = 0x0E,
+ RightCons = 0x0F,
+ FullCons = 0x10,
+ DataChunk = 0x11,
+ CodeChunk = 0x12,
+}
+
#[repr(u8)]
#[derive(Debug, Clone, PartialEq)]
pub enum Address {
@@ -38,6 +64,12 @@ pub enum Address {
Char = 0xfa, // immutable access only
}
+#[derive(Debug, Clone, PartialEq)]
+pub struct Deserializer<'a> {
+ pub input: &'a [u8],
+ // TODO: Debug levels for errors
+}
+
#[derive(Debug, Clone, PartialEq)]
pub struct Operand(pub Address, pub usize);
@@ -45,7 +77,7 @@ pub struct Operand(pub Address, pub usize);
pub struct Instruction(pub Operation, pub Vec);
#[derive(Debug, Clone, PartialEq)]
-pub struct Program(pub Vec);
+pub struct Program(pub Vec, pub Vec);
impl Into for Address {
fn into(self) -> u8 {
@@ -162,16 +194,39 @@ impl Instruction {
impl TryFrom<&[u8]> for Program {
type Error = &'static str;
fn try_from(value: &[u8]) -> Result {
+ let mut data: Vec = vec![];
let mut prog: Vec = vec![];
- let mut cur = 0;
- while cur < value.len() {
- let instruction: Instruction = value[cur..].try_into()?;
- cur += instruction.byte_length() as usize;
- prog.push(instruction);
- }
+ let mut parse_data = || -> Result {
+ let mut cur = 0;
+ if value[cur] != DeserializerControlCode::DataChunk as u8 {
+ return Ok(cur);
+ }
+ cur += 1;
+ while value[cur] != DeserializerControlCode::CodeChunk as u8 {
+ let datum: Datum = value[cur..].try_into()?;
+ cur += datum.byte_length();
+ data.push(datum);
+ }
+ Ok(cur)
+ };
- Ok(Program(prog))
+ let mut parse_code = |cur: usize| -> Result<(), Self::Error> {
+ let mut cur = cur;
+ if value[cur] != DeserializerControlCode::CodeChunk as u8 {
+ return Err("no code chunk detected in program");
+ }
+ cur += 1;
+ while cur < value.len() {
+ let instruction: Instruction = value[cur..].try_into()?;
+ cur += instruction.byte_length() as usize;
+ prog.push(instruction);
+ }
+ Ok(())
+ };
+
+ parse_code(parse_data()?)?;
+ Ok(Program(data, prog))
}
}
@@ -188,10 +243,37 @@ impl Into> for Program {
impl<'a> Index for Program {
type Output = Instruction;
fn index(&self, index: usize) -> &Instruction {
- self.0.get(index).expect("access to out of bounds instruction in vm")
+ self.1.get(index).expect("access to out of bounds instruction in vm")
}
}
+impl TryFrom for DeserializerControlCode {
+ type Error = &'static str;
+ fn try_from(value: u8) -> Result {
+ match value {
+ 0x00 => Ok(DeserializerControlCode::SciNumber),
+ 0x01 => Ok(DeserializerControlCode::FltNumber),
+ 0x02 => Ok(DeserializerControlCode::FraNumber),
+ 0x03 => Ok(DeserializerControlCode::SymInf),
+ 0x04 => Ok(DeserializerControlCode::SymNan),
+ 0x05 => Ok(DeserializerControlCode::SymNegInf),
+ 0x06 => Ok(DeserializerControlCode::SymNegNan),
+ 0x07 => Ok(DeserializerControlCode::BoolFalse),
+ 0x08 => Ok(DeserializerControlCode::BoolTrue),
+ 0x09 => Ok(DeserializerControlCode::Char),
+ 0x0A => Ok(DeserializerControlCode::String),
+ 0x0B => Ok(DeserializerControlCode::ByteVec),
+ 0x0C => Ok(DeserializerControlCode::Vector),
+ 0x0D => Ok(DeserializerControlCode::EmptyCons),
+ 0x0E => Ok(DeserializerControlCode::LeftCons),
+ 0x0F => Ok(DeserializerControlCode::RightCons),
+ 0x10 => Ok(DeserializerControlCode::FullCons),
+ 0x11 => Ok(DeserializerControlCode::DataChunk),
+ 0x12 => Ok(DeserializerControlCode::CodeChunk),
+ _ => Err("invalid control code")
+ }
+ }
+}
#[cfg(test)]
mod tests {
@@ -279,15 +361,24 @@ mod tests {
#[test]
fn test_program_parse() {
- let bytes1 = [instr::LINK.0, 0xf3, 0xf4];
- let out1 = vec![Instruction(instr::LINK,
+ let bytes1 = [
+ DeserializerControlCode::DataChunk as u8,
+ DeserializerControlCode::BoolTrue as u8,
+ DeserializerControlCode::CodeChunk as u8,
+ instr::LINK.0, 0xf3, 0xf4
+ ];
+ let out1a = vec![Datum::Bool(true)];
+ let out1b = vec![Instruction(instr::LINK,
vec![Operand(Address::Oper1, 0), Operand(Address::Oper2, 0)])];
let res1 =
TryInto::::try_into(&bytes1[..]);
assert!(res1.is_ok());
- assert_eq!(res1.unwrap().0, out1);
+ let res1 = res1.unwrap();
+ assert_eq!(res1.0, out1a);
+ assert_eq!(res1.1, out1b);
let bytes2 = [
+ DeserializerControlCode::CodeChunk as u8,
instr::LINK.0, 0xf3, 0xf4,
instr::CLEAR.0, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
];
@@ -304,6 +395,20 @@ mod tests {
let res2 =
TryInto::::try_into(&bytes2[..]);
assert!(res2.is_ok());
- assert_eq!(res2.unwrap().0, out2);
+ assert_eq!(res2.unwrap().1, out2);
+ }
+
+ #[test]
+ fn test_serializer_control_code_consistency() {
+ let mut input: u8 = 0x00;
+ loop {
+ if DeserializerControlCode::try_from(input)
+ .and_then(|x| Ok(assert!(x as u8 == input)))
+ .is_err() {
+ break;
+ }
+
+ input += 1;
+ }
}
}
diff --git a/hyphae/src/vm.rs b/hyphae/src/vm.rs
index 7c247fe..9372d16 100644
--- a/hyphae/src/vm.rs
+++ b/hyphae/src/vm.rs
@@ -21,7 +21,7 @@ use organelle::{Fraction, Number, Numeric};
use crate::hmap::QuickMap;
use crate::stackstack::StackStack;
use crate::instr as i;
-use crate::util::{Operand, Program, Address};
+use crate::serializer::{Operand, Program, Address, Instruction};
use crate::heap::{Gc, Datum, Cons};
use core::ops::DerefMut;
@@ -42,7 +42,7 @@ pub struct VM {
// execution environment
pub stack: StackStack>,
pub symtab: QuickMap,
- pub prog: Program,
+ pub prog: Vec,
pub traps: Vec>,
// data registers
@@ -61,10 +61,14 @@ pub struct VM {
impl From for VM {
fn from(value: Program) -> Self {
+ let mut s = StackStack::>::new();
+ value.0.iter()
+ .for_each(|d| s.push_current_stack(d.clone().into()));
+
VM{
- stack: StackStack::>::new(),
+ stack: s,
symtab: QuickMap::new(),
- prog: value,
+ prog: value.1,
traps: vec![],
expr: Datum::None.into(),
oper: array::from_fn(|_| Datum::None.into()),
@@ -88,7 +92,7 @@ impl VM {
.with_stack(stack)
.with_symbols(syms)
.with_traps(traps)
- .to_owned() // not efficient, but we are not executing
+ .to_owned() // not efficient
}
pub fn with_stack(
@@ -125,11 +129,11 @@ impl VM {
}
pub fn run_program(&mut self) {
- if self.prog.0.len() < 1 {
+ if self.prog.len() < 1 {
self.running = false;
}
- while self.ictr < self.prog.0.len() {
+ while self.ictr < self.prog.len() {
if self.err_state || !self.running {
return;
}
@@ -154,10 +158,10 @@ impl VM {
}
}
- if self.ictr > self.prog.0.len() {
+ if self.ictr > self.prog.len() {
e!("attempt to execute out of bounds instruction");
}
- let instr = &self.prog.0[self.ictr].clone();
+ let instr = &self.prog[self.ictr].clone();
// get or set according to addressing mode
macro_rules! access {
@@ -194,7 +198,7 @@ impl VM {
e!("illegal argument to jump");
};
- if target >= self.prog.0.len() {
+ if target >= self.prog.len() {
e!("out of bounds jump caught");
}
@@ -616,7 +620,7 @@ impl VM {
mod tests {
use super::*;
use crate::instr as i;
- use crate::util::{Program, Instruction, Operand};
+ use crate::serializer::{Program, Instruction, Operand};
use core::ops::Deref;
use organelle::Float;
@@ -699,7 +703,7 @@ mod tests {
#[test]
fn isa_trap_tests() {
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::TRAP, vec![Operand(Address::Numer, 0)])
])).with_traps(Some(vec![
Arc::from(|state: &mut VM| {
@@ -720,7 +724,7 @@ mod tests {
#[test]
fn isa_symtable_tests() {
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::BIND, vec![Operand(Address::Stack, 1),
Operand(Address::Stack, 0)]),
])).with_stack(Some({
@@ -743,7 +747,7 @@ mod tests {
vm.run_program();
assert!(case.test_passes(&vm));
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::BIND, vec![Operand(Address::Stack, 1),
Operand(Address::Stack, 0)]),
Instruction(i::BOUND, vec![Operand(Address::Stack, 1)])
@@ -767,7 +771,7 @@ mod tests {
vm.run_program();
assert!(case.test_passes(&vm));
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::BIND, vec![Operand(Address::Stack, 1),
Operand(Address::Stack, 0)]),
Instruction(i::UNBIND, vec![Operand(Address::Stack, 1)])
@@ -794,7 +798,7 @@ mod tests {
#[test]
fn isa_stack_tests() {
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
Operand(Address::Numer, 4)]),
Instruction(i::PUSH, vec![Operand(Address::Expr, 0)])
@@ -812,7 +816,7 @@ mod tests {
vm.run_program();
assert!(case.test_passes(&vm));
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
Operand(Address::Numer, 4)]),
Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]),
@@ -834,7 +838,7 @@ mod tests {
vm.run_program();
assert!(case.test_passes(&vm));
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
Operand(Address::Numer, 4)]),
Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]),
@@ -857,7 +861,7 @@ mod tests {
vm.run_program();
assert!(case.test_passes(&vm));
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
Operand(Address::Numer, 4)]),
Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]),
@@ -886,7 +890,7 @@ mod tests {
#[test]
fn isa_load_dupl_clear() {
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
Operand(Address::Numer, 4)]),
Instruction(i::LINK, vec![Operand(Address::Expr, 0),
@@ -915,7 +919,7 @@ mod tests {
#[test]
fn isa_nop_halt_panic() {
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::NOP, vec![])
]));
@@ -929,7 +933,7 @@ mod tests {
vm.run_program();
assert!(case.test_passes(&vm));
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::HALT, vec![]),
Instruction(i::PUSH, vec![Operand(Address::Numer, 1)])
]));
@@ -944,7 +948,7 @@ mod tests {
vm.run_program();
assert!(case.test_passes(&vm));
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::PANIC, vec![Operand(Address::Stack, 0)])
])).with_stack({
let mut i = StackStack::>::new();
@@ -965,7 +969,7 @@ mod tests {
#[test]
fn isa_inc_dec() {
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
Operand(Address::Numer, 4)]),
Instruction(i::INC, vec![Operand(Address::Expr, 0)]),
@@ -981,7 +985,7 @@ mod tests {
vm.run_program();
assert!(case.test_passes(&vm));
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
Operand(Address::Numer, 4)]),
Instruction(i::DEC, vec![Operand(Address::Expr, 0)]),
@@ -1000,7 +1004,7 @@ mod tests {
#[test]
fn isa_jmp_jmpif() {
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::JMP, vec![Operand(Address::Instr, 2)]),
Instruction(i::HALT, vec![]),
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
@@ -1017,7 +1021,7 @@ mod tests {
vm.run_program();
assert!(case.test_passes(&vm));
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::LINK, vec![Operand(Address::Stack, 0),
Operand(Address::Expr, 0)]),
Instruction(i::JMPIF, vec![Operand(Address::Instr, 3)]),
@@ -1040,7 +1044,7 @@ mod tests {
vm.run_program();
assert!(case.test_passes(&vm));
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::LINK, vec![Operand(Address::Stack, 0),
Operand(Address::Expr, 0)]),
Instruction(i::JMPIF, vec![Operand(Address::Instr, 3)]),
@@ -1063,7 +1067,7 @@ mod tests {
vm.run_program();
assert!(case.test_passes(&vm));
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::JMP, vec![Operand(Address::Instr, 300)]),
])).with_stack({
let mut i = StackStack::new();
@@ -1085,7 +1089,7 @@ mod tests {
#[test]
fn isa_conversions() {
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
// load from stack into expr
Instruction(i::DUPL, vec![Operand(Address::Stack, 0),
Operand(Address::Expr, 0)]),
@@ -1140,7 +1144,7 @@ mod tests {
#[test]
fn isa_consts() {
- let mut vm = VM::from(Program(vec![
+ let mut vm = VM::from(Program(vec![], vec![
Instruction(i::CONST, vec![Operand(Address::Expr, 0),
Operand(Address::Numer, 1)]),
Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]),
diff --git a/readme.md b/readme.md
index 1b7ddb4..576233d 100644
--- a/readme.md
+++ b/readme.md
@@ -8,9 +8,28 @@ project: a POSIX shell interpreter as well as a compiled to bytecode language fo
running on ESP32 devices.
## Current Status
-Currently the lexer and parser are implemented. On an X86 machine equipped with 64GB
-RAM and an AMD Ryzen 7900 CPU this lexer and parser are capable of creating a fully
+The lexer and parser are implemented. On an X86 machine equipped with 64GB RAM
+and an AMD Ryzen 7900 CPU this lexer and parser are capable of creating a fully
validated abstract syntax tree from approximately 11200 lines of handwritten scheme
in about 55 milliseconds on average.
-Currently the bytecode VM and its instruction set are next to implement.
+
+HyphaeVM is mostly implemented. The instruction set is defined and implemented,
+including extensibility interfaces and the VM layout. Additionally, instruction
+encoding and decoding are implemented. Garbage collection is implemented (via
+reference counting). Currently being implemented are datum encoding/decoding and
+full program encoding/decoding. Yet to be approached are debugging routines, CLI
+utilities, and concurrency features. However, Documentation has been written on
+programming with HyphaeVM.
+
+
+The R7RS-Small Scheme to HyphaeVM compiler is not implemented.
+
+
+R7RS-Large is not implemented.
+
+
+The Linux/Mac/Windows runtime and extended compiler is not implemented.
+
+
+Documentation is not implemented.