1
//! The symbol table.
2
//!
3
//! See the item documentation for [`SymbolTable`] for more details.
4

            
5
use super::serde::{RcRefCellAsId, RcRefCellAsInner};
6
use std::cell::RefCell;
7
use std::collections::btree_map::Entry;
8
use std::collections::BTreeSet;
9
use std::collections::{BTreeMap, VecDeque};
10
use std::rc::Rc;
11
use std::sync::atomic::{AtomicU32, Ordering};
12

            
13
use super::declaration::Declaration;
14
use super::serde::{DefaultWithId, HasId, ObjId};
15
use super::types::Typeable;
16
use itertools::izip;
17
use serde::{Deserialize, Serialize};
18
use serde_with::serde_as;
19
use uniplate::Tree;
20
use uniplate::{Biplate, Uniplate};
21

            
22
use super::name::Name;
23
use super::{Domain, Expression, ReturnType, SubModel};
24
use derivative::Derivative;
25

            
26
// Count symbol tables per thread / model.
27
//
28
// We run tests in parallel and having the id's be per thread keeps them more deterministic in the
29
// JSON output. If this were not thread local, ids would be given to symbol tables differently in
30
// each test run (depending on how the threads were scheduled). These id changes would result in
31
// all the generated tests "changing" each time `ACCEPT=true cargo test` is ran.
32
//
33
// SAFETY: Symbol tables use Rc<RefCell<<>>, so a model is not thread-safe anyways.
34
thread_local! {
35
static ID_COUNTER: AtomicU32 = const { AtomicU32::new(0) };
36
}
37

            
38
/// The global symbol table, mapping names to their definitions.
39
///
40
/// Names in the symbol table are unique, including between different types of object stored in the
41
/// symbol table. For example, you cannot have a letting and decision variable with the same name.
42
///
43
/// # Symbol Kinds
44
///
45
/// The symbol table tracks the following types of symbol:
46
///
47
/// ## Decision Variables
48
///
49
/// ```text
50
/// find NAME: DOMAIN
51
/// ```
52
///
53
/// See [`DecisionVariable`](super::DecisionVariable).
54
///
55
/// ## Lettings
56
///
57
/// Lettings define constants, of which there are two types:
58
///
59
///   + **Constant values**: `letting val be A`, where A is an [`Expression`].
60
///
61
///     A can be any integer, boolean, or matrix expression.
62
///     A can include references to other lettings, model parameters, and, unlike Savile Row,
63
///     decision variables.
64
///
65
///   + **Constant domains**: `letting Domain be domain D`, where D is a [`Domain`].
66
///
67
///     D can include references to other lettings and model parameters, and, unlike Savile Row,
68
///     decision variables.
69
///
70
/// Unless otherwise stated, these follow the semantics specified in section 2.2.2 of the Savile
71
/// Row manual (version 1.9.1 at time of writing).
72
#[derive(Derivative)]
73
#[derivative(PartialEq)]
74
#[derive(Debug, Eq)]
75
#[serde_as]
76
#[derive(Serialize, Deserialize)]
77
pub struct SymbolTable {
78
    #[serde_as(as = "Vec<(_,RcRefCellAsInner)>")]
79
    table: BTreeMap<Name, Rc<Declaration>>,
80

            
81
    /// A unique id for this symbol table, for serialisation and debugging.
82
    #[derivative(PartialEq = "ignore")] // eq by value not id.
83
    id: ObjId,
84

            
85
    #[serde_as(as = "Option<RcRefCellAsId>")]
86
    parent: Option<Rc<RefCell<SymbolTable>>>,
87

            
88
    next_machine_name: RefCell<i32>,
89
}
90

            
91
impl SymbolTable {
92
    /// Creates an empty symbol table.
93
29635
    pub fn new() -> SymbolTable {
94
29635
        SymbolTable::new_inner(None)
95
29635
    }
96

            
97
    /// Creates an empty symbol table with the given parent.
98
    pub fn with_parent(parent: Rc<RefCell<SymbolTable>>) -> SymbolTable {
99
        SymbolTable::new_inner(Some(parent))
100
    }
101

            
102
29635
    fn new_inner(parent: Option<Rc<RefCell<SymbolTable>>>) -> SymbolTable {
103
29635
        let id = ID_COUNTER.with(|x| x.fetch_add(1, Ordering::Relaxed));
104
29635
        SymbolTable {
105
29635
            id,
106
29635
            table: BTreeMap::new(),
107
29635
            next_machine_name: RefCell::new(0),
108
29635
            parent,
109
29635
        }
110
29635
    }
111

            
112
    /// Looks up the declaration with the given name in the current scope only.
113
    ///
114
    /// Returns `None` if there is no declaration with that name in the current scope.
115
88548
    pub fn lookup_local(&self, name: &Name) -> Option<Rc<Declaration>> {
116
88548
        self.table.get(name).cloned()
117
88548
    }
118

            
119
    /// Looks up the declaration with the given name, checking all enclosing scopes.
120
    ///
121
    /// Returns `None` if there is no declaration with that name in scope.
122
88548
    pub fn lookup(&self, name: &Name) -> Option<Rc<Declaration>> {
123
88548
        self.lookup_local(name).or_else(|| {
124
253
            self.parent
125
253
                .as_ref()
126
253
                .and_then(|parent| (*parent).borrow().lookup(name))
127
88548
        })
128
88548
    }
129

            
130
    /// Inserts a declaration into the symbol table.
131
    ///
132
    /// Returns `None` if there is already a symbol with this name in the local scope.
133
8121
    pub fn insert(&mut self, declaration: Rc<Declaration>) -> Option<()> {
134
8121
        let name = declaration.name().clone();
135
8121
        if let Entry::Vacant(e) = self.table.entry(name) {
136
8121
            e.insert(declaration);
137
8121
            Some(())
138
        } else {
139
            None
140
        }
141
8121
    }
142

            
143
    /// Updates or adds a declaration in the immediate local scope.
144
5184360
    pub fn update_insert(&mut self, declaration: Rc<Declaration>) {
145
5184360
        let name = declaration.name().clone();
146
5184360
        self.table.insert(name, declaration);
147
5184360
    }
148

            
149
    /// Looks up the return type for name if it has one and is in scope.
150
    pub fn return_type(&self, name: &Name) -> Option<ReturnType> {
151
        self.lookup(name).and_then(|x| x.return_type())
152
    }
153

            
154
    /// Looks up the return type for name if has one and is in the local scope.
155
    pub fn return_type_local(&self, name: &Name) -> Option<ReturnType> {
156
        self.lookup_local(name).and_then(|x| x.return_type())
157
    }
158

            
159
    /// Looks up the domain of name if it has one and is in scope.
160
    ///
161
    /// This method can return domain references: if a ground domain is always required, use
162
    /// [`SymbolTable::resolve_domain`].
163
4632
    pub fn domain(&self, name: &Name) -> Option<Domain> {
164
        // TODO: do not clone here: in the future, we might want to wrap all domains in Rc's to get
165
        // clone-on-write behaviour (saving memory in scenarios such as matrix decomposition where
166
        // a lot of the domains would be the same).
167
4632
        let decl = self.lookup(name)?;
168

            
169
4631
        decl.domain().cloned()
170
4632
    }
171

            
172
    /// Looks up the domain of name, resolving domain references to ground domains.
173
    ///
174
    /// See [`SymbolTable::domain`].
175
4344
    pub fn resolve_domain(&self, name: &Name) -> Option<Domain> {
176
4344
        match self.domain(name) {
177
288
            Some(Domain::DomainReference(name)) => self
178
288
                .lookup(&name)
179
288
                .and_then(|decl| decl.as_domain_letting().cloned()),
180
4056
            result => result,
181
        }
182
4344
    }
183

            
184
    /// Iterates over entries in the local symbol table only.
185
40860
    pub fn into_iter_local(self) -> LocalIntoIter {
186
40860
        LocalIntoIter {
187
40860
            inner: self.table.into_iter(),
188
40860
        }
189
40860
    }
190

            
191
    /// Extends the symbol table with the given symbol table, updating the gensym counter if
192
    /// necessary.
193
17784
    pub fn extend(&mut self, other: SymbolTable) {
194
17784
        if other.table.keys().count() > self.table.keys().count() {
195
1296
            let new_vars = other.table.keys().collect::<BTreeSet<_>>();
196
1296
            let old_vars = self.table.keys().collect::<BTreeSet<_>>();
197

            
198
1440
            for added_var in new_vars.difference(&old_vars) {
199
1440
                let mut next_var = self.next_machine_name.borrow_mut();
200
1440
                match *added_var {
201
                    Name::UserName(_) => {}
202
1440
                    Name::MachineName(m) => {
203
1440
                        if *m >= *next_var {
204
1440
                            *next_var = *m + 1;
205
1440
                        }
206
                    }
207
                }
208
            }
209
16488
        }
210

            
211
17784
        self.table.extend(other.table);
212
17784
    }
213

            
214
    /// Returns an arbitrary variable name that is not in the symbol table.
215
2898
    pub fn gensym(&self) -> Name {
216
2898
        let num = *self.next_machine_name.borrow();
217
2898
        *(self.next_machine_name.borrow_mut()) += 1;
218
2898
        Name::MachineName(num) // incremented when inserted
219
2898
    }
220

            
221
    /// Gets the parent of this symbol table as a mutable reference.
222
    ///
223
    /// This function provides no sanity checks.
224
5382
    pub fn parent_mut_unchecked(&mut self) -> &mut Option<Rc<RefCell<SymbolTable>>> {
225
5382
        &mut self.parent
226
5382
    }
227
}
228

            
229
impl IntoIterator for SymbolTable {
230
    type Item = (Name, Rc<Declaration>);
231

            
232
    type IntoIter = IntoIter;
233

            
234
    /// Iterates over symbol table entries in scope.
235
285786
    fn into_iter(self) -> Self::IntoIter {
236
285786
        IntoIter {
237
285786
            inner: self.table.into_iter(),
238
285786
            parent: self.parent,
239
285786
        }
240
285786
    }
241
}
242

            
243
/// Iterator over symbol table entries in the current scope only.
244
pub struct LocalIntoIter {
245
    // iterator over the btreemap
246
    inner: std::collections::btree_map::IntoIter<Name, Rc<Declaration>>,
247
}
248

            
249
impl Iterator for LocalIntoIter {
250
    type Item = (Name, Rc<Declaration>);
251

            
252
177588
    fn next(&mut self) -> Option<Self::Item> {
253
177588
        self.inner.next()
254
177588
    }
255
}
256

            
257
/// Iterator over all symbol table entries in scope.
258
pub struct IntoIter {
259
    // iterator over the current scopes' btreemap
260
    inner: std::collections::btree_map::IntoIter<Name, Rc<Declaration>>,
261

            
262
    // the parent scope
263
    parent: Option<Rc<RefCell<SymbolTable>>>,
264
}
265

            
266
impl Iterator for IntoIter {
267
    type Item = (Name, Rc<Declaration>);
268

            
269
5474718
    fn next(&mut self) -> Option<Self::Item> {
270
5474718
        let mut val = self.inner.next();
271

            
272
        // Go up the tree until we find a parent symbol table with declarations to iterate over.
273
        //
274
        // Note that the parent symbol table may be empty - this is why this is a loop!
275
5474718
        while val.is_none() {
276
285768
            let parent = self.parent.clone()?;
277
            let parent_ref = (*parent).borrow();
278
            self.parent = parent_ref.parent.clone();
279
            self.inner = parent_ref.table.clone().into_iter();
280

            
281
            val = self.inner.next();
282
        }
283

            
284
5188950
        val
285
5474718
    }
286
}
287

            
288
impl HasId for SymbolTable {
289
5382
    fn id(&self) -> ObjId {
290
5382
        self.id
291
5382
    }
292
}
293

            
294
impl DefaultWithId for SymbolTable {
295
    fn default_with_id(id: ObjId) -> Self {
296
        Self {
297
            table: BTreeMap::new(),
298
            id,
299
            parent: None,
300
            next_machine_name: RefCell::new(0),
301
        }
302
    }
303
}
304

            
305
impl Clone for SymbolTable {
306
706122
    fn clone(&self) -> Self {
307
706122
        Self {
308
706122
            table: self.table.clone(),
309
706122
            id: ID_COUNTER.with(|x| x.fetch_add(1, Ordering::Relaxed)),
310
706122
            parent: self.parent.clone(),
311
706122
            next_machine_name: self.next_machine_name.clone(),
312
706122
        }
313
706122
    }
314
}
315

            
316
impl Default for SymbolTable {
317
    fn default() -> Self {
318
        Self::new_inner(None)
319
    }
320
}
321

            
322
impl Uniplate for SymbolTable {
323
    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
324
        // do not recurse up parents, that would be weird?
325
        let self2 = self.clone();
326
        (Tree::Zero, Box::new(move |_| self2.clone()))
327
    }
328
}
329

            
330
impl Biplate<Expression> for SymbolTable {
331
24984
    fn biplate(&self) -> (Tree<Expression>, Box<dyn Fn(Tree<Expression>) -> Self>) {
332
24984
        let (child_trees, ctxs): (VecDeque<_>, Vec<_>) = self
333
24984
            .table
334
24984
            .values()
335
129006
            .map(|decl| <Declaration as Biplate<Expression>>::biplate(decl.as_ref()))
336
24984
            .unzip();
337
24984

            
338
24984
        let tree = Tree::Many(child_trees);
339
24984

            
340
24984
        let self2 = self.clone();
341
24984
        let ctx = Box::new(move |tree| {
342
            let Tree::Many(exprs) = tree else {
343
                panic!("unexpected children structure");
344
            };
345

            
346
            let mut self3 = self2.clone();
347
            let self3_iter = self3.table.iter_mut();
348
            for (ctx, tree, (_, decl)) in izip!(&ctxs, exprs, self3_iter) {
349
                // update declaration inside the pointer instead of creating a new one, so all
350
                // things referencing this keep referencing this.
351
                *decl = Rc::new(ctx(tree));
352
            }
353

            
354
            self3
355
24984
        });
356
24984

            
357
24984
        (tree, ctx)
358
24984
    }
359
}
360

            
361
impl Biplate<SubModel> for SymbolTable {
362
    // walk into expressions
363
24984
    fn biplate(&self) -> (Tree<SubModel>, Box<dyn Fn(Tree<SubModel>) -> Self>) {
364
24984
        let (exprs, exprs_ctx) = <SymbolTable as Biplate<Expression>>::biplate(self);
365
24984
        let (submodel_tree, submodel_ctx) =
366
24984
            <VecDeque<Expression> as Biplate<SubModel>>::biplate(&exprs.into_iter().collect());
367
24984

            
368
24984
        let ctx = Box::new(move |x| {
369
            exprs_ctx(Tree::Many(
370
                submodel_ctx(x).into_iter().map(Tree::One).collect(),
371
            ))
372
24984
        });
373
24984
        (submodel_tree, ctx)
374
24984
    }
375
}