220 lines
6 KiB
Rust
220 lines
6 KiB
Rust
|
|
/* 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 <https://www.gnu.org/licenses/>.
|
||
|
|
*/
|
||
|
|
|
||
|
|
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<Ast>),
|
||
|
|
Symbol(String),
|
||
|
|
Char(u8),
|
||
|
|
String(Vec<u8>),
|
||
|
|
Vector(RefCell<Vec<Rc<Datum>>>),
|
||
|
|
ByteVector(RefCell<Vec<u8>>),
|
||
|
|
#[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<T: fmt::Display>(ve: &RefCell<Vec<T>>) -> 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::<String>::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::<String>::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<Datum>, pub Rc<Datum>);
|
||
|
|
|
||
|
|
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<Datum>;
|
||
|
|
|
||
|
|
fn next(&mut self) -> Option<Self::Item> {
|
||
|
|
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<usize> 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))
|
||
|
|
}
|
||
|
|
}
|