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>)>); pub 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 }
255 let mut pred_hierarchy = VecDeque::from(vec![predicate.clone()]);
256 while let Some(pred) = pred_hierarchy.pop_front() {
257 for (arg_type, name) in pred.args() {
258 if !args.contains_key(name) {
259 let arg_tp = get_type_by_path(scp.as_ref(), arg_type)?;
260 if let Some(class) = arg_tp.clone().as_class() {
261 let instances = class.instances();
262 if instances.is_empty() {
263 return Err(RiddleError::RuntimeError(format!("No instances found for argument '{}' of type '{}'", name, class.full_name())));
264 } else if instances.len() == 1 {
265 args.insert(name.clone(), Slot::ObjectRef(instances[0]));
266 } else {
267 args.insert(name.clone(), scp.core().new_var(class, instances.as_slice())?);
268 }
269 } else {
270 args.insert(name.clone(), arg_tp.new_instance());
271 }
272 }
273 }
274 for parent_path in pred.parents() {
275 let (predicate_name, class_path) = parent_path.split_last().ok_or_else(|| RiddleError::RuntimeError("Empty parent predicate path".into()))?;
276 let parent_predicate = if class_path.is_empty() {
277 scp.get_predicate(predicate_name).ok_or_else(|| RiddleError::NotFound(format!("Predicate '{}' in parent path", predicate_name)))?
278 } else {
279 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("."))))?;
280 class.get_predicate(predicate_name).ok_or_else(|| RiddleError::NotFound(format!("Predicate '{}' in class '{}'", predicate_name, class.full_name())))?
281 };
282 pred_hierarchy.push_back(parent_predicate);
283 }
284 }
285 let atom = scp.core().new_atom(predicate, *is_fact, args);
286 env.set(name.clone(), Slot::AtomRef(atom));
287 Ok(())
288 }
289 Statement::Return { value } => {
290 let ret = evaluate(scp.as_ref(), env.clone(), value)?;
291 env.set("__return".to_string(), ret);
292 Ok(())
293 }
294 }
295}
296
297pub fn evaluate(scp: &dyn Scope, env: Rc<dyn Env>, expr: &Expr) -> Result<Slot, RiddleError> {
298 match expr {
299 Expr::Bool(bool) => Ok(scp.core().new_bool(*bool)),
300 Expr::Int(int) => Ok(scp.core().new_int(int)),
301 Expr::Real(num, den) => Ok(scp.core().new_real(num, den)),
302 Expr::String(string) => Ok(scp.core().new_string(string)),
303 Expr::QualifiedId { ids } => get_var_by_path(scp.core().as_ref(), env.as_ref(), ids),
304 Expr::Sum { terms } => {
305 let evaluated_terms: Vec<Slot> = terms.iter().map(|t| evaluate(scp, env.clone(), t)).collect::<Result<_, _>>()?;
306 Ok(scp.core().sum(&evaluated_terms)?)
307 }
308 Expr::Opposite { term } => {
309 let evaluated_term = evaluate(scp, env, term)?;
310 Ok(scp.core().opposite(evaluated_term)?)
311 }
312 Expr::Not { term } => {
313 let evaluated_term = evaluate(scp, env, term)?;
314 match &evaluated_term {
315 Slot::Primitive(var) => {
316 if let Ok(bool_expr) = var.clone().as_any().downcast::<BoolExpr>() {
317 Ok(Slot::Primitive(Rc::new(BoolExpr::Not { var_type: Rc::downgrade(&scp.core().bool_type()), term: bool_expr })))
318 } else {
319 Err(RiddleError::RuntimeError(format!("Expected boolean expression, got {}", evaluated_term)))
320 }
321 }
322 _ => Err(RiddleError::RuntimeError(format!("Expected a primitive variable for negation, got {}", evaluated_term))),
323 }
324 }
325 Expr::Mul { factors } => {
326 let evaluated_factors: Vec<Slot> = factors.iter().map(|f| evaluate(scp, env.clone(), f)).collect::<Result<_, _>>()?;
327 Ok(scp.core().mul(&evaluated_factors)?)
328 }
329 Expr::Div { left, right } => {
330 let evaluated_left = evaluate(scp, env.clone(), left)?;
331 let evaluated_right = evaluate(scp, env, right)?;
332 Ok(scp.core().div(evaluated_left, evaluated_right)?)
333 }
334 Expr::Function { name, args } => {
335 let args = args.iter().map(|a| evaluate(scp, env.clone(), a)).collect::<Result<Vec<_>, _>>()?;
336 let arg_types = args
337 .iter()
338 .map(|a| match a {
339 Slot::Primitive(var) => Ok(var.var_type()),
340 Slot::ObjectRef(obj_id) => Ok(scp.core().get_object(*obj_id).ok_or_else(|| RiddleError::NotFound(format!("Object {} not found", *obj_id)))?.var_type()),
341 Slot::AtomRef(atom_id) => Ok(scp.core().get_atom(*atom_id).ok_or_else(|| RiddleError::NotFound(format!("Atom {} not found", *atom_id)))?.var_type()),
342 })
343 .collect::<Result<Vec<_>, _>>()?;
344 let (last, rest) = name.split_last().ok_or_else(|| RiddleError::RuntimeError("Empty function path".into()))?;
345 if rest.is_empty() {
346 if let Some(function) = scp.get_function(last, &arg_types) {
347 let out = function.call(env, args)?;
348 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(", "))))
349 } else {
350 Err(RiddleError::NotFound(format!("Function '{}' with argument types ({}) not found", last, arg_types.iter().map(|t| t.full_name()).collect::<Vec<_>>().join(", "))))
351 }
352 } else {
353 let var = get_var_by_path(scp.core().as_ref(), env.as_ref(), rest)?;
354 match &var {
355 Slot::Primitive(_) => Err(RiddleError::NotAClass(format!("Variable '{}' in function path is a primitive variable, expected an object or atom for function call", rest.join(".")))),
356 Slot::ObjectRef(obj_id) => {
357 let obj = scp.core().get_object(*obj_id).ok_or_else(|| RiddleError::NotFound(format!("Object {} not found", *obj_id)))?;
358 if let Some(function) = obj.class().get_function(last, &arg_types) {
359 let out = function.call(obj.as_env().ok_or_else(|| RiddleError::NotAnEnvironment(format!("Object {} does not have an environment", *obj_id)))?, args)?;
360 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(", "))))
361 } else {
362 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())))
363 }
364 }
365 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))),
366 }
367 }
368 }
369 Expr::Eq { left, right } => {
370 let evaluated_left = evaluate(scp, env.clone(), left)?;
371 let evaluated_right = evaluate(scp, env, right)?;
372 Ok(Slot::Primitive(Rc::new(BoolExpr::Eq {
373 var_type: Rc::downgrade(&scp.core().bool_type()),
374 left: evaluated_left,
375 right: evaluated_right,
376 })))
377 }
378 Expr::Neq { left, right } => {
379 let evaluated_left = evaluate(scp, env.clone(), left)?;
380 let evaluated_right = evaluate(scp, env, right)?;
381 Ok(Slot::Primitive(Rc::new(BoolExpr::Not {
382 var_type: Rc::downgrade(&scp.core().bool_type()),
383 term: Rc::new(BoolExpr::Eq {
384 var_type: Rc::downgrade(&scp.core().bool_type()),
385 left: evaluated_left,
386 right: evaluated_right,
387 }),
388 })))
389 }
390 Expr::Lt { left, right } => {
391 let evaluated_left = evaluate(scp, env.clone(), left)?;
392 let evaluated_right = evaluate(scp, env, right)?;
393 Ok(Slot::Primitive(Rc::new(BoolExpr::Lt {
394 var_type: Rc::downgrade(&scp.core().bool_type()),
395 left: evaluated_left,
396 right: evaluated_right,
397 })))
398 }
399 Expr::Leq { left, right } => {
400 let evaluated_left = evaluate(scp, env.clone(), left)?;
401 let evaluated_right = evaluate(scp, env, right)?;
402 Ok(Slot::Primitive(Rc::new(BoolExpr::Leq {
403 var_type: Rc::downgrade(&scp.core().bool_type()),
404 left: evaluated_left,
405 right: evaluated_right,
406 })))
407 }
408 Expr::Geq { left, right } => {
409 let evaluated_left = evaluate(scp, env.clone(), left)?;
410 let evaluated_right = evaluate(scp, env, right)?;
411 Ok(Slot::Primitive(Rc::new(BoolExpr::Leq {
412 var_type: Rc::downgrade(&scp.core().bool_type()),
413 left: evaluated_right,
414 right: evaluated_left,
415 })))
416 }
417 Expr::Gt { left, right } => {
418 let evaluated_left = evaluate(scp, env.clone(), left)?;
419 let evaluated_right = evaluate(scp, env, right)?;
420 Ok(Slot::Primitive(Rc::new(BoolExpr::Lt {
421 var_type: Rc::downgrade(&scp.core().bool_type()),
422 left: evaluated_right,
423 right: evaluated_left,
424 })))
425 }
426 Expr::Or { terms } => {
427 let evaluated_terms: Vec<Rc<BoolExpr>> = terms
428 .iter()
429 .map(|t| match evaluate(scp, env.clone(), t)? {
430 Slot::Primitive(var) => {
431 if let Ok(bool_expr) = var.as_any().downcast::<BoolExpr>() {
432 Ok(bool_expr)
433 } else {
434 Err(RiddleError::RuntimeError("Expected boolean expression in 'or' term".to_string()))
435 }
436 }
437 _ => Err(RiddleError::RuntimeError("Expected boolean expression in 'or' term".to_string())),
438 })
439 .collect::<Result<_, _>>()?;
440 Ok(Slot::Primitive(Rc::new(BoolExpr::Or { var_type: Rc::downgrade(&scp.core().bool_type()), terms: evaluated_terms })))
441 }
442 Expr::And { terms } => {
443 let evaluated_terms: Vec<Rc<BoolExpr>> = terms
444 .iter()
445 .map(|t| match evaluate(scp, env.clone(), t)? {
446 Slot::Primitive(var) => {
447 if let Ok(bool_expr) = var.as_any().downcast::<BoolExpr>() {
448 Ok(bool_expr)
449 } else {
450 Err(RiddleError::RuntimeError("Expected boolean expression in 'and' term".to_string()))
451 }
452 }
453 _ => Err(RiddleError::RuntimeError("Expected boolean expression in 'and' term".to_string())),
454 })
455 .collect::<Result<_, _>>()?;
456 Ok(Slot::Primitive(Rc::new(BoolExpr::And { var_type: Rc::downgrade(&scp.core().bool_type()), terms: evaluated_terms })))
457 }
458 Expr::NewObject { class_name, args } => {
459 let class = get_type_by_path(scp, class_name)?.as_class().ok_or_else(|| RiddleError::NotAClass(class_name.join(".")))?;
460 let args = args.iter().map(|a| evaluate(scp, env.clone(), a)).collect::<Result<Vec<_>, _>>()?;
461 let arg_types = args
462 .iter()
463 .map(|a| match a {
464 Slot::Primitive(var) => Ok(var.var_type()),
465 Slot::ObjectRef(obj_id) => Ok(scp.core().get_object(*obj_id).ok_or_else(|| RiddleError::NotFound(format!("Object {} not found", *obj_id)))?.var_type()),
466 Slot::AtomRef(atom_id) => Ok(scp.core().get_atom(*atom_id).ok_or_else(|| RiddleError::NotFound(format!("Atom {} not found", *atom_id)))?.var_type()),
467 })
468 .collect::<Result<Vec<_>, _>>()?;
469 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(", "))))?;
470 let object = class.new_instance();
471 let object = match object {
472 Slot::ObjectRef(obj_id) => Ok(obj_id),
473 _ => Err(RiddleError::RuntimeError("Constructor did not return an object reference".to_string())),
474 }?;
475 constructor.call(object, args)?;
476 Ok(Slot::ObjectRef(object))
477 }
478 }
479}