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