use std::fmt; use crate::Token; #[derive(Debug, Clone)] pub enum PreLispValue { Nil, String(String), Var(String), Integer(i32), Float(f32), List(Vec, bool), // Values, Quoted LispFunction(String, Vec), } impl fmt::Display for PreLispValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { PreLispValue::Nil => write!(f, "nil"), PreLispValue::String(str) => write!(f, "{}", str), PreLispValue::LispFunction(name, _) => write!(f, "<'{}': Lisp Function>", name), PreLispValue::Integer(num) => write!(f, "{}", num), PreLispValue::Float(num) => write!(f, "{}", num), _ => todo!() } } } impl From<&str> for PreLispValue { fn from(value: &str) -> Self { PreLispValue::String(value.to_string()) } } impl From for PreLispValue { fn from(value: String) -> Self { PreLispValue::String(value) } } impl From for PreLispValue { fn from(value: i32) -> Self { PreLispValue::Integer(value) } } impl From for PreLispValue { fn from(value: f32) -> Self { PreLispValue::Float(value) } } impl From> for PreLispValue { fn from(value: Vec) -> Self { PreLispValue::List(value, false) } } // TODO: Handle failure fn read_exp(open_paren_idx: usize, tokens: &Vec) -> Option<(Vec, usize)> /* Option */ { let mut tkns = Vec::new(); let mut depth = 0; for i in open_paren_idx..tokens.len() { match &tokens[i] { Token::OpenParen => { if depth != 0 { tkns.push(Token::OpenParen); } depth += 1; } Token::CloseParen => { depth -= 1; if depth == 0 { return Some((tkns, i)); } else { tkns.push(Token::CloseParen) } } token => { tkns.push(token.clone()); } } } None } fn parse_exp(tokens: Vec, quoted: bool) -> PreLispValue { let mut values = Vec::new(); if tokens.len() < 1 { return PreLispValue::List(values, false); } let mut quote_next_list = false; let mut unquote_next_list = false; let mut i = 0; while i < tokens.len() { let tkn = &tokens[i]; match tkn { Token::Quote => { quote_next_list = true; }, Token::Unquote => { unquote_next_list = true; } Token::OpenParen => { let (tkns, close_paren_idx) = read_exp(i, &tokens).unwrap(); values.push(parse_exp(tkns, if unquote_next_list {false} else {quote_next_list || quoted})); i = close_paren_idx; quote_next_list = false; unquote_next_list = false; }, Token::Identifier(name) => { values.push(PreLispValue::Var(name.to_owned())); }, Token::Integer(num) => { values.push(PreLispValue::Integer(*num)); }, Token::Float(num) => { values.push(PreLispValue::Float(*num)); }, Token::String(str) => { values.push(PreLispValue::String(str.to_owned())); }, Token::CloseParen => { panic!("Unexpected closing parenthesis"); }, } i += 1; } PreLispValue::List(values, quoted) } pub fn parse(tokens: Vec) -> Vec { let mut values = Vec::new(); let mut i = 0; while i < tokens.len() { match &tokens[i] { Token::OpenParen => { let (tkns, close_paren_idx) = read_exp(i, &tokens).unwrap(); values.push(parse_exp(tkns, false)); i = close_paren_idx; } tkn => { // TODO: Include more error data panic!("Unexpected token {:?}", tkn); } } i += 1; } values }