riddle-lang 0.2.4

RiDDLe is a language for the definition of timeline-based domains and problem definitions, designed to facilitate the integration with solvers and to increase modularity and reusability of domain models.
Documentation
#![allow(dead_code)]

use core::fmt;
use riddle::{
    RiddleError,
    core::{CommonCore, Core},
    env::{Atom, AtomId, BoolExpr, Env, Object, ObjectId, Slot, Var},
    language::Disjunction,
    scope::{Class, Field, Function, Predicate, Scope, Type, arith_type, get_type_by_path},
};
use std::{
    any::Any,
    cell::RefCell,
    collections::HashMap,
    rc::{Rc, Weak},
};

struct TestObject {
    var_type: Weak<dyn Type>,
}

impl TestObject {
    fn new(var_type: Rc<dyn Type>) -> Self {
        Self { var_type: Rc::downgrade(&var_type) }
    }
}

impl Var for TestObject {
    fn var_type(&self) -> Rc<dyn Type> {
        self.var_type.upgrade().expect("Type has been dropped").clone()
    }

    fn as_any(self: Rc<Self>) -> Rc<dyn Any> {
        self
    }
}

struct TestEnum {
    var_type: Weak<dyn Type>,
    variables: RefCell<HashMap<String, Slot>>,
}

impl TestEnum {
    fn new(var_type: Rc<dyn Type>) -> Self {
        Self { var_type: Rc::downgrade(&var_type), variables: RefCell::new(HashMap::new()) }
    }
}

impl Var for TestEnum {
    fn var_type(&self) -> Rc<dyn Type> {
        self.var_type.upgrade().expect("Type has been dropped").clone()
    }

    fn as_any(self: Rc<Self>) -> Rc<dyn Any> {
        self
    }

    fn as_env(self: Rc<Self>) -> Option<Rc<dyn Env>> {
        Some(self.clone())
    }
}

impl Env for TestEnum {
    fn parent(&self) -> Option<Rc<dyn Env>> {
        None
    }

    fn get(&self, name: &str) -> Option<Slot> {
        if let Some(var) = self.variables.borrow().get(name) {
            return Some(var.clone());
        } else {
            if let Some(class) = self.var_type.upgrade().expect("Type has been dropped").as_class() {
                if let Some(field) = class.get_field(name) {
                    let field_type = get_type_by_path(class.as_ref(), field.field_type()).expect("Field type should exist");
                    return Some(field_type.new_instance());
                }
            }
        }
        None
    }

    fn set(&self, name: String, value: Slot) {
        self.variables.borrow_mut().insert(name, value);
    }
}

pub(crate) struct TestCore {
    core: Rc<CommonCore>,
}

impl TestCore {
    pub(crate) fn new() -> Rc<Self> {
        let slv = Rc::new_cyclic(|core| TestCore {
            core: {
                let core: Weak<TestCore> = core.clone();
                CommonCore::new(core)
            },
        });
        slv.core.read("real origin, horizon; origin >= 0.0; origin <= horizon;").expect("Failed to read core definitions");
        slv.core.read("predicate Impulse(real at) { at >= origin; at <= horizon; }").expect("Failed to read core definitions");
        slv.core.read("predicate Interval(real start, real duration, real end) { start >= origin; end <= horizon; duration == end - start; }").expect("Failed to read core definitions");
        slv.core.read("class StateVariable { }").expect("Failed to read core definitions");
        slv.core.read("class ReusableResource { real capacity; ReusableResource(real capacity) : capacity(capacity) { } predicate Use(real amount) : Interval { amount >= 0.0; amount <= capacity; } }").expect("Failed to read core definitions");
        slv
    }

    pub(crate) fn read(&self, script: &str) -> Result<(), RiddleError> {
        self.core.read(script)
    }
}

impl Core for TestCore {
    fn new_bool(&self, _value: bool) -> Slot {
        Slot::Primitive(Rc::new(TestObject::new(self.bool_type())))
    }
    fn new_bool_var(&self) -> Slot {
        Slot::Primitive(Rc::new(TestObject::new(self.bool_type())))
    }
    fn new_int(&self, _value: &str) -> Slot {
        Slot::Primitive(Rc::new(TestObject::new(self.int_type())))
    }
    fn new_int_var(&self) -> Slot {
        Slot::Primitive(Rc::new(TestObject::new(self.int_type())))
    }
    fn new_real(&self, _num: &str, _den: &str) -> Slot {
        Slot::Primitive(Rc::new(TestObject::new(self.real_type())))
    }
    fn new_real_var(&self) -> Slot {
        Slot::Primitive(Rc::new(TestObject::new(self.real_type())))
    }
    fn new_string(&self, _value: &str) -> Slot {
        Slot::Primitive(Rc::new(TestObject::new(self.string_type())))
    }
    fn new_string_var(&self) -> Slot {
        Slot::Primitive(Rc::new(TestObject::new(self.string_type())))
    }

    fn sum(&self, sum: &[Slot]) -> Result<Slot, RiddleError> {
        let tp = arith_type(self, sum)?;
        Ok(Slot::Primitive(Rc::new(TestObject::new(tp))))
    }
    fn opposite(&self, term: Slot) -> Result<Slot, RiddleError> {
        let tp = match term {
            Slot::Primitive(var) => var.var_type(),
            Slot::ObjectRef(id) => self.get_object(id).expect("Object should exist").class(),
            Slot::AtomRef(id) => self.get_atom(id).expect("Atom should exist").predicate(),
        };
        Ok(Slot::Primitive(Rc::new(TestObject::new(tp))))
    }
    fn mul(&self, mul: &[Slot]) -> Result<Slot, RiddleError> {
        let tp = arith_type(self, mul)?;
        Ok(Slot::Primitive(Rc::new(TestObject::new(tp))))
    }
    fn div(&self, left: Slot, right: Slot) -> Result<Slot, RiddleError> {
        let tp = arith_type(self, &[left, right])?;
        Ok(Slot::Primitive(Rc::new(TestObject::new(tp))))
    }

    fn assert(&self, _term: Rc<BoolExpr>) -> bool {
        true
    }

    fn new_var(&self, class: Rc<dyn Class>, instances: &[ObjectId]) -> Result<Slot, RiddleError> {
        if instances.is_empty() {
            return Err(RiddleError::InconsistencyError("Cannot create variable with no instances".into()));
        }
        Ok(Slot::Primitive(Rc::new(TestEnum::new(class))))
    }
    fn new_disjunction(&self, _disjunction: Disjunction) {}

    fn new_object(&self, class: Rc<dyn Class>) -> ObjectId {
        self.core.new_object(class)
    }
    fn get_object(&self, id: ObjectId) -> Option<Rc<Object>> {
        self.core.get_object(id)
    }
    fn new_atom(&self, predicate: Rc<Predicate>, fact: bool, args: HashMap<String, Slot>) -> AtomId {
        self.core.new_atom(predicate, fact, args)
    }
    fn get_atom(&self, id: AtomId) -> Option<Rc<Atom>> {
        self.core.get_atom(id)
    }
}

impl Scope for TestCore {
    fn core(&self) -> Rc<dyn Core> {
        panic!("Core should not call scope core method")
    }

    fn scope(&self) -> Option<Rc<dyn Scope>> {
        None
    }

    fn get_fields(&self) -> Vec<Rc<Field>> {
        self.core.get_fields()
    }

    fn get_field(&self, _name: &str) -> Option<Rc<Field>> {
        self.core.get_field(_name)
    }

    fn get_function(&self, name: &str, types: &[Rc<dyn Type>]) -> Option<Rc<Function>> {
        self.core.get_function(name, types)
    }

    fn get_type(&self, name: &str) -> Option<Rc<dyn Type>> {
        self.core.get_type(name)
    }

    fn get_predicate(&self, name: &str) -> Option<Rc<Predicate>> {
        self.core.get_predicate(name)
    }
}

impl Env for TestCore {
    fn parent(&self) -> Option<Rc<dyn Env>> {
        None
    }

    fn get(&self, name: &str) -> Option<Slot> {
        self.core.get(name)
    }

    fn set(&self, name: String, value: Slot) {
        self.core.set(name, value);
    }
}

impl fmt::Debug for TestCore {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "TestCore {{ ... }}")
    }
}