1use crate::{
2 exp, exp_assert, parse, resolve_resource, CallSnapshot, Environment, Exception,
3 ExceptionValue as EV, Expression, Value,
4};
5use regex::Regex;
6use std::fmt;
7
8use crate::Locker;
9
10#[derive(Debug, Clone, PartialEq, PartialOrd)]
11pub enum Operator {
12 Quote,
13 Atom,
14 Eq,
15 Car,
16 Cdr,
17 Cons,
18 Cond,
19 Export,
20 Let,
21 Sum,
22 Prod,
23 Exp,
24 Modulo,
25 Gt,
26 Ge,
27 Type,
28 Disp,
29 Import,
30 Eval,
31 While,
32 Lambda,
33 Macro,
34 List,
35 Catch,
36 Throw,
37 Format,
38 Parse,
39 Length,
40 Append,
41 Do,
42 Floor,
43 Rand,
44 Equiv,
45}
46
47impl fmt::Display for Operator {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 write!(f, "{}", format!("{:?}", self).to_lowercase().as_str())
50 }
51}
52
53impl Operator {
54 pub fn apply(
55 &self,
56 snapshot: Locker<CallSnapshot>,
57 arguments: Vec<&Expression>,
58 expr: &Expression,
59 env: Locker<Environment>,
60 ) -> Result<Expression, Exception> {
61 use crate::Operator::*;
62 use Value::*;
63
64 let snap = || snapshot.clone();
65
66 match self {
67 Quote => {
68 if arguments.len() != 1 {
69 exp!(
70 EV::ArgumentMismatch(arguments.len(), "1".to_string()),
71 snapshot
72 );
73 }
74 let arg = *arguments.get(0).unwrap();
75 Ok(arg.clone())
76 }
77 Atom => {
78 exp_assert!(
79 arguments.len() == 1,
80 EV::ArgumentMismatch(arguments.len(), "1".to_string()),
81 snapshot
82 );
83 match arguments.get(0).unwrap().eval(snapshot, env)?.into_value() {
84 Value::List(_) => Ok(Expression::new(Value::List(vec![]))),
85 _ => Ok(Expression::new(Value::True)),
86 }
87 }
88 Eq => {
89 exp_assert!(
90 arguments.len() > 1,
91 EV::ArgumentMismatch(arguments.len(), "2+".to_string()),
92 snap()
93 );
94
95 let mut prev: Option<Expression> = None;
96 for argument in arguments {
97 let evaled = argument.eval(snap(), env.clone())?;
98 match &prev {
99 None => prev = Some(evaled),
100 Some(val) => match (evaled.get_value(), val.get_value()) {
101 (Value::List(l1), Value::List(l2)) => {
102 if !(l1.is_empty() && l2.is_empty()) {
103 return Ok(Expression::nil());
104 }
105 }
106 (v1, v2) => {
107 if v1 != v2 {
108 return Ok(Expression::nil());
109 }
110 }
111 },
112 }
113 }
114 Ok(Expression::t())
115 }
116 Car => {
117 exp_assert!(
118 arguments.len() == 1,
119 EV::ArgumentMismatch(arguments.len(), "1".to_string()),
120 snap()
121 );
122
123 let list = arguments.get(0).unwrap().eval(snap(), env)?;
124
125 match list.into_value() {
126 Value::List(mut vals) => {
127 exp_assert!(
128 !vals.is_empty(),
129 EV::InvalidArgument,
130 snap(),
131 "cannot `car` an empty list (nil)".to_string()
132 );
133 Ok(vals.remove(0))
134 }
135 val => exp!(
136 EV::InvalidArgument,
137 snap(),
138 format!("`car` expects a list, got `{}`", val)
139 ),
140 }
141 }
142 Cdr => {
143 exp_assert!(
144 arguments.len() == 1,
145 EV::ArgumentMismatch(arguments.len(), "1".to_string()),
146 snap()
147 );
148 let list = arguments.get(0).unwrap().eval(snap(), env)?;
149 match list.into_value() {
150 Value::List(mut vals) => {
151 if !vals.is_empty() {
152 vals.remove(0);
153 }
154 Ok(Expression::new(Value::List(vals)))
155 }
156 val => exp!(
157 EV::InvalidArgument,
158 snap(),
159 format!("`cdr` expects a list, not `{}`", val)
160 ),
161 }
162 }
163 Cons => {
164 exp_assert!(
165 arguments.len() == 2,
166 EV::ArgumentMismatch(arguments.len(), "2".to_string()),
167 snap()
168 );
169 let first = arguments.get(0).unwrap().eval(snap(), env.clone())?;
170 let list = arguments.get(1).unwrap().eval(snap(), env)?;
171 match list.into_value() {
172 Value::List(mut vals) => {
173 vals.insert(0, first);
174 Ok(Expression::new(Value::List(vals)))
175 }
176 val => exp!(
177 EV::InvalidArgument,
178 snap(),
179 format!(
180 "`cons` expects a list as its second argument, got `{}`",
181 val
182 )
183 ),
184 }
185 }
186 Cond => {
187 for argument in &arguments {
188 match argument.get_value() {
189 Value::List(elems) => {
190 exp_assert!(
191 elems.len() == 2,
192 EV::InvalidArgument,
193 snap(),
194 format!(
195 "each `cond` condition must be a list of length two (the given list has {} elements)",
196 elems.len()
197 )
198 );
199 let cond = { elems.get(0).unwrap() };
200 if cond.eval(snap(), env.clone())? != Expression::nil() {
201 let val = { elems.get(1).unwrap() };
202 return val.eval(snapshot, env);
203 }
204 }
205 val => exp!(
206 EV::InvalidArgument,
207 snap(),
208 format!("`cond` must be called on a list, got `{}`", val)
209 ),
210 }
211 }
212 Ok(Expression::nil())
213 }
214 Export | Let => {
215 exp_assert!(
216 arguments.len() == 2,
217 EV::ArgumentMismatch(arguments.len(), "2".to_string()),
218 snap()
219 );
220 let sym_exp = arguments.get(0).unwrap().eval(snap(), env.clone())?;
221 let symbol = match sym_exp.into_value() {
222 Symbol(sym) => sym,
223 other => exp!(
224 EV::InvalidArgument,
225 snap(),
226 format!(
227 "first arg of label must evaluate to a symbol (received `{}`)",
228 other
229 )
230 ),
231 };
232
233 let assigned_expr = arguments.get(1).unwrap().eval(snap(), env.clone())?;
234 env.write().unwrap().assign(
235 symbol,
236 assigned_expr.clone(),
237 !matches!(self, Export),
238 snap(),
239 )?;
240 Ok(assigned_expr)
241 }
242 Sum => {
243 let mut sum = 0.0;
244 for arg in arguments {
245 match arg.eval(snap(), env.clone())?.into_value() {
246 Number(val) => sum += val,
247 val => exp!(
248 EV::InvalidArgument,
249 snap(),
250 format!("`sum` expects numbers as its arguments (got `{}`)", val)
251 ),
252 }
253 }
254 Ok(Expression::new(Value::Number(sum)))
255 }
256 Prod => {
257 let mut prod = 1.0;
258 for arg in arguments {
259 match arg.eval(snap(), env.clone())?.into_value() {
260 Number(val) => prod *= val,
261 val => exp!(
262 EV::InvalidArgument,
263 snap(),
264 format!("`prod` expects numbers as its arguments (got `{}`)", val)
265 ),
266 }
267 }
268 Ok(Expression::new(Value::Number(prod)))
269 }
270 Exp => {
271 exp_assert!(
272 arguments.len() == 2,
273 EV::ArgumentMismatch(arguments.len(), "2".to_string()),
274 snap()
275 );
276 let base = arguments
277 .get(0)
278 .unwrap()
279 .eval(snap(), env.clone())?
280 .into_value();
281 let exp = arguments.get(1).unwrap().eval(snap(), env)?.into_value();
282 match (base, exp) {
283 (Number(base), Number(exp)) => {
284 Ok(Expression::new(Value::Number(base.powf(exp))))
285 }
286 (base, exp) => exp!(
287 EV::InvalidArgument,
288 snap(),
289 format!(
290 "`exp` requires its arguments to be both numeric (got `{}` and `{}`)",
291 base, exp
292 )
293 ),
294 }
295 }
296 Modulo => {
297 exp_assert!(
298 arguments.len() == 2,
299 EV::ArgumentMismatch(arguments.len(), "2".to_string()),
300 snap()
301 );
302 let val = arguments
303 .get(0)
304 .unwrap()
305 .eval(snap(), env.clone())?
306 .into_value();
307 let modu = arguments.get(1).unwrap().eval(snap(), env)?.into_value();
308 match (val, modu) {
309 (Number(first), Number(second)) => {
310 Ok(Expression::new(Value::Number(first % second)))
311 }
312 (base, exp) => exp!(
313 EV::InvalidArgument,
314 snap(),
315 format!(
316 "`modulo` requires its arguments to be both numeric (got `{}` and `{}`)",
317 base, exp)
318 ),
319 }
320 }
321 Gt => {
322 let mut args_evaled = Vec::with_capacity(arguments.len());
323 for arg in arguments {
324 args_evaled.push(arg.eval(snap(), env.clone())?);
325 }
326 match args_evaled
327 .iter()
328 .skip(1)
329 .zip(args_evaled.iter())
330 .all(|(g, l)| g > l)
331 {
332 true => Ok(Expression::t()),
333 false => Ok(Expression::nil()),
334 }
335 }
336 Ge => {
337 let mut args_evaled = Vec::with_capacity(arguments.len());
338 for arg in arguments {
339 args_evaled.push(arg.eval(snap(), env.clone())?);
340 }
341 match args_evaled
342 .iter()
343 .skip(1)
344 .zip(args_evaled.iter())
345 .all(|(g, l)| g >= l)
346 {
347 true => Ok(Expression::t()),
348 false => Ok(Expression::nil()),
349 }
350 }
351 Type => {
352 exp_assert!(
353 arguments.len() == 1,
354 EV::ArgumentMismatch(arguments.len(), "1".to_string()),
355 snap()
356 );
357 let arg_type = arguments
358 .get(0)
359 .unwrap()
360 .eval(snap(), env)?
361 .into_value()
362 .as_type();
363 Ok(Expression::new(arg_type))
364 }
365 Disp => {
366 for arg in arguments {
367 println!("{}", arg.eval(snap(), env.clone())?);
368 }
369 Ok(Expression::nil())
370 }
371 Import => {
372 if !(arguments.len() == 1 || arguments.len() == 2) {
373 exp!(
374 EV::ArgumentMismatch(arguments.len(), "1 or 2".to_string()),
375 snapshot
376 );
377 }
378 let path = match arguments.get(0).unwrap().eval(snap(), env.clone())?.into_value() {
379 Text(val) => val,
380 val => exp!(
381 EV::InvalidArgument,
382 snapshot,
383 format!(
384 "`import` requires the path (:text) as its first argument (got `{}` instead)",
385 val
386 )
387 ),
388 };
389
390 let namespace = match arguments.get(1) {
391 Some(val) => match val.eval(snap(), env.clone())?.into_value() {
392 Keyword(val) => Some(val.string_value().clone()),
393 val => exp!(
394 EV::InvalidArgument,
395 snapshot,
396 format!(
397 "`import` requires the namespace (:keyword) as its second argument (got `{}` instead)",
398 val
399 )
400 ),
401 },
402 None => None
403 };
404
405 let imported_env = Locker::new(Environment::root());
406 let exp = resolve_resource(&path, snapshot, expr, imported_env.clone())?;
407 env.write().unwrap().add_parent(imported_env, namespace);
408 Ok(exp)
409 }
410 Eval => {
411 if arguments.len() != 1 {
412 exp!(
413 EV::ArgumentMismatch(arguments.len(), "1".to_string()),
414 snapshot
415 );
416 }
417 arguments
418 .get(0)
419 .unwrap()
420 .eval(snap(), env.clone())?
421 .eval(snap(), env)
422 }
423 While => {
424 exp_assert!(
425 arguments.len() >= 2,
426 EV::ArgumentMismatch(arguments.len(), "2+".to_string()),
427 snapshot
428 );
429 let condition = arguments.get(0).unwrap();
430 let mut result = Expression::nil();
431 while condition.eval(snap(), env.clone())? != Expression::nil() {
432 for action in arguments.iter().skip(1) {
433 result = action.eval(snap(), env.clone())?
434 }
435 }
436 Ok(result)
437 }
438 crate::Operator::Lambda | crate::Operator::Macro => {
439 exp_assert!(
440 arguments.len() >= 2,
441 EV::ArgumentMismatch(arguments.len(), "2+".to_string()),
442 snapshot
443 );
444
445 let mut collapse_input = true;
446 let func_args = match arguments
447 .get(0)
448 .unwrap()
449 .eval(snap(), env.clone())?
450 .into_value()
451 {
452 Value::List(vals) => {
453 collapse_input = false;
454 let mut symbols = Vec::new();
455 for val in vals {
456 match val.into_value() {
457 Value::Symbol(sym) => symbols.push(sym),
458 other => exp!(EV::InvalidArgument, snapshot, format!("each item in the first argument (a list) must be a symbol (got `{}`)", other)),
459 }
460 }
461 symbols
462 }
463 Value::Symbol(sym) => vec![sym],
464 val => exp!(
465 EV::InvalidArgument,
466 snapshot,
467 format!(
468 "the first argument must only evaluate to symbol(s) (got `{}`)",
469 val
470 )
471 ),
472 };
473 let mut func_expressions = Vec::new();
474 for arg_expr in arguments.iter().skip(1) {
475 func_expressions.push(arg_expr.eval(snap(), env.clone())?);
476 }
477
478 (match self {
479 crate::Operator::Lambda => {
480 Expression::new(Value::Lambda(crate::Function::new(
481 func_args,
482 func_expressions,
483 collapse_input,
484 env.clone(),
485 )))
486 }
487 crate::Operator::Macro => Expression::new(Value::Macro(crate::Function::new(
488 func_args,
489 func_expressions,
490 collapse_input,
491 env.clone(),
492 ))),
493 _ => unreachable!(),
494 })
495 .eval(snap(), env)
496 }
497 crate::Operator::List => {
498 let mut args_evaled = Vec::new();
499 for argument in arguments {
500 args_evaled.push(argument.eval(snap(), env.clone())?);
501 }
502 Ok(Expression::new(Value::List(args_evaled)))
503 }
504 Catch => {
505 exp_assert!(
506 arguments.len() == 2,
507 EV::ArgumentMismatch(arguments.len(), "2".to_string()),
508 snapshot
509 );
510 let action = arguments.get(0).unwrap().eval(snap(), env.clone());
511 let catch_func = arguments.get(1).unwrap().eval(snap(), env.clone())?;
512 match action {
513 Ok(exp) => Ok(exp),
514 Err(err) => {
515 match catch_func.get_value() {
517 Value::Lambda{..} => Expression::new(Value::List(vec![catch_func.clone(), err.into_value().into_expression()])).eval(snapshot, Locker::new(Environment::root().with_parent(env, None))),
518 _ => exp!(
519 EV::InvalidArgument,
520 snapshot,
521 format!("the second argument of `catch` must be a lambda expression (got `{}`)", catch_func)
522 )
523 }
524 }
525 }
526 }
527 Throw => {
528 exp_assert!(
529 arguments.len() == 1,
530 EV::ArgumentMismatch(arguments.len(), "1".to_string()),
531 snapshot
532 );
533 Err(Exception::new(
534 EV::Other(arguments.get(0).unwrap().eval(snap(), env)?),
535 Some(snap()),
536 None,
537 ))
538 }
539 Format => {
540 exp_assert!(
541 !arguments.is_empty(),
542 EV::ArgumentMismatch(arguments.len(), "1+".to_string()),
543 snapshot
544 );
545 let mut literal = match arguments
546 .get(0)
547 .unwrap()
548 .eval(snap(), env.clone())?
549 .into_value()
550 {
551 Text(value) => value,
552 other => return Ok(Expression::new(Value::Text(format!("{}", other)))),
553 };
554 let placeholder = Regex::new(r"\{\}").unwrap(); let interpolations: Vec<regex::Match> = placeholder.find_iter(&literal).collect();
556 exp_assert!(
557 arguments.len() == interpolations.len() + 1,
558 EV::ArgumentMismatch(arguments.len(), format!("{}", interpolations.len() + 1)),
559 snapshot,
560 format!("`{}` has {} placeholders, so {} total arguments are necessary (including the first string literal)", literal, interpolations.len(), interpolations.len() + 1)
561 );
562 for i in 1..arguments.len() {
563 let replace_with =
564 format!("{}", arguments.get(i).unwrap().eval(snap(), env.clone())?);
565 literal = String::from(placeholder.replace(&literal, replace_with.as_str()));
566 }
567 Ok(Expression::new(Value::Text(literal)))
568 }
569 Parse => {
570 exp_assert!(
571 arguments.len() == 1,
572 EV::ArgumentMismatch(arguments.len(), "1".to_string()),
573 snapshot
574 );
575 let value_str = match arguments.get(0).unwrap().eval(snap(), env)?.into_value() {
576 Text(value) => value,
577 other => exp!(
578 EV::InvalidArgument,
579 snapshot,
580 format!("the argument of `parse` must be text (got `{}`)", other)
581 ),
582 };
583 let mut values = parse(&value_str, "<parse>")?;
584 exp_assert!(
585 values.len() == 1,
586 EV::InvalidArgument,
587 snapshot,
588 format!(
589 "`parse` can only handle a single value, not {}",
590 values.len()
591 )
592 );
593 Ok(values.remove(0))
594 }
595 Length => {
596 exp_assert!(
597 arguments.len() == 1,
598 EV::ArgumentMismatch(arguments.len(), "1".to_string()),
599 snapshot
600 );
601 match arguments.get(0).unwrap().eval(snap(), env)?.into_value() {
602 Value::List(vals) => Ok(Expression::new(Value::Number(vals.len() as f64))),
603 other => exp!(
604 EV::InvalidArgument,
605 snapshot,
606 format!(
607 "length expects a list as its first argument (got `{}`)",
608 other
609 )
610 ),
611 }
612 }
613 Append => {
614 exp_assert!(
615 !arguments.is_empty(),
616 EV::ArgumentMismatch(arguments.len(), "1+".to_string()),
617 snapshot
618 );
619 let mut new_list: Vec<Expression> = Vec::with_capacity(arguments.len());
620 for argument in arguments {
621 match argument.eval(snap(), env.clone())?.into_value() {
622 Value::List(values) => new_list.extend(values),
623 other => exp!(
624 EV::InvalidArgument,
625 snapshot,
626 format!(
627 "append requires all its arguments to be a list (got `{}`)",
628 other
629 )
630 ),
631 }
632 }
633 Ok(Expression::new(Value::List(new_list)))
634 }
635 Do => {
636 exp_assert!(
637 !arguments.is_empty(),
638 EV::ArgumentMismatch(arguments.len(), "1+".to_string()),
639 snapshot
640 );
641
642 let mut result = Expression::nil();
643 for argument in arguments {
644 result = argument.eval(snap(), env.clone())?;
645 }
646 Ok(result)
647 }
648 Floor => {
649 exp_assert!(
650 arguments.len() == 1,
651 EV::ArgumentMismatch(arguments.len(), "1".to_string()),
652 snapshot
653 );
654 match arguments
655 .get(0)
656 .unwrap()
657 .eval(snap(), env.clone())?
658 .into_value()
659 {
660 Number(val) => Ok(Expression::new(Value::Number(val.floor()))),
661 val => exp!(
662 EV::InvalidArgument,
663 snap(),
664 format!("`floor` expects a number as its argument (got `{}`)", val)
665 ),
666 }
667 }
668 Rand => {
669 exp_assert!(
670 arguments.len() == 0,
671 EV::ArgumentMismatch(arguments.len(), "0".to_string()),
672 snapshot
673 );
674 Ok(Expression::new(Value::Number(rand::random())))
675 }
676 Equiv => {
677 exp_assert!(
678 arguments.len() >= 2,
679 EV::ArgumentMismatch(arguments.len(), "2+".to_string()),
680 snapshot
681 );
682 let equals = arguments.get(0).unwrap().eval(snap(), env.clone())?;
683 for i in arguments.iter().skip(1) {
684 if i.eval(snap(), env.clone())? != equals {
685 return Ok(Expression::nil());
686 }
687 }
688 return Ok(Expression::t());
689 }
690 }
691 }
692}