conjure_core/ast/
submodel.rs

1use super::{
2    comprehension::Comprehension,
3    declaration::DeclarationKind,
4    pretty::{
5        pretty_domain_letting_declaration, pretty_expressions_as_top_level,
6        pretty_value_letting_declaration, pretty_variable_declaration,
7    },
8    serde::RcRefCellAsInner,
9    Declaration,
10};
11use serde::{Deserialize, Serialize};
12use serde_with::serde_as;
13use uniplate::{Biplate, Tree, Uniplate};
14
15use crate::{bug, metadata::Metadata};
16use std::{
17    cell::{Ref, RefCell, RefMut},
18    collections::VecDeque,
19    fmt::Display,
20    rc::Rc,
21};
22
23use super::{types::Typeable, Expression, ReturnType, SymbolTable};
24
25/// A sub-model, representing a lexical scope in the model.
26///
27/// Each sub-model contains a symbol table representing its scope, as well as a expression tree.
28///
29/// The expression tree is formed of a root node of type [`Expression::Root`], which contains a
30/// vector of top-level constraints.
31#[serde_as]
32#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
33pub struct SubModel {
34    constraints: Expression,
35    #[serde_as(as = "RcRefCellAsInner")]
36    symbols: Rc<RefCell<SymbolTable>>,
37}
38
39impl SubModel {
40    /// Creates a new [`Submodel`] with no parent scope.
41    ///
42    /// Top level models are represented as [`Model`](super::model): consider using
43    /// [`Model::new`](super::Model::new) instead.
44    #[doc(hidden)]
45    pub(super) fn new_top_level() -> SubModel {
46        SubModel {
47            constraints: Expression::Root(Metadata::new(), vec![]),
48            symbols: Rc::new(RefCell::new(SymbolTable::new())),
49        }
50    }
51
52    /// Creates a new [`Submodel`] as a child scope of `parent`.
53    ///
54    /// `parent` should be the symbol table of the containing scope of this sub-model.
55    pub fn new(parent: Rc<RefCell<SymbolTable>>) -> SubModel {
56        SubModel {
57            constraints: Expression::Root(Metadata::new(), vec![]),
58            symbols: Rc::new(RefCell::new(SymbolTable::with_parent(parent))),
59        }
60    }
61
62    /// The symbol table for this sub-model as a pointer.
63    ///
64    /// The caller should only mutate the returned symbol table if this method was called on a
65    /// mutable model.
66    pub fn symbols_ptr_unchecked(&self) -> &Rc<RefCell<SymbolTable>> {
67        &self.symbols
68    }
69
70    /// The symbol table for this sub-model as a reference.
71    pub fn symbols(&self) -> Ref<SymbolTable> {
72        (*self.symbols).borrow()
73    }
74
75    /// The symbol table for this sub-model as a mutable reference.
76    pub fn symbols_mut(&mut self) -> RefMut<SymbolTable> {
77        (*self.symbols).borrow_mut()
78    }
79
80    /// The root node of this sub-model.
81    ///
82    /// The root node is an [`Expression::Root`] containing a vector of the top level constraints
83    /// in this sub-model.
84    pub fn root(&self) -> &Expression {
85        &self.constraints
86    }
87
88    /// The root node of this sub-model, as a mutable reference.
89    ///
90    /// The caller is responsible for ensuring that the root node remains an [`Expression::Root`].
91    ///
92    fn root_mut_unchecked(&mut self) -> &mut Expression {
93        &mut self.constraints
94    }
95
96    /// Replaces the root node with `new_root`, returning the old root node.
97    ///
98    /// # Panics
99    ///
100    /// - If `new_root` is not an [`Expression::Root`].
101    pub fn replace_root(&mut self, new_root: Expression) -> Expression {
102        let Expression::Root(_, _) = new_root else {
103            panic!("new_root is not an Expression::Root");
104        };
105
106        // INVARIANT: already checked that `new_root` is an [`Expression::Root`]
107        std::mem::replace(self.root_mut_unchecked(), new_root)
108    }
109
110    /// The top-level constraints in this sub-model.
111    pub fn constraints(&self) -> &Vec<Expression> {
112        let Expression::Root(_, constraints) = &self.constraints else {
113            bug!("The top level expression in a submodel should be Expr::Root");
114        };
115
116        constraints
117    }
118
119    /// The top-level constraints in this sub-model as a mutable vector.
120    pub fn constraints_mut(&mut self) -> &mut Vec<Expression> {
121        let Expression::Root(_, constraints) = &mut self.constraints else {
122            bug!("The top level expression in a submodel should be Expr::Root");
123        };
124
125        constraints
126    }
127
128    /// Replaces the top-level constraints with `new_constraints`, returning the old ones.
129    pub fn replace_constraints(&mut self, new_constraints: Vec<Expression>) -> Vec<Expression> {
130        std::mem::replace(self.constraints_mut(), new_constraints)
131    }
132
133    /// Adds a top-level constraint.
134    pub fn add_constraint(&mut self, constraint: Expression) {
135        self.constraints_mut().push(constraint);
136    }
137
138    /// Adds top-level constraints.
139    pub fn add_constraints(&mut self, constraints: Vec<Expression>) {
140        self.constraints_mut().extend(constraints);
141    }
142
143    /// Adds a new symbol to the symbol table
144    /// (Wrapper over `SymbolTable.insert`)
145    pub fn add_symbol(&mut self, sym: Declaration) -> Option<()> {
146        self.symbols_mut().insert(Rc::new(sym))
147    }
148}
149
150impl Typeable for SubModel {
151    fn return_type(&self) -> Option<super::ReturnType> {
152        Some(ReturnType::Bool)
153    }
154}
155
156impl Display for SubModel {
157    #[allow(clippy::unwrap_used)] // [rustdocs]: should only fail iff the formatter fails
158    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159        for (name, decl) in self.symbols().clone().into_iter_local() {
160            match decl.kind() {
161                DeclarationKind::DecisionVariable(_) => {
162                    writeln!(
163                        f,
164                        "{}",
165                        pretty_variable_declaration(&self.symbols(), &name).unwrap()
166                    )?;
167                }
168                DeclarationKind::ValueLetting(_) => {
169                    writeln!(
170                        f,
171                        "{}",
172                        pretty_value_letting_declaration(&self.symbols(), &name).unwrap()
173                    )?;
174                }
175                DeclarationKind::DomainLetting(_) => {
176                    writeln!(
177                        f,
178                        "{}",
179                        pretty_domain_letting_declaration(&self.symbols(), &name).unwrap()
180                    )?;
181                }
182            }
183        }
184
185        writeln!(f, "\nsuch that\n")?;
186
187        writeln!(f, "{}", pretty_expressions_as_top_level(self.constraints()))?;
188
189        Ok(())
190    }
191}
192
193// Using manual implementations of Uniplate so that we can update the old Rc<RefCell<<>>> with the
194// new value instead of creating a new one. This will keep the parent pointers in sync.
195//
196// I considered adding Rc RefCell shared-mutability to Uniplate, but I think this is unsound in
197// generality: e.g. two pointers to the same object are in our tree, and both get modified in
198// different ways.
199//
200// Shared mutability is probably fine here, as we only have one pointer to each symbol table
201// reachable via Uniplate, the one in its Submodel. The SymbolTable implementation doesn't return
202// or traverse through the parent pointers.
203//
204// -- nd60
205
206impl Uniplate for SubModel {
207    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
208        // Look inside constraint tree and symbol tables.
209
210        let (expr_tree, expr_ctx) = <Expression as Biplate<SubModel>>::biplate(self.root());
211
212        let symtab_ptr = self.symbols();
213        let (symtab_tree, symtab_ctx) = <SymbolTable as Biplate<SubModel>>::biplate(&symtab_ptr);
214
215        let tree = Tree::Many(VecDeque::from([expr_tree, symtab_tree]));
216
217        let self2 = self.clone();
218        let ctx = Box::new(move |x| {
219            let Tree::Many(xs) = x else {
220                panic!();
221            };
222
223            let root = expr_ctx(xs[0].clone());
224            let symtab = symtab_ctx(xs[1].clone());
225
226            let mut self3 = self2.clone();
227
228            let Expression::Root(_, _) = root else {
229                bug!("root expression not root");
230            };
231
232            *self3.root_mut_unchecked() = root;
233
234            *self3.symbols_mut() = symtab;
235
236            self3
237        });
238
239        (tree, ctx)
240    }
241}
242
243impl Biplate<Expression> for SubModel {
244    fn biplate(&self) -> (Tree<Expression>, Box<dyn Fn(Tree<Expression>) -> Self>) {
245        // Return constraints tree and look inside symbol table.
246        let symtab_ptr = self.symbols();
247        let (symtab_tree, symtab_ctx) = <SymbolTable as Biplate<Expression>>::biplate(&symtab_ptr);
248
249        let tree = Tree::Many(VecDeque::from([
250            Tree::One(self.root().clone()),
251            symtab_tree,
252        ]));
253
254        let self2 = self.clone();
255        let ctx = Box::new(move |x| {
256            let Tree::Many(xs) = x else {
257                panic!();
258            };
259
260            let Tree::One(root) = xs[0].clone() else {
261                panic!();
262            };
263
264            let symtab = symtab_ctx(xs[1].clone());
265
266            let mut self3 = self2.clone();
267
268            let Expression::Root(_, _) = root else {
269                bug!("root expression not root");
270            };
271
272            *self3.root_mut_unchecked() = root;
273
274            *self3.symbols_mut() = symtab;
275
276            self3
277        });
278
279        (tree, ctx)
280    }
281}
282
283impl Biplate<SubModel> for SubModel {
284    fn biplate(&self) -> (Tree<SubModel>, Box<dyn Fn(Tree<SubModel>) -> Self>) {
285        (
286            Tree::One(self.clone()),
287            Box::new(move |x| {
288                let Tree::One(x) = x else {
289                    panic!();
290                };
291                x
292            }),
293        )
294    }
295}
296
297impl Biplate<Comprehension> for SubModel {
298    fn biplate(
299        &self,
300    ) -> (
301        Tree<Comprehension>,
302        Box<dyn Fn(Tree<Comprehension>) -> Self>,
303    ) {
304        let (f1_tree, f1_ctx) = <_ as Biplate<Comprehension>>::biplate(&self.constraints);
305        let (f2_tree, f2_ctx) =
306            <SymbolTable as Biplate<Comprehension>>::biplate(&self.symbols.borrow());
307
308        let tree = Tree::Many(VecDeque::from([f1_tree, f2_tree]));
309        let self2 = self.clone();
310        let ctx = Box::new(move |x| {
311            let Tree::Many(xs) = x else {
312                panic!();
313            };
314
315            let root = f1_ctx(xs[0].clone());
316            let symtab = f2_ctx(xs[1].clone());
317
318            let mut self3 = self2.clone();
319
320            let Expression::Root(_, _) = root else {
321                bug!("root expression not root");
322            };
323
324            *self3.symbols_mut() = symtab;
325            *self3.root_mut_unchecked() = root;
326
327            self3
328        });
329
330        (tree, ctx)
331    }
332}