diff --git a/Cargo.lock b/Cargo.lock
index 97860ea..7e5eb99 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -134,8 +134,8 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
name = "hyphae"
version = "0.1.0"
dependencies = [
- "mycelium",
"num",
+ "organelle",
"serde",
"toml",
]
@@ -166,7 +166,7 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
name = "mycelium"
version = "0.1.0"
dependencies = [
- "num",
+ "organelle",
]
[[package]]
@@ -248,6 +248,13 @@ version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+[[package]]
+name = "organelle"
+version = "0.1.0"
+dependencies = [
+ "num",
+]
+
[[package]]
name = "proc-macro2"
version = "1.0.95"
diff --git a/Cargo.toml b/Cargo.toml
index 43867c5..e69f2e1 100755
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,3 +1,3 @@
[workspace]
resolver = "2"
-members = ["mycelium", "decomposer", "hyphae"]
+members = ["mycelium", "decomposer", "hyphae", "organelle"]
diff --git a/hyphae/Cargo.toml b/hyphae/Cargo.toml
index cb867ab..06538cd 100644
--- a/hyphae/Cargo.toml
+++ b/hyphae/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2024"
[dependencies]
-mycelium = { path = "../mycelium" }
+organelle = { path = "../organelle" }
num = { version = "0.4.3", features = ["alloc"] }
[build-dependencies]
diff --git a/hyphae/src/heap.rs b/hyphae/src/heap.rs
new file mode 100644
index 0000000..b1b49ae
--- /dev/null
+++ b/hyphae/src/heap.rs
@@ -0,0 +1,219 @@
+/* Mycelium Scheme
+ * Copyright (C) 2025 Ava Affine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+use core::fmt::{self, Formatter};
+use core::ops::Index;
+use core::cell::RefCell;
+
+use alloc::format;
+use alloc::rc::Rc;
+use alloc::vec::Vec;
+use alloc::string::String;
+
+use organelle::Number;
+
+#[derive(Default, Clone, PartialEq)]
+pub enum Datum {
+ Number(Number),
+ Bool(bool),
+ List(Rc),
+ Symbol(String),
+ Char(u8),
+ String(Vec),
+ Vector(RefCell>>),
+ ByteVector(RefCell>),
+ #[default]
+ None,
+}
+
+fn byte_to_escaped_char(b: u8) -> String {
+ // alarm, backspace, delete
+ match b {
+ _ if b > 31 && b < 127 => String::from(b as char),
+ _ => format!("x{:x}", b),
+ }
+}
+
+fn fmt_vec(ve: &RefCell>) -> String {
+ let v = ve.borrow();
+ if v.len() == 0 {
+ return String::new()
+ }
+ let mut s = format!("{}", v[0]);
+ let mut i = v.iter();
+ i.next(); // discard
+ i.for_each(|e| {
+ s = format!("{} {}", s, e);
+ });
+
+ s
+}
+
+impl fmt::Display for Datum {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ match self {
+ Datum::Number(n) => write!(f, "{}", Into::::into(*n)),
+ Datum::Bool(n) => write!(f, "{}", if *n {"#t"} else {"#f"}),
+ Datum::List(n) => write!(f, "{n}"),
+ Datum::Symbol(n) => write!(f, "{n}"),
+ Datum::Char(n) => write!(f, "#\\{}",
+ byte_to_escaped_char(*n)),
+ Datum::String(n) =>
+ write!(f, "\"{}\"", String::from_utf8_lossy(&*n)),
+ Datum::Vector(n) => write!(f, "#({})", fmt_vec(n)),
+ Datum::ByteVector(n) => write!(f, "#u8({})", fmt_vec(n)),
+ Datum::None => Ok(())
+ }
+ }
+}
+
+/* WARNING
+ * This is in a sense overloaded.
+ * Instead of using this to print debugging information for the
+ * Rust code, I have instead overloaded it to print the most
+ * maximal expanded valid syntax for this Datum
+ */
+impl fmt::Debug for Datum {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ match self {
+ Datum::Number(n) => write!(f, "{}", Into::::into(*n)),
+ Datum::Bool(n) => write!(f, "{}", if *n {"#t"} else {"#f"}),
+ Datum::List(n) => write!(f, "{n}"),
+ Datum::Char(n) => write!(f, "{}",
+ byte_to_escaped_char(*n)),
+ Datum::Symbol(n) => write!(f, "{n}"),
+ Datum::String(n) =>
+ write!(f, "\"{}\"", String::from_utf8_lossy(&*n)),
+ Datum::Vector(n) => write!(f, "#({n:?})"),
+ Datum::ByteVector(n) => write!(f, "#u8({n:?})"),
+ Datum::None => Ok(())
+ }
+ }
+}
+
+
+#[derive(Default, Clone, PartialEq)]
+pub struct Ast(pub Rc, pub Rc);
+
+impl Ast {
+ pub fn subsl(&self, start: isize, end: isize) -> Ast {
+ if end - start == 1 {
+ return Ast(Rc::from(self[start as usize].clone()), Rc::from(Datum::None))
+ }
+
+ if end == 0 {
+ return Ast(
+ Rc::from((*(self.0)).clone()),
+ Rc::from(Datum::None)
+ )
+ }
+
+ let Datum::List(ref next) = *self.1 else {
+ panic!("index into improper list form")
+ };
+
+ if start <= 0 {
+ Ast(
+ Rc::from((*(self.0)).clone()),
+ Rc::from(Datum::List(
+ Rc::from(next.subsl(start - 1, end - 1))))
+ )
+
+ } else {
+ next.subsl(start - 1, end - 1)
+ }
+ }
+
+ pub fn len(&self) -> usize {
+ let Datum::List(ref next) = *self.1 else {
+ return 1
+ };
+ 1 + next.len()
+ }
+}
+
+impl Iterator for Ast {
+ type Item = Rc;
+
+ fn next(&mut self) -> Option {
+ if let Datum::List(n) = &*self.1 {
+ let tmp_pair = n;
+ self.0 = tmp_pair.0.clone();
+ self.1 = tmp_pair.1.clone();
+ return Some(self.0.clone());
+ }
+
+ if let Datum::None = *self.1 {
+ return None;
+ }
+
+ let tmp = self.1.clone();
+ self.0 = Rc::from(Datum::None);
+ self.1 = Rc::from(Datum::None);
+ return Some(tmp);
+ }
+}
+
+impl Index for Ast {
+ type Output = Datum;
+ fn index(&self, index: usize) -> &Self::Output {
+ if index == 0 {
+ if let Datum::None = *self.0 {
+ panic!("out of bounds indexing into AST")
+ } else {
+ self.0.as_ref()
+ }
+ } else {
+ let Datum::List(ref next) = *self.1 else {
+ panic!("out of bounds indexing into AST")
+ };
+
+ next.index(index - 1)
+ }
+ }
+}
+
+impl fmt::Display for Ast {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "({}", self.0)?;
+ let mut cur = self;
+ while let Datum::List(next) = &*cur.1 {
+ cur = &next;
+ write!(f, " {}", cur.0)?;
+ }
+
+ if let Datum::None = &*cur.1 {
+ write!(f, ")")
+ } else {
+ write!(f, " . {})", cur.1)
+ }
+ }
+}
+
+impl fmt::Debug for Ast {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "({}", self.0)?;
+ let mut cur = self;
+ let mut end = 1;
+ while let Datum::List(next) = &*cur.1 {
+ cur = &next;
+ end += 1;
+ write!(f, "({} . ", cur.0)?
+ }
+ write!(f, "{}{}", cur.1, ")".repeat(end))
+ }
+}
diff --git a/hyphae/src/lib.rs b/hyphae/src/lib.rs
index 4de7909..fe4ed14 100644
--- a/hyphae/src/lib.rs
+++ b/hyphae/src/lib.rs
@@ -22,5 +22,6 @@ pub mod stackstack;
pub mod instr;
pub mod vm;
pub mod util;
+pub mod heap;
extern crate alloc;
diff --git a/hyphae/src/vm.rs b/hyphae/src/vm.rs
index 089e1fd..8a932fa 100644
--- a/hyphae/src/vm.rs
+++ b/hyphae/src/vm.rs
@@ -16,13 +16,13 @@
*/
-use mycelium::sexpr::Datum;
-use mycelium::number::{Fraction, Number, Numeric};
+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::heap::Datum;
use core::cell::RefCell;
diff --git a/mycelium/Cargo.toml b/mycelium/Cargo.toml
index 9370cd3..206b304 100644
--- a/mycelium/Cargo.toml
+++ b/mycelium/Cargo.toml
@@ -4,5 +4,5 @@ version = "0.1.0"
edition = "2024"
[dependencies]
-num = { version = "0.4.3", features = ["alloc"] }
+organelle = { path = "../organelle" }
diff --git a/mycelium/src/lib.rs b/mycelium/src/lib.rs
index e6896e7..f753f5e 100644
--- a/mycelium/src/lib.rs
+++ b/mycelium/src/lib.rs
@@ -23,7 +23,6 @@
pub mod sexpr;
pub mod lexer;
pub mod parser;
-pub mod number;
extern crate alloc;
diff --git a/mycelium/src/parser.rs b/mycelium/src/parser.rs
index 31dc0d5..6aa660f 100644
--- a/mycelium/src/parser.rs
+++ b/mycelium/src/parser.rs
@@ -26,7 +26,7 @@ use crate::lexer::{
E_CHAR_TOO_LONG,
E_END_OF_DOCUMENT
};
-use crate::number::{Number, Numeric};
+use organelle::{Number, Numeric};
use crate::sexpr::{Datum, Ast};
use alloc::vec::Vec;
diff --git a/mycelium/src/sexpr.rs b/mycelium/src/sexpr.rs
index d9f9438..b1b49ae 100644
--- a/mycelium/src/sexpr.rs
+++ b/mycelium/src/sexpr.rs
@@ -24,7 +24,7 @@ use alloc::rc::Rc;
use alloc::vec::Vec;
use alloc::string::String;
-use crate::number::Number;
+use organelle::Number;
#[derive(Default, Clone, PartialEq)]
pub enum Datum {
diff --git a/organelle/Cargo.toml b/organelle/Cargo.toml
new file mode 100644
index 0000000..4b7d9db
--- /dev/null
+++ b/organelle/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "organelle"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+num = { version = "0.4.3", features = ["alloc"] }
+
diff --git a/mycelium/src/number.rs b/organelle/src/lib.rs
similarity index 99%
rename from mycelium/src/number.rs
rename to organelle/src/lib.rs
index d9af991..3703d35 100644
--- a/mycelium/src/number.rs
+++ b/organelle/src/lib.rs
@@ -15,6 +15,9 @@
* along with this program. If not, see .
*/
+#![cfg_attr(not(test), no_std)]
+extern crate alloc;
+
use alloc::string::String;
use alloc::format;
use alloc::fmt::Debug;