Skip to main content

mazer_core/
interpreter.rs

1use std::{collections::HashMap, fmt::Debug};
2
3use crate::parser::{LispErr, LispExpr};
4
5pub type Environment = HashMap<String, LispExpr>;
6
7#[derive(Debug)]
8pub struct Interpreter {
9    env: Environment,
10}
11
12impl Interpreter {
13    pub fn new() -> Self {
14        Interpreter {
15            env: Interpreter::stdenv(),
16        }
17    }
18
19    fn stdenv() -> Environment {
20        let mut env = HashMap::new();
21
22        // constants
23        env.insert("pi".to_string(), LispExpr::Number(std::f64::consts::PI));
24        env.insert("e".to_string(), LispExpr::Number(std::f64::consts::E));
25
26        // arithmetic functions
27        env.insert("+".to_string(), LispExpr::Function(|args, _| {
28            let sum: f64 = args.iter().map(|arg| {
29                if let LispExpr::Number(n) = arg {
30                    *n
31                } else {
32                    0.0
33                }
34            }).sum();
35            Ok(LispExpr::Number(sum))
36        }));
37
38        env.insert("-".to_string(), LispExpr::Function(|args, _env| {
39            if args.is_empty() {
40                return Err(LispErr::new("Subtraction requires at least one argument"));
41            }
42            
43            if let LispExpr::Number(first) = args[0] {
44                if args.len() == 1 {
45                    // Unary minus
46                    return Ok(LispExpr::Number(-first));
47                }
48                
49                let mut result = first;
50                for arg in &args[1..] {
51                    if let LispExpr::Number(n) = arg {
52                        result -= n;
53                    } else {
54                        return Err(LispErr::new(&format!("Expected number, got: {}", arg)));
55                    }
56                }
57                Ok(LispExpr::Number(result))
58            } else {
59                Err(LispErr::new(&format!("Expected number, got: {}", args[0])))
60            }
61        }));
62        
63        env.insert("*".to_string(), LispExpr::Function(|args, _env| {
64            let mut result = 1.0;
65            for arg in args {
66                if let LispExpr::Number(n) = arg {
67                    result *= n;
68                } else {
69                    return Err(LispErr::new(&format!("Expected number, got: {}", arg)));
70                }
71            }
72            Ok(LispExpr::Number(result))
73        }));
74        
75        env.insert("/".to_string(), LispExpr::Function(|args, _env| {
76            if args.is_empty() {
77                return Err(LispErr::new("/ requires at least one argument"));
78            }
79            
80            if let LispExpr::Number(first) = args[0] {
81                if args.len() == 1 {
82                    // Reciprocal
83                    if first == 0.0 {
84                        return Err(LispErr::new("Division by zero"));
85                    }
86                    return Ok(LispExpr::Number(1.0 / first));
87                }
88                
89                let mut result = first;
90                for arg in &args[1..] {
91                    if let LispExpr::Number(n) = arg {
92                        if *n == 0.0 {
93                            return Err(LispErr::new("Division by zero"));
94                        }
95                        result /= n;
96                    } else {
97                        return Err(LispErr::new(&format!("Expected number, got: {}", arg)));
98                    }
99                }
100                Ok(LispExpr::Number(result))
101            } else {
102                Err(LispErr::new(&format!("Expected number, got: {}", args[0])))
103            }
104        }));
105        
106        // Comparison operations
107        env.insert("=".to_string(), LispExpr::Function(|args, _env| {
108            if args.len() < 2 {
109                return Err(LispErr::new("= requires at least two arguments"));
110            }
111            
112            if let LispExpr::Number(first) = args[0] {
113                for arg in &args[1..] {
114                    if let LispExpr::Number(n) = arg {
115                        if first != *n {
116                            return Ok(LispExpr::Boolean(false));
117                        }
118                    } else {
119                        return Err(LispErr::new(&format!("Expected number, got: {}", arg)));
120                    }
121                }
122                Ok(LispExpr::Boolean(true))
123            } else {
124                Err(LispErr::new(&format!("Expected number, got: {}", args[0])))
125            }
126        }));
127        
128        env.insert(">".to_string(), LispExpr::Function(|args, _env| {
129            if args.len() != 2 {
130                return Err(LispErr::new("> requires exactly two arguments"));
131            }
132            
133            if let (LispExpr::Number(a), LispExpr::Number(b)) = (&args[0], &args[1]) {
134                Ok(LispExpr::Boolean(a > b))
135            } else {
136                Err(LispErr::new(&format!("Expected number, got: {} and {}", args[0], args[1])))
137            }
138        }));
139        
140        env.insert("<".to_string(), LispExpr::Function(|args, _env| {
141            if args.len() != 2 {
142                return Err(LispErr::new("< requires exactly two arguments"));
143            }
144            
145            if let (LispExpr::Number(a), LispExpr::Number(b)) = (&args[0], &args[1]) {
146                Ok(LispExpr::Boolean(a < b))
147            } else {
148                Err(LispErr::new(&format!("Expected number, got: {} and {}", args[0], args[1])))
149            }
150        }));
151        
152        // Math functions
153        env.insert("sqrt".to_string(), LispExpr::Function(|args, _env| {
154            if args.len() != 1 {
155                return Err(LispErr::new("sqrt requires exactly one argument"));
156            }
157            
158            if let LispExpr::Number(n) = args[0] {
159                if n < 0.0 {
160                    return Err(LispErr::new(&format!("Cannot take square root of negative number: {}", n)));
161                }
162                Ok(LispExpr::Number(n.sqrt()))
163            } else {
164                Err(LispErr::new(&format!("Expected number, got: {}", args[0])))
165            }
166        }));
167        
168        env.insert("pow".to_string(), LispExpr::Function(|args, _env| {
169            if args.len() != 2 {
170                return Err(LispErr::new("pow requires exactly two arguments"));
171            }
172            
173            if let (LispExpr::Number(base), LispExpr::Number(exp)) = (&args[0], &args[1]) {
174                Ok(LispExpr::Number(base.powf(*exp)))
175            } else {
176                Err(LispErr::new(&format!("Expected numbers, got: {} and {}", args[0], args[1])))
177            }
178        }));
179        
180        env
181    }
182
183    pub fn environment(&self) -> Environment {
184        self.env.clone()
185    }
186
187    pub fn get_symbol(&self, symbol: String) -> Option<LispExpr> {
188        self.env.get(&symbol).cloned()
189    }
190
191    pub fn set_symbol(&mut self, symbol: String, definition: LispExpr) {
192        self.env.insert(symbol, definition);
193    }
194
195    pub fn eval(&self, symbol: String) -> Result<LispExpr, LispErr> {
196        let _expr = self.get_symbol(symbol.clone()).ok_or(LispErr::new(&format!("Symbol {} not found", symbol)))?;
197        unimplemented!("interpreter::eval")
198    }
199}