1
#![allow(clippy::arc_with_non_send_sync)] // uniplate needs this
2
use std::cell::RefCell;
3
use std::collections::{HashMap, VecDeque};
4
use std::fmt::{Debug, Display};
5
use std::rc::Rc;
6
use std::sync::{Arc, RwLock};
7

            
8
use derivative::Derivative;
9
use serde::{Deserialize, Serialize};
10
use uniplate::{Biplate, Tree, Uniplate};
11

            
12
use crate::ast::{Expression, Typeable};
13
use crate::context::Context;
14

            
15
use super::serde::{HasId, ObjId};
16
use super::{DeclarationPtr, Name, SubModel};
17
use 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)]
28
pub 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

            
36
impl 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

            
70
impl 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

            
81
impl Typeable for Model {
82
    fn return_type(&self) -> ReturnType {
83
        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.
89
impl 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

            
97
impl 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

            
142
impl 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

            
161
impl 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)]
173
pub 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

            
180
impl SerdeModel {
181
    /// Initialises the model for rewriting.
182
    ///
183
    /// This swizzles the pointers to symbol tables and declarations using the stored ids.
184
    pub fn initialise(mut self, context: Arc<RwLock<Context<'static>>>) -> Option<Model> {
185
        // The definitive versions of each symbol table are stored in the submodels. Parent
186
        // pointers store dummy values with the correct ids, but nothing else. We need to replace
187
        // these dummy values with pointers to the actual parent symbol tables, using the ids to
188
        // know which tables should be equal.
189
        //
190
        // See super::serde::RcRefCellToInner, super::serde::RcRefCellToId.
191

            
192
        // Store the definitive versions of all symbol tables by id.
193
        let mut tables: HashMap<ObjId, Rc<RefCell<SymbolTable>>> = HashMap::new();
194

            
195
        // Find the definitive versions by traversing the sub-models.
196
        for submodel in self.submodel.universe() {
197
            let id = submodel.symbols().id();
198

            
199
            // ids should be unique!
200
            assert_eq!(
201
                tables.insert(id, submodel.symbols_ptr_unchecked().clone()),
202
                None
203
            );
204
        }
205

            
206
        // Restore parent pointers using `tables`.
207
        for table in tables.clone().into_values() {
208
            let mut table_mut = table.borrow_mut();
209
            let parent_mut = table_mut.parent_mut_unchecked();
210

            
211
            #[allow(clippy::unwrap_used)]
212
            if let Some(parent) = parent_mut {
213
                let parent_id = parent.borrow().id();
214

            
215
                *parent = tables.get(&parent_id).unwrap().clone();
216
            }
217
        }
218

            
219
        // The definitive versions of declarations are stored in the symbol table. References store
220
        // dummy values with the correct ids, but nothing else.
221

            
222
        // Store the definitive version of all declarations by id.
223
        let mut all_declarations: HashMap<ObjId, DeclarationPtr> = HashMap::new();
224
        for table in tables.values() {
225
            for (_, decl) in table.as_ref().borrow().clone().into_iter_local() {
226
                let id = decl.id();
227
                all_declarations.insert(id, decl);
228
            }
229
        }
230

            
231
        // Swizzle declaration pointers in expressions (references, auxdecls) using their ids and `all_declarations`.
232
        *self.submodel.constraints_mut() = self.submodel.constraints().transform_bi(&move |decl: DeclarationPtr| {
233
                let id = decl.id();
234
                        all_declarations
235
                            .get(&id)
236
                            .unwrap_or_else(|| panic!("A declaration used in the expression tree should exist in the symbol table. The missing declaration has id {id}."))
237
                            .clone()
238
        });
239

            
240
        Some(Model {
241
            submodel: self.submodel,
242
            dominance: self.dominance,
243
            context,
244
            search_order: self.search_order,
245
        })
246
    }
247
}
248

            
249
impl From<Model> for SerdeModel {
250
    fn from(val: Model) -> Self {
251
        SerdeModel {
252
            submodel: val.submodel,
253
            dominance: val.dominance,
254
            search_order: val.search_order,
255
        }
256
    }
257
}
258

            
259
impl Display for SerdeModel {
260
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
261
        std::fmt::Display::fmt(&self.submodel, f)
262
    }
263
}
264

            
265
impl SerdeModel {
266
    /// Collects all ObjId values from the model using uniplate traversal.
267
    ///
268
    /// Traverses the model structure using `universe_bi` to collect IDs from:
269
    /// - All SubModels (to get SymbolTable IDs via `HasId`)
270
    /// - All DeclarationPtrs (to get declaration IDs via `HasId`)
271
    ///
272
    /// Returns a mapping from original ID to stable sequential ID (0, 1, 2, ...).
273
    /// IDs are assigned in the order they are encountered during traversal, ensuring
274
    /// stability across identical model structures.
275
    pub fn collect_stable_id_mapping(&self) -> HashMap<ObjId, ObjId> {
276
        let mut id_list: Vec<ObjId> = Vec::new();
277

            
278
        // Collect SymbolTable IDs by traversing all SubModels
279
        for submodel in self.submodel.universe() {
280
            let symbol_table_id = submodel.symbols().id();
281
            if !id_list.contains(&symbol_table_id) {
282
                id_list.push(symbol_table_id);
283
            }
284
        }
285

            
286
        // Collect DeclarationPtr IDs by traversing the constraints expression tree
287
        for decl_ptr in Biplate::<DeclarationPtr>::universe_bi(self.submodel.constraints()) {
288
            let decl_id = decl_ptr.id();
289
            if !id_list.contains(&decl_id) {
290
                id_list.push(decl_id);
291
            }
292
        }
293

            
294
        // Create stable mapping: original_id -> stable_id
295
        let mut id_map = HashMap::new();
296
        for (stable_id, &original_id) in id_list.iter().enumerate() {
297
            id_map.insert(original_id, stable_id as ObjId);
298
        }
299

            
300
        id_map
301
    }
302
}