sim_lib_control/
conditional.rs1use sim_kernel::{
12 Args, Callable, ClassRef, Cx, Error, Object, ObjectCompat, RawArgs, Result, Symbol, Value,
13};
14
15#[derive(Clone, Copy)]
21pub struct IfForm;
22
23impl IfForm {
24 pub fn symbol() -> Symbol {
26 Symbol::new("if")
27 }
28
29 fn arity_error(count: usize) -> Error {
32 Error::Eval(format!(
33 "if expects (if test then) or (if test then else), got {count} argument(s)"
34 ))
35 }
36}
37
38impl Object for IfForm {
39 fn display(&self, _cx: &mut Cx) -> Result<String> {
40 Ok("#<special-form if>".to_owned())
41 }
42
43 fn as_any(&self) -> &dyn std::any::Any {
44 self
45 }
46}
47
48impl ObjectCompat for IfForm {
49 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
50 cx.resolve_class(&Symbol::qualified("core", "Function"))
51 }
52
53 fn as_callable(&self) -> Option<&dyn Callable> {
54 Some(self)
55 }
56}
57
58impl Callable for IfForm {
59 fn call(&self, cx: &mut Cx, args: Args) -> Result<Value> {
64 let values = args.into_vec();
65 if values.len() < 2 || values.len() > 3 {
66 return Err(Self::arity_error(values.len()));
67 }
68 if values[0].object().truth(cx)? {
69 Ok(values[1].clone())
70 } else if let Some(alt) = values.get(2) {
71 Ok(alt.clone())
72 } else {
73 cx.factory().nil()
74 }
75 }
76
77 fn call_exprs(&self, cx: &mut Cx, args: RawArgs) -> Result<Value> {
78 let exprs = args.into_exprs();
79 if exprs.len() < 2 || exprs.len() > 3 {
80 return Err(Self::arity_error(exprs.len()));
81 }
82 let mut exprs = exprs.into_iter();
83 let test = exprs.next().expect("arity checked");
84 let then_branch = exprs.next().expect("arity checked");
85 let else_branch = exprs.next();
86
87 let taken = if cx.eval_expr(test)?.object().truth(cx)? {
88 then_branch
89 } else if let Some(else_branch) = else_branch {
90 else_branch
91 } else {
92 return cx.factory().nil();
93 };
94 cx.eval_expr(taken)
95 }
96}