Skip to main content

riddle/
language.rs

1use crate::{
2    RiddleError,
3    env::{BoolExpr, CommonEnv, Env, Slot, Var, get_var_by_path},
4    scope::{Scope, Type, get_type_by_path, is_assignable_from},
5};
6use std::{
7    collections::{HashMap, VecDeque},
8    fmt,
9    rc::Rc,
10};
11
12pub struct ProblemDef {
13    pub functions: Vec<FunctionDef>,
14    pub predicates: Vec<PredicateDef>,
15    pub classes: Vec<ClassDef>,
16    pub statements: Vec<Statement>,
17}
18
19pub type FieldDef = (Vec<String>, Vec<(String, Option<Expr>)>); // (type, [(name, optional initializer)])
20
21pub struct ClassDef {
22    pub name: String,
23    pub parents: Vec<Vec<String>>,
24    pub fields: Vec<FieldDef>,
25    pub constructors: Vec<ConstructorDef>,
26    pub functions: Vec<FunctionDef>,
27    pub predicates: Vec<PredicateDef>,
28    pub classes: Vec<ClassDef>,
29}
30
31pub struct ConstructorDef {
32    pub args: Vec<(Vec<String>, String)>,
33    pub init: Vec<(Vec<String>, Vec<Expr>)>,
34    pub statements: Vec<Statement>,
35}
36
37pub struct FunctionDef {
38    pub return_type: Option<Vec<String>>,
39    pub name: String,
40    pub args: Vec<(Vec<String>, String)>,
41    pub statements: Vec<Statement>,
42}
43
44pub struct PredicateDef {
45    pub name: String,
46    pub args: Vec<(Vec<String>, String)>,
47    pub parents: Vec<Vec<String>>,
48    pub statements: Vec<Statement>,
49}
50
51#[derive(Debug, PartialEq, Clone)]
52pub enum Statement {
53    Expr(Expr),
54    LocalField { field_type: Vec<String>, fields: Vec<(String, Option<Expr>)> },
55    Assign { name: Vec<String>, value: Expr },
56    ForAll { var_type: Vec<String>, var_name: String, statements: Vec<Statement> },
57    Disjunction { disjuncts: Vec<(Vec<Statement>, Expr)> },
58    Formula { is_fact: bool, name: String, tau: Vec<String>, predicate_name: String, args: Vec<(String, Expr)> },
59    Return { value: Expr },
60}
61
62impl fmt::Display for Statement {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        match self {
65            Statement::Expr(e) => write!(f, "{};", e),
66            Statement::LocalField { field_type, fields } => write!(f, "{} {};", field_type.join("."), fields.iter().map(|(n, v)| format!("{}{}", n, v.as_ref().map(|v| format!(" = {}", v)).unwrap_or_default())).collect::<Vec<_>>().join(", ")),
67            Statement::Assign { name, value } => write!(f, "{} = {};", name.join("."), value),
68            Statement::ForAll { var_type, var_name, statements } => write!(f, "for {} {} {{\n{}\n}}", var_type.join("."), var_name, statements.iter().map(|s| format!("    {}", s)).collect::<Vec<_>>().join("\n")),
69            Statement::Disjunction { disjuncts } => write!(f, "{{\n{}\n}}", disjuncts.iter().map(|(s, e)| format!("    {{\n{}\n    }}: {}", s.iter().map(|s| format!("        {}", s)).collect::<Vec<_>>().join("\n"), e)).collect::<Vec<_>>().join(" or ")),
70            Statement::Formula { is_fact, name, tau, predicate_name, args } => write!(f, "{} {} = new {}{}({});", if *is_fact { "fact" } else { "formula" }, name, if tau.is_empty() { String::new() } else { tau.join(".") + "." }, predicate_name, args.iter().map(|(n, e)| format!("{}: {}", n, e)).collect::<Vec<_>>().join(", ")),
71            Statement::Return { value } => write!(f, "return {};", value),
72        }
73    }
74}
75
76#[derive(Debug, PartialEq, Clone)]
77pub enum Expr {
78    Bool(bool),
79    Int(String),
80    Real(String, String),
81    String(String),
82    QualifiedId { ids: Vec<String> },
83    Sum { terms: Vec<Expr> },
84    Opposite { term: Box<Expr> },
85    Not { term: Box<Expr> },
86    Mul { factors: Vec<Expr> },
87    Div { left: Box<Expr>, right: Box<Expr> },
88    Function { name: Vec<String>, args: Vec<Expr> },
89    Eq { left: Box<Expr>, right: Box<Expr> },
90    Neq { left: Box<Expr>, right: Box<Expr> },
91    Lt { left: Box<Expr>, right: Box<Expr> },
92    Leq { left: Box<Expr>, right: Box<Expr> },
93    Gt { left: Box<Expr>, right: Box<Expr> },
94    Geq { left: Box<Expr>, right: Box<Expr> },
95    Or { terms: Vec<Expr> },
96    And { terms: Vec<Expr> },
97    NewObject { class_name: Vec<String>, args: Vec<Expr> },
98}
99
100impl fmt::Display for Expr {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        match self {
103            Expr::Bool(b) => write!(f, "{}", b),
104            Expr::Int(i) => write!(f, "{}", i),
105            Expr::Real(num, den) => {
106                if den == "1" {
107                    write!(f, "{}", num)
108                } else {
109                    write!(f, "{}/{}", num, den)
110                }
111            }
112            Expr::String(s) => write!(f, "\"{}\"", s),
113            Expr::QualifiedId { ids } => write!(f, "{}", ids.join(".")),
114            Expr::Sum { terms } => write!(f, "({})", terms.iter().map(|t| format!("{}", t)).collect::<Vec<_>>().join(" + ")),
115            Expr::Opposite { term } => write!(f, "-({})", term),
116            Expr::Not { term } => write!(f, "!({})", term),
117            Expr::Mul { factors } => write!(f, "({})", factors.iter().map(|t| format!("{}", t)).collect::<Vec<_>>().join(" * ")),
118            Expr::Div { left, right } => write!(f, "({} / {})", left, right),
119            Expr::Function { name, args } => write!(f, "{}({})", name.join("."), args.iter().map(|a| format!("{}", a)).collect::<Vec<_>>().join(", ")),
120            Expr::Eq { left, right } => write!(f, "({} == {})", left, right),
121            Expr::Neq { left, right } => write!(f, "({} != {})", left, right),
122            Expr::Lt { left, right } => write!(f, "({} < {})", left, right),
123            Expr::Leq { left, right } => write!(f, "({} <= {})", left, right),
124            Expr::Gt { left, right } => write!(f, "({} > {})", left, right),
125            Expr::Geq { left, right } => write!(f, "({} >= {})", left, right),
126            Expr::Or { terms } => write!(f, "({})", terms.iter().map(|t| format!("{}", t)).collect::<Vec<_>>().join(" || ")),
127            Expr::And { terms } => write!(f, "({})", terms.iter().map(|t| format!("{}", t)).collect::<Vec<_>>().join(" && ")),
128            Expr::NewObject { class_name, args } => write!(f, "new {}({})", class_name.join("."), args.iter().map(|a| format!("{}", a)).collect::<Vec<_>>().join(", ")),
129        }
130    }
131}
132
133pub struct Disjunction {
134    pub scp: Rc<dyn Scope>,
135    pub env: Rc<dyn Env>,
136    pub disjuncts: Vec<(Vec<Statement>, Expr)>,
137}
138
139pub fn execute(scp: &Rc<dyn Scope>, env: Rc<dyn Env>, stmt: &Statement) -> Result<(), RiddleError> {
140    match stmt {
141        Statement::Expr(expr) => {
142            let expr = evaluate(scp.as_ref(), env, expr)?;
143            if let Slot::Primitive(var) = expr.clone()
144                && let Ok(bool_expr) = var.as_any().downcast::<BoolExpr>()
145            {
146                scp.core().assert(bool_expr);
147                Ok(())
148            } else {
149                Err(RiddleError::RuntimeError(format!("Expected boolean expression, got {}", expr)))
150            }
151        }
152        Statement::LocalField { field_type, fields } => {
153            let fld_tp = get_type_by_path(scp.as_ref(), field_type)?;
154            for (name, default) in fields {
155                if let Some(expr) = default {
156                    let value = evaluate(scp.as_ref(), env.clone(), expr)?;
157                    match &value {
158                        Slot::Primitive(var) => {
159                            if !is_assignable_from(&fld_tp, &var.var_type()) {
160                                return Err(RiddleError::TypeError(format!("Default value for field '{}' is not assignable to field type '{}'", name, field_type.join("."))));
161                            }
162                        }
163                        Slot::ObjectRef(obj_id) => {
164                            let obj = scp.core().get_object(*obj_id).ok_or_else(|| RiddleError::NotFound(format!("Object {} not found", *obj_id)))?;
165                            let obj_type: Rc<dyn Type> = obj.class();
166                            if !is_assignable_from(&fld_tp, &obj_type) {
167                                return Err(RiddleError::TypeError(format!("Default value for field '{}' is not assignable to field type '{}'", name, field_type.join("."))));
168                            }
169                        }
170                        Slot::AtomRef(atom_id) => {
171                            let atom = scp.core().get_atom(*atom_id).ok_or_else(|| RiddleError::NotFound(format!("Atom {} not found", *atom_id)))?;
172                            let atom_type: Rc<dyn Type> = atom.predicate();
173                            if !is_assignable_from(&fld_tp, &atom_type) {
174                                return Err(RiddleError::TypeError(format!("Default value for field '{}' is not assignable to field type '{}'", name, field_type.join("."))));
175                            }
176                        }
177                    }
178                    env.set(name.clone(), value);
179                } else if let Some(class) = fld_tp.clone().as_class() {
180                    let instances = class.instances();
181                    if instances.is_empty() {
182                        return Err(RiddleError::RuntimeError(format!("No instances found for field '{}' of type '{}'", name, class.full_name())));
183                    } else if instances.len() == 1 {
184                        env.set(name.clone(), Slot::ObjectRef(instances[0]));
185                    } else {
186                        env.set(name.clone(), scp.core().new_var(class, instances.as_slice())?);
187                    }
188                } else {
189                    env.set(name.clone(), fld_tp.clone().new_instance());
190                }
191            }
192            Ok(())
193        }
194        Statement::Assign { name, value } => {
195            let value = evaluate(scp.as_ref(), env.clone(), value)?;
196            if name.len() == 1 {
197                env.set(name[0].clone(), value);
198                Ok(())
199            } else {
200                let (last, rest) = name.split_last().ok_or_else(|| RiddleError::RuntimeError("Empty assignment path".into()))?;
201                let var = get_var_by_path(scp.core().as_ref(), env.as_ref(), rest)?;
202                match &var {
203                    Slot::Primitive(_) => Err(RiddleError::NotAnEnvironment(format!("Variable '{}' in assignment path is a primitive variable, cannot assign to '{}'", rest.join("."), last))),
204                    Slot::ObjectRef(obj_id) => {
205                        let obj = scp.core().get_object(*obj_id).ok_or_else(|| RiddleError::NotFound(format!("Object {} not found", *obj_id)))?;
206                        obj.as_env().ok_or_else(|| RiddleError::NotAnEnvironment(format!("Object {} does not have an environment", *obj_id)))?.set(last.to_string(), value);
207                        Ok(())
208                    }
209                    Slot::AtomRef(atom_id) => {
210                        let atom = scp.core().get_atom(*atom_id).ok_or_else(|| RiddleError::NotFound(format!("Atom {} not found", *atom_id)))?;
211                        atom.as_env().ok_or_else(|| RiddleError::NotAnEnvironment(format!("Atom {} does not have an environment", *atom_id)))?.set(last.to_string(), value);
212                        Ok(())
213                    }
214                }
215            }
216        }
217        Statement::ForAll { var_type, var_name, statements } => {
218            let class = get_type_by_path(scp.as_ref(), var_type)?.as_class().ok_or_else(|| RiddleError::NotAClass(var_type.join(".")))?;
219            for instance in class.instances() {
220                let loop_env = Rc::new(CommonEnv::new(Some(env.clone())));
221                loop_env.set(var_name.clone(), Slot::ObjectRef(instance));
222                for stmt in statements {
223                    execute(scp, loop_env.clone(), stmt)?;
224                }
225            }
226            Ok(())
227        }
228        Statement::Disjunction { disjuncts } => {
229            let disjunction = Disjunction { scp: scp.clone(), env: env.clone(), disjuncts: disjuncts.clone() };
230            scp.core().new_disjunction(disjunction);
231            Ok(())
232        }
233        Statement::Formula { is_fact, name, tau, predicate_name, args } => {
234            let tau = if tau.is_empty() { None } else { Some(get_var_by_path(scp.core().as_ref(), env.as_ref(), tau)?) };
235            let predicate = if let Some(tau) = tau.as_ref() {
236                let tau = match tau {
237                    Slot::Primitive(var) => Err(RiddleError::NotAClass(format!("Tau variable is a primitive variable of type '{}', expected a class", var.var_type().full_name()))),
238                    Slot::ObjectRef(obj_id) => scp.core().get_object(*obj_id).ok_or_else(|| RiddleError::NotFound(format!("Object {} not found", *obj_id))),
239                    Slot::AtomRef(atom_id) => Err(RiddleError::NotAClass(format!("Tau variable is an atom {}, expected a class", *atom_id))),
240                }?;
241                tau.var_type().as_class().ok_or_else(|| RiddleError::NotAClass(format!("Type '{}' in tau path", tau.var_type().full_name())))?.get_predicate(predicate_name).ok_or_else(|| RiddleError::NotFound(format!("Predicate '{}' in class '{}'", predicate_name, tau.var_type().full_name())))?
242            } else {
243                scp.get_predicate(predicate_name).ok_or_else(|| RiddleError::NotFound(format!("Predicate '{}'", predicate_name)))?
244            };
245            let mut args: HashMap<String, Slot> = args
246                .iter()
247                .map(|(n, e)| {
248                    let val = evaluate(scp.as_ref(), env.clone(), e)?;
249                    Ok((n.clone(), val))
250                })
251                .collect::<Result<_, _>>()?;
252            if let Some(tau) = tau {
253                args.insert("tau".to_string(), tau);
254            } else if let Some(tau) = env.get("tau") {
255                args.insert("tau".to_string(), tau);
256            }
257            let mut pred_hierarchy = VecDeque::from(vec![predicate.clone()]);
258            while let Some(pred) = pred_hierarchy.pop_front() {
259                for (arg_type, name) in pred.args() {
260                    if !args.contains_key(name) {
261                        let arg_tp = get_type_by_path(scp.as_ref(), arg_type)?;
262                        if let Some(class) = arg_tp.clone().as_class() {
263                            let instances = class.instances();
264                            if instances.is_empty() {
265                                return Err(RiddleError::RuntimeError(format!("No instances found for argument '{}' of type '{}'", name, class.full_name())));
266                            } else if instances.len() == 1 {
267                                args.insert(name.clone(), Slot::ObjectRef(instances[0]));
268                            } else {
269                                args.insert(name.clone(), scp.core().new_var(class, instances.as_slice())?);
270                            }
271                        } else {
272                            args.insert(name.clone(), arg_tp.new_instance());
273                        }
274                    }
275                }
276                for parent_path in pred.parents() {
277                    let (predicate_name, class_path) = parent_path.split_last().ok_or_else(|| RiddleError::RuntimeError("Empty parent predicate path".into()))?;
278                    let parent_predicate = if class_path.is_empty() {
279                        scp.get_predicate(predicate_name).ok_or_else(|| RiddleError::NotFound(format!("Predicate '{}' in parent path", predicate_name)))?
280                    } else {
281                        let class = get_type_by_path(scp.as_ref(), class_path)?.as_class().ok_or_else(|| RiddleError::NotAClass(format!("Type '{}' in parent path", class_path.join("."))))?;
282                        class.get_predicate(predicate_name).ok_or_else(|| RiddleError::NotFound(format!("Predicate '{}' in class '{}'", predicate_name, class.full_name())))?
283                    };
284                    pred_hierarchy.push_back(parent_predicate);
285                }
286            }
287            let atom = scp.core().new_atom(predicate, *is_fact, args);
288            env.set(name.clone(), Slot::AtomRef(atom));
289            Ok(())
290        }
291        Statement::Return { value } => {
292            let ret = evaluate(scp.as_ref(), env.clone(), value)?;
293            env.set("__return".to_string(), ret);
294            Ok(())
295        }
296    }
297}
298
299pub fn evaluate(scp: &dyn Scope, env: Rc<dyn Env>, expr: &Expr) -> Result<Slot, RiddleError> {
300    match expr {
301        Expr::Bool(bool) => Ok(scp.core().new_bool(*bool)),
302        Expr::Int(int) => Ok(scp.core().new_int(int)),
303        Expr::Real(num, den) => Ok(scp.core().new_real(num, den)),
304        Expr::String(string) => Ok(scp.core().new_string(string)),
305        Expr::QualifiedId { ids } => get_var_by_path(scp.core().as_ref(), env.as_ref(), ids),
306        Expr::Sum { terms } => {
307            let evaluated_terms: Vec<Slot> = terms.iter().map(|t| evaluate(scp, env.clone(), t)).collect::<Result<_, _>>()?;
308            Ok(scp.core().sum(&evaluated_terms)?)
309        }
310        Expr::Opposite { term } => {
311            let evaluated_term = evaluate(scp, env, term)?;
312            Ok(scp.core().opposite(evaluated_term)?)
313        }
314        Expr::Not { term } => {
315            let evaluated_term = evaluate(scp, env, term)?;
316            match &evaluated_term {
317                Slot::Primitive(var) => {
318                    if let Ok(bool_expr) = var.clone().as_any().downcast::<BoolExpr>() {
319                        Ok(Slot::Primitive(Rc::new(BoolExpr::Not { var_type: Rc::downgrade(&scp.core().bool_type()), term: bool_expr })))
320                    } else {
321                        Err(RiddleError::RuntimeError(format!("Expected boolean expression, got {}", evaluated_term)))
322                    }
323                }
324                _ => Err(RiddleError::RuntimeError(format!("Expected a primitive variable for negation, got {}", evaluated_term))),
325            }
326        }
327        Expr::Mul { factors } => {
328            let evaluated_factors: Vec<Slot> = factors.iter().map(|f| evaluate(scp, env.clone(), f)).collect::<Result<_, _>>()?;
329            Ok(scp.core().mul(&evaluated_factors)?)
330        }
331        Expr::Div { left, right } => {
332            let evaluated_left = evaluate(scp, env.clone(), left)?;
333            let evaluated_right = evaluate(scp, env, right)?;
334            Ok(scp.core().div(evaluated_left, evaluated_right)?)
335        }
336        Expr::Function { name, args } => {
337            let args = args.iter().map(|a| evaluate(scp, env.clone(), a)).collect::<Result<Vec<_>, _>>()?;
338            let arg_types = args
339                .iter()
340                .map(|a| match a {
341                    Slot::Primitive(var) => Ok(var.var_type()),
342                    Slot::ObjectRef(obj_id) => Ok(scp.core().get_object(*obj_id).ok_or_else(|| RiddleError::NotFound(format!("Object {} not found", *obj_id)))?.var_type()),
343                    Slot::AtomRef(atom_id) => Ok(scp.core().get_atom(*atom_id).ok_or_else(|| RiddleError::NotFound(format!("Atom {} not found", *atom_id)))?.var_type()),
344                })
345                .collect::<Result<Vec<_>, _>>()?;
346            let (last, rest) = name.split_last().ok_or_else(|| RiddleError::RuntimeError("Empty function path".into()))?;
347            if rest.is_empty() {
348                if let Some(function) = scp.get_function(last, &arg_types) {
349                    let out = function.call(env, args)?;
350                    out.ok_or_else(|| RiddleError::RuntimeError(format!("Function '{}' with argument types ({}) did not return a value", last, arg_types.iter().map(|t| t.full_name()).collect::<Vec<_>>().join(", "))))
351                } else {
352                    Err(RiddleError::NotFound(format!("Function '{}' with argument types ({}) not found", last, arg_types.iter().map(|t| t.full_name()).collect::<Vec<_>>().join(", "))))
353                }
354            } else {
355                let var = get_var_by_path(scp.core().as_ref(), env.as_ref(), rest)?;
356                match &var {
357                    Slot::Primitive(_) => Err(RiddleError::NotAClass(format!("Variable '{}' in function path is a primitive variable, expected an object or atom for function call", rest.join(".")))),
358                    Slot::ObjectRef(obj_id) => {
359                        let obj = scp.core().get_object(*obj_id).ok_or_else(|| RiddleError::NotFound(format!("Object {} not found", *obj_id)))?;
360                        if let Some(function) = obj.class().get_function(last, &arg_types) {
361                            let out = function.call(obj.as_env().ok_or_else(|| RiddleError::NotAnEnvironment(format!("Object {} does not have an environment", *obj_id)))?, args)?;
362                            out.ok_or_else(|| RiddleError::RuntimeError(format!("Function '{}' with argument types ({}) did not return a value", last, arg_types.iter().map(|t| t.full_name()).collect::<Vec<_>>().join(", "))))
363                        } else {
364                            Err(RiddleError::NotFound(format!("Function '{}' with argument types ({}) not found in class '{}'", last, arg_types.iter().map(|t| t.full_name()).collect::<Vec<_>>().join(", "), obj.class().full_name())))
365                        }
366                    }
367                    Slot::AtomRef(atom_id) => Err(RiddleError::NotAClass(format!("Variable '{}' in function path is an atom {}, expected an object for function call", rest.join("."), *atom_id))),
368                }
369            }
370        }
371        Expr::Eq { left, right } => {
372            let evaluated_left = evaluate(scp, env.clone(), left)?;
373            let evaluated_right = evaluate(scp, env, right)?;
374            Ok(Slot::Primitive(Rc::new(BoolExpr::Eq {
375                var_type: Rc::downgrade(&scp.core().bool_type()),
376                left: evaluated_left,
377                right: evaluated_right,
378            })))
379        }
380        Expr::Neq { left, right } => {
381            let evaluated_left = evaluate(scp, env.clone(), left)?;
382            let evaluated_right = evaluate(scp, env, right)?;
383            Ok(Slot::Primitive(Rc::new(BoolExpr::Not {
384                var_type: Rc::downgrade(&scp.core().bool_type()),
385                term: Rc::new(BoolExpr::Eq {
386                    var_type: Rc::downgrade(&scp.core().bool_type()),
387                    left: evaluated_left,
388                    right: evaluated_right,
389                }),
390            })))
391        }
392        Expr::Lt { left, right } => {
393            let evaluated_left = evaluate(scp, env.clone(), left)?;
394            let evaluated_right = evaluate(scp, env, right)?;
395            Ok(Slot::Primitive(Rc::new(BoolExpr::Lt {
396                var_type: Rc::downgrade(&scp.core().bool_type()),
397                left: evaluated_left,
398                right: evaluated_right,
399            })))
400        }
401        Expr::Leq { left, right } => {
402            let evaluated_left = evaluate(scp, env.clone(), left)?;
403            let evaluated_right = evaluate(scp, env, right)?;
404            Ok(Slot::Primitive(Rc::new(BoolExpr::Leq {
405                var_type: Rc::downgrade(&scp.core().bool_type()),
406                left: evaluated_left,
407                right: evaluated_right,
408            })))
409        }
410        Expr::Geq { left, right } => {
411            let evaluated_left = evaluate(scp, env.clone(), left)?;
412            let evaluated_right = evaluate(scp, env, right)?;
413            Ok(Slot::Primitive(Rc::new(BoolExpr::Leq {
414                var_type: Rc::downgrade(&scp.core().bool_type()),
415                left: evaluated_right,
416                right: evaluated_left,
417            })))
418        }
419        Expr::Gt { left, right } => {
420            let evaluated_left = evaluate(scp, env.clone(), left)?;
421            let evaluated_right = evaluate(scp, env, right)?;
422            Ok(Slot::Primitive(Rc::new(BoolExpr::Lt {
423                var_type: Rc::downgrade(&scp.core().bool_type()),
424                left: evaluated_right,
425                right: evaluated_left,
426            })))
427        }
428        Expr::Or { terms } => {
429            let evaluated_terms: Vec<Rc<BoolExpr>> = terms
430                .iter()
431                .map(|t| match evaluate(scp, env.clone(), t)? {
432                    Slot::Primitive(var) => {
433                        if let Ok(bool_expr) = var.as_any().downcast::<BoolExpr>() {
434                            Ok(bool_expr)
435                        } else {
436                            Err(RiddleError::RuntimeError("Expected boolean expression in 'or' term".to_string()))
437                        }
438                    }
439                    _ => Err(RiddleError::RuntimeError("Expected boolean expression in 'or' term".to_string())),
440                })
441                .collect::<Result<_, _>>()?;
442            Ok(Slot::Primitive(Rc::new(BoolExpr::Or { var_type: Rc::downgrade(&scp.core().bool_type()), terms: evaluated_terms })))
443        }
444        Expr::And { terms } => {
445            let evaluated_terms: Vec<Rc<BoolExpr>> = terms
446                .iter()
447                .map(|t| match evaluate(scp, env.clone(), t)? {
448                    Slot::Primitive(var) => {
449                        if let Ok(bool_expr) = var.as_any().downcast::<BoolExpr>() {
450                            Ok(bool_expr)
451                        } else {
452                            Err(RiddleError::RuntimeError("Expected boolean expression in 'and' term".to_string()))
453                        }
454                    }
455                    _ => Err(RiddleError::RuntimeError("Expected boolean expression in 'and' term".to_string())),
456                })
457                .collect::<Result<_, _>>()?;
458            Ok(Slot::Primitive(Rc::new(BoolExpr::And { var_type: Rc::downgrade(&scp.core().bool_type()), terms: evaluated_terms })))
459        }
460        Expr::NewObject { class_name, args } => {
461            let class = get_type_by_path(scp, class_name)?.as_class().ok_or_else(|| RiddleError::NotAClass(class_name.join(".")))?;
462            let args = args.iter().map(|a| evaluate(scp, env.clone(), a)).collect::<Result<Vec<_>, _>>()?;
463            let arg_types = args
464                .iter()
465                .map(|a| match a {
466                    Slot::Primitive(var) => Ok(var.var_type()),
467                    Slot::ObjectRef(obj_id) => Ok(scp.core().get_object(*obj_id).ok_or_else(|| RiddleError::NotFound(format!("Object {} not found", *obj_id)))?.var_type()),
468                    Slot::AtomRef(atom_id) => Ok(scp.core().get_atom(*atom_id).ok_or_else(|| RiddleError::NotFound(format!("Atom {} not found", *atom_id)))?.var_type()),
469                })
470                .collect::<Result<Vec<_>, _>>()?;
471            let constructor = class.constructor(&arg_types).ok_or_else(|| RiddleError::NotFound(format!("Constructor for class '{}' with argument types ({}) not found", class.full_name(), arg_types.iter().map(|t| t.full_name()).collect::<Vec<_>>().join(", "))))?;
472            let object = class.new_instance();
473            let object = match object {
474                Slot::ObjectRef(obj_id) => Ok(obj_id),
475                _ => Err(RiddleError::RuntimeError("Constructor did not return an object reference".to_string())),
476            }?;
477            constructor.call(object, args)?;
478            Ok(Slot::ObjectRef(object))
479        }
480    }
481}