/* relish: versatile lisp shell * Copyright (C) 2021 Aidan Hahn * * 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 std::fmt; use std::marker::PhantomData; use std::ops::Index; // Container #[derive(Debug, Default)] pub enum Ctr { Symbol(String), String(String), Integer(i128), Float(f64), Bool(bool), Seg(Seg), #[default] None, } // Type of Container #[derive(PartialEq, Clone)] pub enum Type { Symbol, String, Integer, Float, Bool, Seg, None, } /* Segment * Holds two Containers. * Basic building block for more complex data structures. * I was going to call it Cell and then I learned about * how important RefCells were in Rust */ #[derive(Debug, Default)] pub struct Seg { /* "Contents of Address Register" * Historical way of referring to the first value in a cell. */ pub car: Box, /* "Contents of Decrement Register" * Historical way of referring to the second value in a cell. */ pub cdr: Box, /* Stupid hack that makes rust look foolish. * Needed to determine variance of lifetime. * How this is an acceptable solution I have * not a single clue. */ _lifetime_variance_determinant: PhantomData<()> } static NOTHING: Ctr = Ctr::None; impl Ctr { pub fn to_type(&self) -> Type { match self { Ctr::Symbol(_s) => Type::Symbol, Ctr::String(_s) => Type::String, Ctr::Integer(_s) => Type::Integer, Ctr::Float(_s) => Type::Float, Ctr::Bool(_s) => Type::Bool, Ctr::Seg(_s) => Type::Seg, Ctr::None => Type::None, } } } impl Seg { /* recurs over tree assumed to be list in standard form * appends object to end of list * * TODO: figure out how not to call CLONE on a CTR via obj arg * TODO: return result */ pub fn append(&mut self, obj: Box) { if let Ctr::None = &*(self.car) { self.car = obj; return } if let Ctr::Seg(s) = &mut *(self.cdr) { s.append(obj); return } if let Ctr::None = &mut *(self.cdr) { self.cdr = Box::new(Ctr::Seg(Seg::from_mono(obj))); // pray for memory lost to the void } } /* applies a function across a list in standard form * function must take a Ctr and return a bool * short circuits on the first false returned. * also returns false on a non standard form list */ pub fn circuit bool>(&self, func: &mut F) -> bool { if func(&self.car) { match &*(self.cdr) { Ctr::None => true, Ctr::Seg(l) => l.circuit(func), _ => false, } } else { false } } pub fn from_mono(arg: Box) -> Seg { Seg { car: arg, cdr: Box::new(Ctr::None), _lifetime_variance_determinant: PhantomData, } } pub fn from(car: Box, cdr: Box) -> Seg { Seg { car, cdr, _lifetime_variance_determinant: PhantomData, } } /* recurs over ast assumed to be list in standard form * returns length */ pub fn len(&self) -> u128 { let mut len = 0; self.circuit(&mut |_c: &Ctr| -> bool { len += 1; true }); len } pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn new() -> Seg { Seg { car: Box::new(Ctr::None), cdr: Box::new(Ctr::None), _lifetime_variance_determinant: PhantomData, } } } fn seg_to_string(s: &Seg, parens: bool) -> String { let mut string = String::new(); if parens { string.push('('); } match *(s.car) { Ctr::None => string.push_str(""), _ => string.push_str(&s.car.to_string()), } string.push(' '); match &*(s.cdr) { Ctr::Seg(inner) => string.push_str(&seg_to_string(inner, false)), Ctr::None => {string.pop();}, _ => string.push_str(&s.cdr.to_string()), } if parens { string.push(')'); } string } impl Clone for Seg { fn clone(&self) -> Seg { Seg { car: self.car.clone(), cdr: self.cdr.clone(), _lifetime_variance_determinant: PhantomData, } } } impl Index for Seg { type Output = Ctr; fn index(&self, idx: usize) -> &Self::Output { if idx == 0 { return &self.car; } if let Ctr::Seg(ref s) = *self.cdr { return s.index(idx - 1) } &NOTHING } } impl Clone for Ctr { fn clone(&self) -> Ctr { match self { Ctr::Symbol(s) => Ctr::Symbol(s.clone()), Ctr::String(s) => Ctr::String(s.clone()), Ctr::Integer(s) => Ctr::Integer(*s), Ctr::Float(s) => Ctr::Float(*s), Ctr::Bool(s) => Ctr::Bool(*s), Ctr::Seg(s) => Ctr::Seg(s.clone()), Ctr::None => Ctr::None, } } } impl fmt::Display for Ctr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Ctr::Symbol(s) => write!(f, "{}", s), Ctr::String(s) => write!(f, "\'{}\'", s), Ctr::Integer(s) => write!(f, "{}", s), Ctr::Float(s) => write!(f, "{}", s), Ctr::Bool(s) => { if *s { write!(f, "T") } else { write!(f, "F") } }, Ctr::Seg(s) => write!(f, "{}", s), Ctr::None => Ok(()), } } } impl fmt::Display for Seg { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", seg_to_string(self, true)) } } impl fmt::Display for Type { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let ret: &str = match self { Type::Symbol => "symbol", Type::String => "string", Type::Integer => "integer", Type::Float => "float", Type::Bool => "bool", Type::Seg => "segment", Type::None => "none", }; write!(f, "{}", ret) } } impl std::convert::From for Type { fn from(value: String) -> Self { match value.as_str() { "symbol" => Type::Symbol, "string" => Type::String, "integer" => Type::Integer, "float" => Type::Float, "bool" => Type::Bool, "segment" => Type::Seg, _ => Type::None, } } }