1use crate::{
2 model::{Env, Lambda, List, RuntimeError, Symbol, Value},
3 utils::{require_arg, require_typed_arg},
4};
5use std::{cell::RefCell, rc::Rc};
6
7pub fn eval(env: Rc<RefCell<Env>>, expression: &Value) -> Result<Value, RuntimeError> {
9 eval_inner(env, expression, Context::new())
10}
11
12pub fn eval_block(
15 env: Rc<RefCell<Env>>,
16 clauses: impl Iterator<Item = Value>,
17) -> Result<Value, RuntimeError> {
18 eval_block_inner(env, clauses, Context::new())
19}
20
21fn eval_block_inner(
22 env: Rc<RefCell<Env>>,
23 clauses: impl Iterator<Item = Value>,
24 context: Context,
25) -> Result<Value, RuntimeError> {
26 let mut current_expr: Option<Value> = None;
27
28 for clause in clauses {
29 if let Some(expr) = current_expr {
30 match eval_inner(env.clone(), &expr, context.found_tail(true)) {
31 Ok(_) => (),
32 Err(e) => {
33 return Err(e);
34 }
35 }
36 }
37
38 current_expr = Some(clause);
39 }
40
41 if let Some(expr) = ¤t_expr {
42 eval_inner(env, expr, context)
43 } else {
44 Err(RuntimeError {
45 msg: "Unrecognized expression".to_owned(),
46 })
47 }
48}
49
50fn eval_inner(
58 env: Rc<RefCell<Env>>,
59 expression: &Value,
60 context: Context,
61) -> Result<Value, RuntimeError> {
62 if context.quoting {
63 match expression {
64 Value::List(list) if *list != List::NIL => match &list.car()? {
65 Value::Symbol(Symbol(keyword)) if keyword == "comma" => {
66 }
68 _ => {
69 return list
70 .into_iter()
71 .map(|el| eval_inner(env.clone(), &el, context))
72 .collect::<Result<List, RuntimeError>>()
73 .map(Value::List);
74 }
75 },
76 _ => return Ok(expression.clone()),
77 }
78 }
79
80 match expression {
81 Value::Symbol(symbol) => env.borrow().get(symbol).ok_or_else(|| RuntimeError {
83 msg: format!("\"{}\" is not defined", symbol),
84 }),
85
86 Value::List(list) if *list != List::NIL => {
88 match &list.car()? {
89 Value::Symbol(Symbol(keyword)) if keyword == "comma" => {
91 eval_inner(env, &list.cdr().car()?, context.quoting(false))
92 }
93
94 Value::Symbol(Symbol(keyword)) if keyword == "quote" => {
95 eval_inner(env, &list.cdr().car()?, context.quoting(true))
96 }
97
98 Value::Symbol(Symbol(keyword)) if keyword == "define" || keyword == "set" => {
99 let args = &list.cdr().into_iter().collect::<Vec<Value>>();
100
101 let symbol = require_typed_arg::<&Symbol>(keyword, args, 0)?;
102 let value_expr = require_arg(keyword, args, 1)?;
103
104 let value = eval_inner(env.clone(), value_expr, context.found_tail(true))?;
105
106 if keyword == "define" {
107 env.borrow_mut().define(symbol.clone(), value.clone());
108 } else {
109 env.borrow_mut().set(symbol.clone(), value.clone())?;
110 }
111
112 Ok(value)
113 }
114
115 Value::Symbol(Symbol(keyword)) if keyword == "defmacro" => {
116 let args = &list.cdr().into_iter().collect::<Vec<Value>>();
117
118 let symbol = require_typed_arg::<&Symbol>(keyword, args, 0)?;
119 let argnames_list = require_typed_arg::<&List>(keyword, args, 1)?;
120 let argnames = value_to_argnames(argnames_list.clone())?;
121 let body = Rc::new(Value::List(list.cdr().cdr().cdr()));
122
123 let lambda = Value::Macro(Lambda {
124 closure: env.clone(),
125 argnames,
126 body,
127 });
128
129 env.borrow_mut().define(symbol.clone(), lambda);
130
131 Ok(Value::NIL)
132 }
133
134 Value::Symbol(Symbol(keyword)) if keyword == "defun" => {
135 let args = &list.cdr().into_iter().collect::<Vec<Value>>();
136
137 let symbol = require_typed_arg::<&Symbol>(keyword, args, 0)?;
138 let argnames_list = require_typed_arg::<&List>(keyword, args, 1)?;
139 let argnames = value_to_argnames(argnames_list.clone())?;
140 let body = Rc::new(Value::List(list.cdr().cdr().cdr()));
141
142 let lambda = Value::Lambda(Lambda {
143 closure: env.clone(),
144 argnames,
145 body,
146 });
147
148 env.borrow_mut().define(symbol.clone(), lambda);
149
150 Ok(Value::NIL)
151 }
152
153 Value::Symbol(Symbol(keyword)) if keyword == "lambda" => {
154 let args = &list.cdr().into_iter().collect::<Vec<Value>>();
155
156 let argnames_list = require_typed_arg::<&List>(keyword, args, 0)?;
157 let argnames = value_to_argnames(argnames_list.clone())?;
158 let body = Rc::new(Value::List(list.cdr().cdr()));
159
160 Ok(Value::Lambda(Lambda {
161 closure: env,
162 argnames,
163 body,
164 }))
165 }
166
167 Value::Symbol(Symbol(keyword)) if keyword == "let" => {
168 let let_env = Rc::new(RefCell::new(Env::extend(env)));
169
170 let args = &list.cdr().into_iter().collect::<Vec<Value>>();
171
172 let declarations = require_typed_arg::<&List>(keyword, args, 0)?;
173
174 for decl in declarations.into_iter() {
175 let decl = &decl;
176
177 let decl_cons: &List = decl.try_into().map_err(|_| RuntimeError {
178 msg: format!("Expected declaration clause, found {}", decl),
179 })?;
180 let symbol = &decl_cons.car()?;
181 let symbol: &Symbol = symbol.try_into().map_err(|_| RuntimeError {
182 msg: format!("Expected symbol for let declaration, found {}", symbol),
183 })?;
184 let expr = &decl_cons.cdr().car()?;
185
186 let result = eval_inner(let_env.clone(), expr, context.found_tail(true))?;
187 let_env.borrow_mut().define(symbol.clone(), result);
188 }
189
190 let body = &Value::List(list.cdr().cdr());
191 let body: &List = body.try_into().map_err(|_| RuntimeError {
192 msg: format!(
193 "Expected expression(s) after let-declarations, found {}",
194 body
195 ),
196 })?;
197
198 eval_block_inner(let_env, body.into_iter(), context)
199 }
200
201 Value::Symbol(Symbol(keyword)) if keyword == "begin" => {
202 eval_block_inner(env, list.cdr().into_iter(), context)
203 }
204
205 Value::Symbol(Symbol(keyword)) if keyword == "cond" => {
206 let clauses = list.cdr();
207
208 for clause in clauses.into_iter() {
209 let clause = &clause;
210
211 let clause: &List = clause.try_into().map_err(|_| RuntimeError {
212 msg: format!("Expected conditional clause, found {}", clause),
213 })?;
214
215 let condition = &clause.car()?;
216 let then = &clause.cdr().car()?;
217
218 if eval_inner(env.clone(), condition, context.found_tail(true))?.into() {
219 return eval_inner(env, then, context);
220 }
221 }
222
223 Ok(Value::NIL)
224 }
225
226 Value::Symbol(Symbol(keyword)) if keyword == "if" => {
227 let args = &list.cdr().into_iter().collect::<Vec<Value>>();
228
229 let condition = require_arg(keyword, args, 0)?;
230 let then_expr = require_arg(keyword, args, 1)?;
231 let else_expr = require_arg(keyword, args, 2).ok();
232
233 if eval_inner(env.clone(), condition, context.found_tail(true))?.into() {
234 eval_inner(env, then_expr, context)
235 } else {
236 else_expr
237 .map(|expr| eval_inner(env, &expr, context))
238 .unwrap_or(Ok(Value::NIL))
239 }
240 }
241
242 Value::Symbol(Symbol(keyword)) if keyword == "and" || keyword == "or" => {
243 let args = &list.cdr().into_iter().collect::<Vec<Value>>();
244 let is_or = keyword.as_str() == "or";
245
246 let mut last_result: Option<Value> = None;
247 for arg in args {
248 let result = eval_inner(env.clone(), arg, context.found_tail(true))?;
249 let truthy: bool = (&result).into();
250
251 if is_or == truthy {
252 return Ok(result);
253 }
254
255 last_result = Some(result);
256 }
257
258 Ok(if let Some(last_result) = last_result {
259 last_result
260 } else {
261 (!is_or).into()
263 })
264 }
265
266 _ => {
268 let mut func_or_macro =
269 eval_inner(env.clone(), &list.car()?, context.found_tail(true))?;
270
271 if matches!(func_or_macro, Value::Macro(_)) {
272 let args = list.into_iter().skip(1).collect::<Vec<Value>>();
273
274 let expanded =
275 call_function_or_macro(env.clone(), &mut func_or_macro, args)?;
276
277 eval_inner(env.clone(), &expanded, Context::new())
278 } else {
279 let args = list
280 .into_iter()
281 .skip(1)
282 .map(|car| eval_inner(env.clone(), &car, context.found_tail(true)))
283 .collect::<Result<Vec<Value>, RuntimeError>>()?;
284
285 if !context.found_tail && context.in_func {
286 Ok(Value::TailCall {
287 func: Rc::new(func_or_macro),
288 args,
289 })
290 } else {
291 let mut res =
292 call_function_or_macro(env.clone(), &mut func_or_macro, args);
293
294 while let Ok(Value::TailCall { func, args }) = res {
295 res = call_function_or_macro(env.clone(), func.as_ref(), args);
296 }
297
298 res
299 }
300 }
301 }
302 }
303 }
304
305 _ => Ok(expression.clone()),
307 }
308}
309fn value_to_argnames(argnames: List) -> Result<Vec<Symbol>, RuntimeError> {
312 argnames
313 .into_iter()
314 .enumerate()
315 .map(|(index, arg)| match arg {
316 Value::Symbol(s) => Ok(s),
317 _ => Err(RuntimeError {
318 msg: format!(
319 "Expected list of arg names, but arg {} is a {}",
320 index,
321 arg.type_name()
322 ),
323 }),
324 })
325 .collect()
326}
327
328fn call_function_or_macro(
332 env: Rc<RefCell<Env>>,
333 func: &Value,
334 args: Vec<Value>,
335) -> Result<Value, RuntimeError> {
336 if let Value::NativeFunc(func) = func {
337 func(env, args)
338 } else if let Value::NativeClosure(closure) = func {
339 closure.borrow_mut()(env, args)
340 } else {
341 let lambda = match func {
342 Value::Lambda(lamb) => Some(lamb),
343 Value::Macro(lamb) => Some(lamb),
344 _ => None,
345 };
346
347 if let Some(lambda) = lambda {
348 let mut arg_env = Env::extend(lambda.closure.clone());
350 for (index, arg_name) in lambda.argnames.iter().enumerate() {
351 if arg_name.0 == "..." {
352 arg_env.define(
354 Symbol::from("..."),
355 Value::List(args.into_iter().skip(index).collect()),
356 );
357 break;
358 } else {
359 arg_env.define(arg_name.clone(), args[index].clone());
360 }
361 }
362
363 let clauses: &List = lambda.body.as_ref().try_into()?;
365 eval_block_inner(
366 Rc::new(RefCell::new(arg_env)),
367 clauses.into_iter(),
368 Context {
369 found_tail: false,
370 in_func: true,
371 quoting: false,
372 },
373 )
374 } else {
375 Err(RuntimeError {
376 msg: format!("{} is not callable", func),
377 })
378 }
379 }
380}
381
382#[derive(Debug, Clone, Copy)]
383struct Context {
384 pub found_tail: bool,
385 pub in_func: bool,
386 pub quoting: bool,
387}
388
389impl Context {
390 pub fn new() -> Self {
391 Self {
392 found_tail: false,
393 in_func: false,
394 quoting: false,
395 }
396 }
397
398 pub fn found_tail(self, found_tail: bool) -> Self {
399 Self {
400 found_tail,
401 in_func: self.in_func,
402 quoting: self.quoting,
403 }
404 }
405
406 pub fn quoting(self, quoting: bool) -> Self {
415 Self {
416 found_tail: self.found_tail,
417 in_func: self.in_func,
418 quoting,
419 }
420 }
421}