From 8d2d0ebf0c095ada41dbbbfeb18b190dc822e475 Mon Sep 17 00:00:00 2001 From: Ava Affine Date: Thu, 24 Jul 2025 19:44:43 +0000 Subject: [PATCH] Clean up project structure The number package is moved into its own package henceforth referred to as "organelle". Hyphae and Mycelium are updated accordingly. In addition, Hyphae gets a copy of the sexpr module of Mycelium. This will not remain a copy, rather it will be the basis of a heap manager module within Mycelium to be worked on in the future. Fixes #32 Signed-off-by: Ava Affine --- Cargo.lock | 11 +- Cargo.toml | 2 +- hyphae/Cargo.toml | 2 +- hyphae/src/heap.rs | 219 ++++++++++++++++++ hyphae/src/lib.rs | 1 + hyphae/src/vm.rs | 4 +- mycelium/Cargo.toml | 2 +- mycelium/src/lib.rs | 1 - mycelium/src/parser.rs | 2 +- mycelium/src/sexpr.rs | 2 +- organelle/Cargo.toml | 8 + .../src/number.rs => organelle/src/lib.rs | 3 + 12 files changed, 247 insertions(+), 10 deletions(-) create mode 100644 hyphae/src/heap.rs create mode 100644 organelle/Cargo.toml rename mycelium/src/number.rs => organelle/src/lib.rs (99%) 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;