Skip to main content

riddle/
core.rs

1use crate::{
2    ToJson,
3    env::{Atom, BoolExpr, CommonEnv, Env, Var},
4    language::{Disjunction, RiddleError, execute},
5    parse_problem,
6    scope::{BoolType, CommonScope, Field, IntType, Method, Predicate, RealType, Scope, StringType, Type},
7};
8use serde_json::{Value, json};
9use std::{
10    collections::{HashMap, VecDeque},
11    rc::{Rc, Weak},
12};
13
14pub trait Core: Scope + Env {
15    fn new_bool(&self, value: bool) -> Rc<dyn Var>;
16    fn new_bool_var(&self) -> Rc<dyn Var>;
17    fn new_int(&self, value: i64) -> Rc<dyn Var>;
18    fn new_int_var(&self) -> Rc<dyn Var>;
19    fn new_real(&self, num: i64, den: i64) -> Rc<dyn Var>;
20    fn new_real_var(&self) -> Rc<dyn Var>;
21    fn new_string(&self, value: &str) -> Rc<dyn Var>;
22    fn new_string_var(&self) -> Rc<dyn Var>;
23
24    fn sum(&self, sum: &[Rc<dyn Var>]) -> Result<Rc<dyn Var>, RiddleError>;
25    fn opposite(&self, term: Rc<dyn Var>) -> Result<Rc<dyn Var>, RiddleError>;
26    fn mul(&self, mul: &[Rc<dyn Var>]) -> Result<Rc<dyn Var>, RiddleError>;
27    fn div(&self, left: Rc<dyn Var>, right: Rc<dyn Var>) -> Result<Rc<dyn Var>, RiddleError>;
28
29    fn assert(&self, term: Rc<BoolExpr>) -> bool;
30    fn new_var(&self, class: Rc<dyn Type>, instances: &[Rc<dyn Var>]) -> Result<Rc<dyn Var>, RiddleError>;
31    fn new_disjunction(&self, disjunction: Disjunction);
32    fn new_atom(&self, atom: Rc<Atom>);
33
34    fn bool_type(&self) -> Rc<BoolType> {
35        self.get_type("bool").expect("Core should have bool type").as_any().downcast::<BoolType>().expect("Core bool type should be BoolType")
36    }
37
38    fn int_type(&self) -> Rc<IntType> {
39        self.get_type("int").expect("Core should have int type").as_any().downcast::<IntType>().expect("Core int type should be IntType")
40    }
41
42    fn real_type(&self) -> Rc<RealType> {
43        self.get_type("real").expect("Core should have real type").as_any().downcast::<RealType>().expect("Core real type should be RealType")
44    }
45
46    fn string_type(&self) -> Rc<StringType> {
47        self.get_type("string").expect("Core should have string type").as_any().downcast::<StringType>().expect("Core string type should be StringType")
48    }
49}
50
51#[derive(Debug)]
52pub struct CommonCore {
53    scope: Rc<CommonScope>,
54    env: Rc<CommonEnv>,
55}
56
57impl CommonCore {
58    /// Creates a new shared core with a root scope and environment.
59    ///
60    /// The core is initialized with the builtin primitive types:
61    /// `bool`, `int`, `real`, and `string`.
62    pub fn new(core: Weak<dyn Core>) -> Rc<Self> {
63        let c_core = Rc::new(CommonCore { scope: Rc::new(CommonScope::new(core.clone(), None)), env: Rc::new(CommonEnv::new(None)) });
64        c_core.add_type(Rc::new(BoolType::new(core.clone())));
65        c_core.add_type(Rc::new(IntType::new(core.clone())));
66        c_core.add_type(Rc::new(RealType::new(core.clone())));
67        c_core.add_type(Rc::new(StringType::new(core.clone())));
68        c_core
69    }
70
71    /// Parses and executes a RiDDLe problem in this core context.
72    ///
73    /// The parsed problem metadata is registered in the current scope,
74    /// then each statement is executed in order using this core scope
75    /// and environment.
76    ///
77    /// Returns an error if parsing or execution fails.
78    pub fn read(&self, riddle: &str) -> Result<(), RiddleError> {
79        let mut problem = parse_problem(riddle)?;
80        let statments = std::mem::take(&mut problem.statements);
81        self.scope.add_problem(problem);
82        for stmt in statments {
83            execute(self.scope.clone(), self.env.clone(), &stmt)?;
84        }
85        Ok(())
86    }
87
88    /// Registers a type in the core type table under its declared name.
89    pub fn add_type(&self, class: Rc<dyn Type>) {
90        self.scope.classes.borrow_mut().insert(class.name().to_string(), class);
91    }
92}
93
94impl ToJson for CommonCore {
95    fn to_json(&self) -> Value {
96        let mut terms = HashMap::new();
97        let mut atoms = HashMap::new();
98        let mut q = VecDeque::new();
99        for tp in self.scope.classes.borrow().values() {
100            if let Some(class) = tp.clone().as_class() {
101                q.push_back(class.clone());
102            }
103        }
104        while let Some(tp) = q.pop_front() {
105            for instance in tp.instances() {
106                let id = Rc::as_ptr(&instance) as *const () as usize;
107                terms.insert(id, instance.var_type().name().to_string());
108            }
109            for pred in tp.predicates() {
110                for atom in pred.atoms() {
111                    let id = Rc::as_ptr(&atom) as *const () as usize;
112                    atoms.insert(id, pred.name().to_string());
113                }
114            }
115            for class in tp.classes() {
116                q.push_back(class);
117            }
118        }
119        json!({ "terms": terms, "atoms": atoms })
120    }
121}
122
123impl Scope for CommonCore {
124    fn core(self: Rc<Self>) -> Rc<dyn Core> {
125        self.scope.clone().core()
126    }
127
128    fn scope(&self) -> Option<Rc<dyn Scope>> {
129        None
130    }
131
132    fn get_field(&self, _name: &str) -> Option<Rc<Field>> {
133        self.scope.get_field(_name)
134    }
135
136    fn get_method(&self, _name: &str, _classes: &[Rc<dyn Type>]) -> Option<Rc<Method>> {
137        self.scope.get_method(_name, _classes)
138    }
139
140    fn get_type(&self, name: &str) -> Option<Rc<dyn Type>> {
141        self.scope.get_type(name)
142    }
143
144    fn get_predicate(&self, _name: &str) -> Option<Rc<Predicate>> {
145        self.scope.get_predicate(_name)
146    }
147}
148
149impl Env for CommonCore {
150    fn parent(&self) -> Option<Rc<dyn Env>> {
151        None
152    }
153
154    fn get(&self, name: &str) -> Option<Rc<dyn Var>> {
155        self.env.get(name)
156    }
157
158    fn set(&self, name: String, value: Rc<dyn Var>) {
159        self.env.set(name, value);
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166    use std::{any::Any, cell::RefCell};
167
168    #[derive(Debug)]
169    struct TestObject {
170        class: Weak<dyn Type>,
171        _id: usize,
172    }
173
174    impl Var for TestObject {
175        fn var_type(&self) -> Rc<dyn Type> {
176            self.class.upgrade().expect("Class should still exist")
177        }
178
179        fn as_any(self: Rc<Self>) -> Rc<dyn Any> {
180            self
181        }
182    }
183
184    #[derive(Debug)]
185    struct TestCore {
186        core: Rc<CommonCore>,
187        id_counter: RefCell<usize>,
188    }
189
190    impl TestCore {
191        fn new() -> Rc<Self> {
192            Rc::new_cyclic(|core| Self {
193                core: {
194                    let core: Weak<TestCore> = core.clone();
195                    CommonCore::new(core)
196                },
197                id_counter: RefCell::new(0),
198            })
199        }
200
201        fn read(&self, riddle: &str) -> Result<(), RiddleError> {
202            self.core.read(riddle)
203        }
204
205        fn next_id(&self) -> usize {
206            let mut counter = self.id_counter.borrow_mut();
207            let id = *counter;
208            *counter += 1;
209            id
210        }
211    }
212
213    impl Core for TestCore {
214        fn new_bool(&self, _value: bool) -> Rc<dyn Var> {
215            Rc::new(TestObject { class: Rc::downgrade(&(self.bool_type() as Rc<dyn Type>)), _id: self.next_id() })
216        }
217
218        fn new_bool_var(&self) -> Rc<dyn Var> {
219            Rc::new(TestObject { class: Rc::downgrade(&(self.bool_type() as Rc<dyn Type>)), _id: self.next_id() })
220        }
221
222        fn new_int(&self, _value: i64) -> Rc<dyn Var> {
223            Rc::new(TestObject { class: Rc::downgrade(&(self.int_type() as Rc<dyn Type>)), _id: self.next_id() })
224        }
225
226        fn new_int_var(&self) -> Rc<dyn Var> {
227            Rc::new(TestObject { class: Rc::downgrade(&(self.int_type() as Rc<dyn Type>)), _id: self.next_id() })
228        }
229
230        fn new_real(&self, _num: i64, _den: i64) -> Rc<dyn Var> {
231            Rc::new(TestObject { class: Rc::downgrade(&(self.real_type() as Rc<dyn Type>)), _id: self.next_id() })
232        }
233
234        fn new_real_var(&self) -> Rc<dyn Var> {
235            Rc::new(TestObject { class: Rc::downgrade(&(self.real_type() as Rc<dyn Type>)), _id: self.next_id() })
236        }
237
238        fn new_string(&self, _value: &str) -> Rc<dyn Var> {
239            Rc::new(TestObject { class: Rc::downgrade(&(self.string_type() as Rc<dyn Type>)), _id: self.next_id() })
240        }
241
242        fn new_string_var(&self) -> Rc<dyn Var> {
243            Rc::new(TestObject { class: Rc::downgrade(&(self.string_type() as Rc<dyn Type>)), _id: self.next_id() })
244        }
245
246        fn sum(&self, _sum: &[Rc<dyn Var>]) -> Result<Rc<dyn Var>, RiddleError> {
247            Ok(Rc::new(TestObject { class: Rc::downgrade(&(self.int_type() as Rc<dyn Type>)), _id: self.next_id() }))
248        }
249
250        fn opposite(&self, _term: Rc<dyn Var>) -> Result<Rc<dyn Var>, RiddleError> {
251            Ok(Rc::new(TestObject { class: Rc::downgrade(&(self.int_type() as Rc<dyn Type>)), _id: self.next_id() }))
252        }
253
254        fn mul(&self, _mul: &[Rc<dyn Var>]) -> Result<Rc<dyn Var>, RiddleError> {
255            Ok(Rc::new(TestObject { class: Rc::downgrade(&(self.int_type() as Rc<dyn Type>)), _id: self.next_id() }))
256        }
257
258        fn div(&self, _left: Rc<dyn Var>, _right: Rc<dyn Var>) -> Result<Rc<dyn Var>, RiddleError> {
259            Ok(Rc::new(TestObject { class: Rc::downgrade(&(self.int_type() as Rc<dyn Type>)), _id: self.next_id() }))
260        }
261
262        fn assert(&self, _term: Rc<BoolExpr>) -> bool {
263            true
264        }
265
266        fn new_var(&self, class: Rc<dyn Type>, instances: &[Rc<dyn Var>]) -> Result<Rc<dyn Var>, RiddleError> {
267            if instances.is_empty() {
268                return Err(RiddleError::InconsistencyError("Cannot create variable with no instances".into()));
269            }
270            Ok(Rc::new(TestObject { class: Rc::downgrade(&class), _id: self.next_id() }))
271        }
272
273        fn new_disjunction(&self, _disjunction: Disjunction) {}
274
275        fn new_atom(&self, _atom: Rc<Atom>) {}
276    }
277
278    impl Scope for TestCore {
279        fn core(self: Rc<Self>) -> Rc<dyn Core> {
280            self
281        }
282
283        fn scope(&self) -> Option<Rc<dyn Scope>> {
284            None
285        }
286
287        fn get_field(&self, _name: &str) -> Option<Rc<Field>> {
288            None
289        }
290
291        fn get_method(&self, name: &str, classes: &[Rc<dyn Type>]) -> Option<Rc<Method>> {
292            self.core.get_method(name, classes)
293        }
294
295        fn get_type(&self, name: &str) -> Option<Rc<dyn Type>> {
296            self.core.get_type(name)
297        }
298
299        fn get_predicate(&self, name: &str) -> Option<Rc<Predicate>> {
300            self.core.get_predicate(name)
301        }
302    }
303
304    impl Env for TestCore {
305        fn parent(&self) -> Option<Rc<dyn Env>> {
306            None
307        }
308
309        fn get(&self, name: &str) -> Option<Rc<dyn Var>> {
310            self.core.get(name)
311        }
312
313        fn set(&self, name: String, value: Rc<dyn Var>) {
314            self.core.set(name, value);
315        }
316    }
317
318    #[test]
319    fn create_core() {
320        let core = TestCore::new();
321        assert!(core.get_type("bool").is_some());
322        assert!(core.get_type("int").is_some());
323        assert!(core.get_type("real").is_some());
324        assert!(core.get_type("string").is_some());
325    }
326
327    #[test]
328    fn read_problem() {
329        let core = TestCore::new();
330        core.read("bool a, b, c; (a & b) | c;").expect("Failed to read problem with boolean variables and expression");
331    }
332
333    #[test]
334    fn nested_classes_are_registered_in_class_scope() {
335        let core = TestCore::new();
336        core.read(
337            r#"
338            class Outer {
339                class Inner {}
340            }
341            "#,
342        )
343        .expect("Failed to read problem with nested classes");
344
345        let outer = core.get_type("Outer").expect("Outer class should be registered").as_class().expect("Outer should be a class");
346        let inner = outer.get_type("Inner").expect("Inner class should be registered in the enclosing class scope");
347
348        assert_eq!(inner.full_name(), "Outer.Inner");
349    }
350}