conjure_core/ast/
model.rs

1use std::cell::RefCell;
2use std::collections::{HashMap, VecDeque};
3use std::fmt::{Debug, Display};
4use std::rc::Rc;
5use std::sync::{Arc, RwLock};
6
7use derivative::Derivative;
8use serde::{Deserialize, Serialize};
9use uniplate::{Biplate, Tree, Uniplate};
10
11use crate::ast::Expression;
12use crate::context::Context;
13
14use super::serde::{HasId, ObjId};
15use super::types::Typeable;
16use super::{Name, SubModel};
17use super::{ReturnType, SymbolTable};
18
19/// An Essence model.
20///
21/// - This type wraps a [`Submodel`] containing the top-level lexical scope. To manipulate the
22///   model's constraints or symbols, first convert it to a [`Submodel`] using
23///   [`as_submodel`](Model::as_submodel) / [`as_submodel_mut`](Model::as_submodel_mut).
24///
25/// - To de/serialise a model using `serde`, see [`SerdeModel`].
26#[derive(Derivative, Clone, Debug)]
27#[derivative(PartialEq, Eq)]
28pub struct Model {
29    submodel: SubModel,
30    pub search_order: Option<Vec<Name>>,
31    pub dominance: Option<Expression>,
32    #[derivative(PartialEq = "ignore")]
33    pub context: Arc<RwLock<Context<'static>>>,
34}
35
36impl Model {
37    pub fn from_submodel(submodel: SubModel) -> Model {
38        Model {
39            submodel,
40            ..Default::default()
41        }
42    }
43
44    /// Creates a new model from the given context.
45    pub fn new(context: Arc<RwLock<Context<'static>>>) -> Model {
46        Model {
47            submodel: SubModel::new_top_level(),
48            dominance: None,
49            context,
50            search_order: None,
51        }
52    }
53
54    /// Returns this model as a [`Submodel`].
55    pub fn as_submodel(&self) -> &SubModel {
56        &self.submodel
57    }
58
59    /// Returns this model as a mutable [`Submodel`].
60    pub fn as_submodel_mut(&mut self) -> &mut SubModel {
61        &mut self.submodel
62    }
63
64    /// Replaces the model contents with `new_submodel`, returning the old contents.
65    pub fn replace_submodel(&mut self, new_submodel: SubModel) -> SubModel {
66        std::mem::replace(self.as_submodel_mut(), new_submodel)
67    }
68}
69
70impl Default for Model {
71    fn default() -> Self {
72        Model {
73            submodel: SubModel::new_top_level(),
74            dominance: None,
75            context: Arc::new(RwLock::new(Context::default())),
76            search_order: None,
77        }
78    }
79}
80
81impl Typeable for Model {
82    fn return_type(&self) -> Option<ReturnType> {
83        Some(ReturnType::Bool)
84    }
85}
86
87// At time of writing (03/02/2025), the Uniplate derive macro doesn't like the lifetimes inside
88// context, and we do not yet have a way of ignoring this field.
89impl Uniplate for Model {
90    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
91        // Model contains no sub-models.
92        let self2 = self.clone();
93        (Tree::Zero, Box::new(move |_| self2.clone()))
94    }
95}
96
97impl Biplate<Expression> for Model {
98    fn biplate(&self) -> (Tree<Expression>, Box<dyn Fn(Tree<Expression>) -> Self>) {
99        // walk into submodel
100        let submodel = self.as_submodel();
101        let (expr_tree, expr_ctx) = <SubModel as Biplate<Expression>>::biplate(submodel);
102
103        // walk into dominance relation if it exists
104        let dom_tree = match &self.dominance {
105            Some(expr) => Tree::One(expr.clone()),
106            None => Tree::Zero,
107        };
108        let tree = Tree::<Expression>::Many(VecDeque::from([expr_tree, dom_tree]));
109
110        let self2 = self.clone();
111        let ctx = Box::new(move |x| match x {
112            Tree::Many(xs) => {
113                if xs.len() != 2 {
114                    panic!("Expected a tree with two children");
115                }
116                let submodel_tree = xs[0].clone();
117                let dom_tree = xs[1].clone();
118
119                // reconstruct the submodel
120                let submodel = expr_ctx(submodel_tree);
121                // reconstruct the dominance relation
122                let dominance = match dom_tree {
123                    Tree::One(expr) => Some(expr),
124                    Tree::Zero => None,
125                    _ => panic!("Expected a tree with two children"),
126                };
127
128                let mut self3 = self2.clone();
129                self3.replace_submodel(submodel);
130                self3.dominance = dominance;
131                self3
132            }
133            _ => {
134                panic!("Expected a tree with two children");
135            }
136        });
137
138        (tree, ctx)
139    }
140}
141
142impl Biplate<SubModel> for Model {
143    fn biplate(&self) -> (Tree<SubModel>, Box<dyn Fn(Tree<SubModel>) -> Self>) {
144        let submodel = self.as_submodel().clone();
145
146        let self2 = self.clone();
147        let ctx = Box::new(move |x| {
148            let Tree::One(submodel) = x else {
149                panic!();
150            };
151
152            let mut self3 = self2.clone();
153            self3.replace_submodel(submodel);
154            self3
155        });
156
157        (Tree::One(submodel), ctx)
158    }
159}
160
161impl Display for Model {
162    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163        std::fmt::Display::fmt(self.as_submodel(), f)
164    }
165}
166
167/// A model that is de/serializable using `serde`.
168///
169/// To turn this into a rewritable model, it needs to be initialised using [`initialise`](SerdeModel::initialise).
170///
171/// To deserialise a [`Model`], use `.into()` to convert it into a `SerdeModel` first.
172#[derive(Clone, Debug, Serialize, Deserialize)]
173pub struct SerdeModel {
174    #[serde(flatten)]
175    submodel: SubModel,
176    search_order: Option<Vec<Name>>, // TODO: make this a [expressions]
177    dominance: Option<Expression>,
178}
179
180impl SerdeModel {
181    /// Initialises the model for rewriting.
182    pub fn initialise(self, context: Arc<RwLock<Context<'static>>>) -> Option<Model> {
183        // The definitive versions of each symbol table are stored in the submodels. Parent
184        // pointers store dummy values with the correct ids, but nothing else. We need to replace
185        // these dummy values with pointers to the actual parent symbol tables, using the ids to
186        // know which tables should be equal.
187        //
188        // See super::serde::RcRefCellToInner, super::serde::RcRefCellToId.
189
190        // Store the definitive versions of all symbol tables by id.
191        let mut tables: HashMap<ObjId, Rc<RefCell<SymbolTable>>> = HashMap::new();
192
193        // Find the definitive versions by traversing the sub-models.
194        for submodel in self.submodel.universe() {
195            let id = submodel.symbols().id();
196
197            // ids should be unique!
198            assert_eq!(
199                tables.insert(id, submodel.symbols_ptr_unchecked().clone()),
200                None
201            );
202        }
203
204        // Restore parent pointers using `tables`.
205        for table in tables.clone().into_values() {
206            let mut table_mut = table.borrow_mut();
207            let parent_mut = table_mut.parent_mut_unchecked();
208
209            #[allow(clippy::unwrap_used)]
210            if let Some(parent) = parent_mut {
211                let parent_id = parent.borrow().id();
212
213                *parent = tables.get(&parent_id).unwrap().clone();
214            }
215        }
216
217        Some(Model {
218            submodel: self.submodel,
219            dominance: self.dominance,
220            context,
221            search_order: self.search_order,
222        })
223    }
224}
225
226impl From<Model> for SerdeModel {
227    fn from(val: Model) -> Self {
228        SerdeModel {
229            submodel: val.submodel,
230            dominance: val.dominance,
231            search_order: val.search_order,
232        }
233    }
234}
235
236impl Display for SerdeModel {
237    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238        std::fmt::Display::fmt(&self.submodel, f)
239    }
240}