use crate::environment::Env; use crate::lexer::Token; use crate::lexer::Tokens; use std::cmp::Ordering; use std::fmt; #[derive(Debug, Clone)] pub enum Datum { Boolean(bool), Number(i64), String(String), Symbol(String), Pair(Box<(Datum, Datum)>), List(Vec), Primitive(fn(Vec) -> Datum), Lambda { parameters: Vec, body: Vec, }, Procedure { parameters: Vec, body: Vec, env: Env, }, Unspecified, } pub fn make_symbol(s: &str) -> Datum { Datum::Symbol(s.to_string()) } impl Default for Datum { fn default() -> Self { Datum::Unspecified } } impl PartialEq for Datum { fn eq(&self, other: &Self) -> bool { match (self, other) { (Datum::Boolean(b1), Datum::Boolean(b2)) => b1 == b2, (Datum::Number(n1), Datum::Number(n2)) => n1 == n2, _ => false, } } } impl fmt::Display for Datum { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Datum::Boolean(true) => write!(f, "#t"), Datum::Boolean(false) => write!(f, "#f"), Datum::Number(n) => write!(f, "{}", n), Datum::Symbol(s) => write!(f, "{}", s), Datum::String(s) => write!(f, "{}", s), Datum::Pair(p) => write!(f, "({} . {})", p.0, p.1), Datum::List(v) => { let mut s = String::new(); s.push_str("("); for e in v { let es = format!("{} ", e); if es != "list " { s.push_str(&es); } } s.pop(); // remove last space s.push_str(")"); write!(f, "{}", s) } _ => panic!("DISPLAY -- cannot print {:?}", self), } } } impl PartialOrd for Datum { fn partial_cmp(&self, other: &Self) -> Option { match (self, other) { (Datum::Boolean(b1), Datum::Boolean(b2)) => Some(b1.cmp(b2)), (Datum::Number(n1), Datum::Number(n2)) => Some(n1.cmp(n2)), _ => None, } } } impl Datum { pub fn as_str(&self) -> Option { match self { Datum::Symbol(s) => Some(s.to_string()), _ => None, } } } pub fn parse(tokens: Tokens) -> Datum { let (datum, _) = parse_datum(&tokens, 0); datum } fn parse_datum(tokens: &Tokens, ix: usize) -> (Datum, usize) { match &tokens[ix] { Token::Identifier(s) => (Datum::Symbol(s.to_string()), ix + 1), Token::Boolean(b) => (Datum::Boolean(*b), ix + 1), Token::Number(n) => (Datum::Number(*n), ix + 1), Token::String(s) => (Datum::String(s.to_string()), ix + 1), Token::Quote => parse_quote(tokens, ix + 1), Token::LeftRoundBracket => parse_list(tokens, ix + 1), _ => panic!("Unexpected token {:?}", tokens[ix]), } } pub fn parse_quote(tokens: &Tokens, ix: usize) -> (Datum, usize) { let mut datums = vec![make_symbol("quote")]; let (datum, ix) = parse_datum(tokens, ix); datums.push(datum); (Datum::List(datums), ix) } pub fn parse_list(tokens: &Tokens, mut ix: usize) -> (Datum, usize) { let mut datums = vec![]; while ix < tokens.len() && tokens[ix] != Token::RightRoundBracket { let (datum, new_ix) = parse_datum(tokens, ix); datums.push(datum); ix = new_ix; } if ix == tokens.len() { panic!("PARSE_LIST -- missing closing bracket {:?}", tokens) } (Datum::List(datums), ix + 1) }