use std::{collections::HashMap, fmt}; use crate::{OpCode, PreLispValue}; pub struct LispState { table: HashMap, } fn add_function + Clone>(table: &mut HashMap, name: T, func: fn(Vec) -> Vec) { table.insert(name.clone().into(), LispValue::RustFunction(name.into(), func)); } #[derive(Debug, Clone)] pub enum LispValue { Nil, String(String), Integer(i32), Float(f32), List(Vec), LispFunction(String, Vec), RustFunction(String, fn(Vec) -> Vec), } impl fmt::Display for LispValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { LispValue::Nil => write!(f, "nil"), LispValue::String(str) => write!(f, "{}", str), LispValue::LispFunction(name, _) => write!(f, "<'{}': Lisp Function>", name), LispValue::RustFunction(name, _) => write!(f, "<'{}': Rust Function>", name), LispValue::Integer(num) => write!(f, "{}", num), LispValue::Float(num) => write!(f, "{}", num), val => { write!(f, "{}", format!("{:?}", val)) } } } } impl From<&str> for LispValue { fn from(value: &str) -> Self { LispValue::String(value.to_string()) } } impl From for LispValue { fn from(value: String) -> Self { LispValue::String(value) } } impl From for LispValue { fn from(value: i32) -> Self { LispValue::Integer(value) } } impl From for LispValue { fn from(value: f32) -> Self { LispValue::Float(value) } } impl LispState { pub fn new() -> LispState { let mut table = HashMap::new(); add_function(&mut table, "print", |x| { let mut strings = Vec::new(); for val in x { strings.push(val.to_string()); } let str = strings.join(" "); println!("{}", str); vec![LispValue::Nil] }); add_function(&mut table, "concat", |x| { let mut strings = Vec::new(); for val in x { strings.push(val.to_string()); } let str = strings.concat(); vec![LispValue::String(str)] }); add_function(&mut table, "add", |x| { if x.len() < 1 { return vec![LispValue::Nil] } else if x.len() == 1 { return vec![x[0].clone()]; } let mut t = "int"; for v in &x { match v { LispValue::Float(_) => t = "float", LispValue::Integer(_) => (), _ => return vec![LispValue::Nil] } } match t { "int" => { let mut sum = 0; for v in &x { if let LispValue::Integer(n) = v { sum += n; } else { unreachable!() } } return vec![LispValue::Integer(sum)]; }, "float" => { let mut sum = 0.0 as f32; for v in &x { if let LispValue::Float(n) = v { sum += n; } else if let LispValue::Integer(n) = v{ sum += *n as f32; } else { unreachable!() } } return vec![LispValue::Float(sum)]; }, _ => unreachable!() } }); add_function(&mut table, "sub", |x| { if x.len() < 1 { return vec![LispValue::Nil] } else if x.len() == 1 { return vec![x[0].clone()]; } let mut t = "int"; for v in &x { match v { LispValue::Float(_) => t = "float", LispValue::Integer(_) => (), _ => return vec![LispValue::Nil] } } match t { "int" => { if let LispValue::Integer(n) = x[0] { let mut sum = n; for i in 1..x.len() { if let LispValue::Integer(n) = &x[i] { sum -= n; } else { unreachable!() } } return vec![LispValue::Integer(sum)]; } else { unreachable!() } }, "float" => { if let LispValue::Float(n) = x[0] { let mut sum = n; for i in 1..x.len() { if let LispValue::Float(n) = &x[i] { sum -= *n; } else if let LispValue::Integer(n) = &x[i] { sum -= *n as f32; } else { unreachable!() } } return vec![LispValue::Float(sum)]; } else if let LispValue::Integer(n) = x[0] { let mut sum = n as f32; for i in 1..x.len() { if let LispValue::Float(n) = &x[i] { sum -= *n; } else if let LispValue::Integer(n) = &x[i] { sum -= *n as f32; } else { unreachable!() } } return vec![LispValue::Float(sum)]; } { unreachable!() } }, _ => unreachable!() } }); add_function(&mut table, "mul", |x| { if x.len() < 1 { return vec![LispValue::Nil] } else if x.len() == 1 { return vec![x[0].clone()]; } let mut t = "int"; for v in &x { match v { LispValue::Float(_) => t = "float", LispValue::Integer(_) => (), _ => return vec![LispValue::Nil] } } match t { "int" => { if let LispValue::Integer(n) = x[0] { let mut sum = n; for i in 1..x.len() { if let LispValue::Integer(n) = &x[i] { sum *= n; } else { unreachable!() } } return vec![LispValue::Integer(sum)]; } else { unreachable!() } }, "float" => { if let LispValue::Float(n) = x[0] { let mut product = n; for i in 1..x.len() { if let LispValue::Float(n) = &x[i] { product *= *n; } else if let LispValue::Integer(n) = &x[i] { product *= *n as f32; } else { unreachable!() } } return vec![LispValue::Float(product)]; } else if let LispValue::Integer(n) = x[0] { let mut product = n as f32; for i in 1..x.len() { if let LispValue::Float(n) = &x[i] { product *= *n; } else if let LispValue::Integer(n) = &x[i] { product *= *n as f32; } else { unreachable!() } } return vec![LispValue::Float(product)]; } { unreachable!() } }, _ => unreachable!() } }); add_function(&mut table, "div", |x| { if x.len() < 1 { return vec![LispValue::Nil] } else if x.len() == 1 { return vec![x[0].clone()]; } let mut t = "int"; for v in &x { match v { LispValue::Float(_) => t = "float", LispValue::Integer(_) => (), _ => return vec![LispValue::Nil] } } match t { "int" => { if let LispValue::Integer(n) = x[0] { let mut sum = n; for i in 1..x.len() { if let LispValue::Integer(n) = &x[i] { sum /= n; } else { unreachable!() } } return vec![LispValue::Integer(sum)]; } else { unreachable!() } }, "float" => { if let LispValue::Float(n) = x[0] { let mut product = n; for i in 1..x.len() { if let LispValue::Float(n) = &x[i] { product /= *n; } else if let LispValue::Integer(n) = &x[i] { product /= *n as f32; } else { unreachable!() } } return vec![LispValue::Float(product)]; } else if let LispValue::Integer(n) = x[0] { let mut product = n as f32; for i in 1..x.len() { if let LispValue::Float(n) = &x[i] { product /= *n; } else if let LispValue::Integer(n) = &x[i] { product /= *n as f32; } else { unreachable!() } } return vec![LispValue::Float(product)]; } { unreachable!() } }, _ => unreachable!() } }); LispState { table } } fn do_call(&self, opcode: &OpCode) -> Vec { if let OpCode::Call(func, args) = opcode { let f = self.table.get(func).unwrap(); let mut args: Vec = args.clone(); for i in 0..args.len() { let arg = &args[i]; if let LispValue::Eval(OpCode::Exp(opcodes)) = arg { if opcodes.len() < 1 { args[i] = LispValue::Nil; continue; } let call_opcode = opcodes.last().unwrap(); let mut res = self.do_call(call_opcode); args.remove(i); for j in 0..res.len() { args.insert(i + j, res.remove(0)); } } } if let LispValue::RustFunction(_, f) = f { return f(args.to_vec()); } else { todo!(); } } else { panic!("Bad OpCode: expected OpCode::Call") } } pub fn execute(&self, instructions: Vec) { for op in instructions { match op { OpCode::Call(func, args) => { self.do_call(&OpCode::Call(func, args)); }, OpCode::Exp(ins) => { self.execute(ins); } } } } }