use std::{collections::HashMap, fmt}; #[cfg(test)] mod tests { use crate::{Parser, PreLispValue, Tokenizer, TokenizerError}; fn quick_parse(source: &str) -> Result, TokenizerError> { let mut tokenizer = Tokenizer::new(String::from(source)); let tokens = tokenizer.tokenize()?; let mut parser = Parser::new(tokens); Ok(parser.parse()) } fn var(name: &str) -> PreLispValue { PreLispValue::Var(String::from(name)) } fn string(s: &str) -> PreLispValue { PreLispValue::String(String::from(s)) } fn list(v: Vec, quoted: bool) -> PreLispValue { PreLispValue::List(v, quoted) } fn int(n: i32) -> PreLispValue { PreLispValue::Integer(n) } fn float(n: f32) -> PreLispValue { PreLispValue::Float(n) } #[test] fn test_hello_world() -> Result<(), TokenizerError> { assert_eq!( vec![list(vec![var("print"), string("Hello, World!")], false)], quick_parse( " (print \"Hello, World!\") " )? ); Ok(()) } #[test] fn test_math() -> Result<(), TokenizerError> { assert_eq!( vec![list( vec![ var("print"), list( vec![ var("add"), list( vec![ var("div"), float(4.5), list(vec![var("sub"), float(0.5), float(0.2)], false) ], false ), list(vec![var("mul"), int(21), float(0.05)], false) ], false ) ], false )], quick_parse( " (print (add (div 4.5 (sub 0.5 0.2) ) (mul 21 0.05) ) ) " )? ); Ok(()) } } use crate::Token; #[derive(Debug, Clone, PartialEq)] pub enum PreLispValue { Nil, True, False, String(String), Var(String), Integer(i32), Float(f32), List(Vec, bool), // Values, Quoted LispFunction(String, Vec, Vec), } impl fmt::Display for PreLispValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { PreLispValue::Nil => write!(f, "nil"), PreLispValue::True => write!(f, "true"), PreLispValue::False => write!(f, "false"), PreLispValue::String(str) => write!(f, "{}", str), PreLispValue::LispFunction(name, _, _) => write!(f, "", 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) => match name.as_str() { "nil" => values.push(PreLispValue::Nil), "true" => values.push(PreLispValue::True), "false" => values.push(PreLispValue::False), _ => values.push(PreLispValue::Var(name.to_owned())), }, Token::Index(map, idx) => { values.push(PreLispValue::List( vec![ PreLispValue::Var(String::from("get")), PreLispValue::Var(map.to_owned()), PreLispValue::String(idx.to_owned()), ], false, )); } 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 struct Parser { tokens: Vec, macros: HashMap) -> Vec>, } fn add_macro( macros: &mut HashMap) -> Vec>, name: impl Into, mac: fn(Vec) -> Vec, ) { macros.insert(name.into(), mac); } impl Parser { pub fn new(tokens: Vec) -> Parser { let mut macros = HashMap::new(); add_macro(&mut macros, "set", |x| { if x.len() != 3 || (!matches!(x[1], PreLispValue::Var(_)) && !matches!(x[1], PreLispValue::String(_))) { return x; } let mut list = x.clone(); if let PreLispValue::Var(name) = &list[1] { list[1] = PreLispValue::String(name.to_owned()) } list }); add_macro(&mut macros, "fn", |x| { if x.len() < 3 || x.len() > 4 { return x; } let mut name: String = String::new(); let mut args: &Vec = &Vec::new(); let mut list: &Vec = &Vec::new(); if x.len() == 3 { if !matches!(x[1], PreLispValue::List(_, _)) || !matches!(x[2], PreLispValue::List(_, _)) { return x; } name = String::from("Anonymous"); if let PreLispValue::List(l, _) = &x[1] { args = l; } if let PreLispValue::List(l, _) = &x[2] { list = l; } } else if x.len() == 4 { if !matches!(x[1], PreLispValue::Var(_)) || !matches!(x[2], PreLispValue::List(_, _)) || !matches!(x[3], PreLispValue::List(_, _)) { return x; } if let PreLispValue::Var(n) = &x[1] { name = n.to_owned(); } if let PreLispValue::List(l, _) = &x[2] { args = l; } if let PreLispValue::List(l, _) = &x[3] { list = l; } } else { return x; } let mut arg_names = Vec::new(); for arg in args { if let PreLispValue::Var(n) = arg { arg_names.push(n.to_owned()); } } let func = PreLispValue::LispFunction(name.clone(), arg_names, list.to_owned()); if x.len() == 4 { return vec![PreLispValue::Var(String::from("set")), name.into(), func]; } return vec![PreLispValue::Var(String::from("echo")), func]; }); Parser { tokens, macros } } fn macro_check(&mut self, input: Vec, quoted: bool) -> Vec { if quoted || input.len() < 1 { return input; } let mut output = input.clone(); for i in 0..output.len() { if let PreLispValue::List(elems, quoted) = &output[i] { output[i] = PreLispValue::List(self.macro_check(elems.to_vec(), *quoted), *quoted); } } if let PreLispValue::Var(name) = &output[0] { if self.macros.contains_key(name) { return self.macros.get(name).unwrap()(output); } } output } pub fn parse(&mut self) -> Vec { let mut values = Vec::new(); let mut i = 0; while i < self.tokens.len() { match &self.tokens[i] { Token::OpenParen => { let (tkns, close_paren_idx) = read_exp(i, &self.tokens).unwrap(); values.push(parse_exp(tkns, false)); i = close_paren_idx; } tkn => { // TODO: Include more error data panic!("Unexpected token {:?}", tkn); } } i += 1; } self.macro_check(values, false) } }