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

            
5
use crate::bug;
6
use crate::representation::{Representation, get_repr_rule};
7
use std::any::TypeId;
8

            
9
use std::collections::BTreeSet;
10
use std::collections::VecDeque;
11
use std::hash::{Hash, Hasher};
12
use std::sync::Arc;
13
use std::sync::atomic::{AtomicU32, Ordering};
14

            
15
use super::comprehension::Comprehension;
16
use super::serde::{AsId, DefaultWithId, HasId, IdPtr, ObjId, PtrAsInner};
17
use super::{
18
    DeclarationPtr, DomainPtr, Expression, GroundDomain, Model, Moo, Name, ReturnType, Typeable,
19
};
20
use itertools::{Itertools as _, izip};
21
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
22
use serde::{Deserialize, Serialize};
23
use serde_with::serde_as;
24
use tracing::trace;
25
use uniplate::{Biplate, Tree, Uniplate};
26

            
27
use indexmap::IndexMap;
28
use indexmap::map::Entry;
29

            
30
/// Global counter of symbol tables.
31
/// Note that the counter is shared between all threads
32
/// Thus, when running multiple models in parallel, IDs may
33
/// be different with every run depending on scheduling order
34
static SYMBOL_TABLE_ID_COUNTER: AtomicU32 = const { AtomicU32::new(0) };
35

            
36
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
37
pub struct SymbolTablePtr
38
where
39
    Self: Send + Sync,
40
{
41
    inner: Arc<SymbolTablePtrInner>,
42
}
43

            
44
impl SymbolTablePtr {
45
    /// Create an empty new [SymbolTable] and return a shared pointer to it
46
116070
    pub fn new() -> Self {
47
116070
        Self::new_with_data(SymbolTable::new())
48
116070
    }
49

            
50
    /// Create an empty new [SymbolTable] with the given parent and return a shared pointer to it
51
20496
    pub fn with_parent(symbols: SymbolTablePtr) -> Self {
52
20496
        Self::new_with_data(SymbolTable::with_parent(symbols))
53
20496
    }
54

            
55
136610
    fn new_with_data(data: SymbolTable) -> Self {
56
136610
        let object_id = SYMBOL_TABLE_ID_COUNTER.fetch_add(1, Ordering::Relaxed);
57
136610
        let id = ObjId {
58
136610
            object_id,
59
136610
            type_name: SymbolTablePtr::TYPE_NAME.into(),
60
136610
        };
61
136610
        Self::new_with_id_and_data(id, data)
62
136610
    }
63

            
64
140010
    fn new_with_id_and_data(id: ObjId, data: SymbolTable) -> Self {
65
140010
        Self {
66
140010
            inner: Arc::new(SymbolTablePtrInner {
67
140010
                id,
68
140010
                value: RwLock::new(data),
69
140010
            }),
70
140010
        }
71
140010
    }
72

            
73
    /// Read the underlying symbol table.
74
    /// This will block the current thread until a read lock can be acquired.
75
    ///
76
    /// # WARNING
77
    ///
78
    /// - If the current thread already holds a lock over this table, this may deadlock.
79
389368245
    pub fn read(&self) -> RwLockReadGuard<'_, SymbolTable> {
80
389368245
        self.inner.value.read()
81
389368245
    }
82

            
83
    /// Mutate the underlying symbol table.
84
    /// This will block the current thread until an exclusive write lock can be acquired.
85
    ///
86
    /// # WARNING
87
    ///
88
    /// - If the current thread already holds a lock over this table, this may deadlock.
89
    /// - Trying to acquire any other lock until the write lock is released will cause a deadlock.
90
    /// - This will mutate the underlying data, which may be shared between other `SymbolTablePtr`s.
91
    ///   Make sure that this is what you want.
92
    ///
93
    /// To create a separate copy of the table, see [SymbolTablePtr::detach].
94
    ///
95
612659
    pub fn write(&self) -> RwLockWriteGuard<'_, SymbolTable> {
96
612659
        self.inner.value.write()
97
612659
    }
98

            
99
    /// Create a new symbol table with the same contents as this one, but a new ID,
100
    /// and return a pointer to it.
101
44
    pub fn detach(&self) -> Self {
102
44
        Self::new_with_data(self.read().clone())
103
44
    }
104
}
105

            
106
impl Default for SymbolTablePtr {
107
    fn default() -> Self {
108
        Self::new()
109
    }
110
}
111

            
112
impl HasId for SymbolTablePtr {
113
    const TYPE_NAME: &'static str = "SymbolTable";
114

            
115
625752
    fn id(&self) -> ObjId {
116
625752
        self.inner.id.clone()
117
625752
    }
118
}
119

            
120
impl DefaultWithId for SymbolTablePtr {
121
    fn default_with_id(id: ObjId) -> Self {
122
        Self::new_with_id_and_data(id, SymbolTable::default())
123
    }
124
}
125

            
126
impl IdPtr for SymbolTablePtr {
127
    type Data = SymbolTable;
128

            
129
15740
    fn get_data(&self) -> Self::Data {
130
15740
        self.read().clone()
131
15740
    }
132

            
133
3400
    fn with_id_and_data(id: ObjId, data: Self::Data) -> Self {
134
3400
        Self::new_with_id_and_data(id, data)
135
3400
    }
136
}
137

            
138
// TODO: this code is almost exactly copied from [DeclarationPtr].
139
//       It should be possible to eliminate the duplication...
140
//       Perhaps by merging SymbolTablePtr and DeclarationPtr together?
141
//       (Alternatively, a macro?)
142

            
143
impl Uniplate for SymbolTablePtr {
144
70480
    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
145
70480
        let symtab = self.read();
146
70480
        let (tree, recons) = Biplate::<SymbolTablePtr>::biplate(&symtab as &SymbolTable);
147

            
148
70480
        let self2 = self.clone();
149
        (
150
70480
            tree,
151
70480
            Box::new(move |x| {
152
                let self3 = self2.clone();
153
                *(self3.write()) = recons(x);
154
                self3
155
            }),
156
        )
157
70480
    }
158
}
159

            
160
impl<To> Biplate<To> for SymbolTablePtr
161
where
162
    SymbolTable: Biplate<To>,
163
    To: Uniplate,
164
{
165
1122452
    fn biplate(&self) -> (Tree<To>, Box<dyn Fn(Tree<To>) -> Self>) {
166
1122452
        if TypeId::of::<To>() == TypeId::of::<Self>() {
167
            unsafe {
168
70480
                let self_as_to = std::mem::transmute::<&Self, &To>(self).clone();
169
                (
170
70480
                    Tree::One(self_as_to),
171
70480
                    Box::new(move |x| {
172
                        let Tree::One(x) = x else { panic!() };
173

            
174
                        let x_as_self = std::mem::transmute::<&To, &Self>(&x);
175
                        x_as_self.clone()
176
                    }),
177
                )
178
            }
179
        } else {
180
            // call biplate on the enclosed declaration
181
1051972
            let decl = self.read();
182
1051972
            let (tree, recons) = Biplate::<To>::biplate(&decl as &SymbolTable);
183

            
184
1051972
            let self2 = self.clone();
185
            (
186
1051972
                tree,
187
1051972
                Box::new(move |x| {
188
12528
                    let self3 = self2.clone();
189
12528
                    *(self3.write()) = recons(x);
190
12528
                    self3
191
12528
                }),
192
            )
193
        }
194
1122452
    }
195
}
196

            
197
#[derive(Debug)]
198
struct SymbolTablePtrInner {
199
    id: ObjId,
200
    value: RwLock<SymbolTable>,
201
}
202

            
203
impl Hash for SymbolTablePtrInner {
204
    fn hash<H: Hasher>(&self, state: &mut H) {
205
        self.id.hash(state);
206
    }
207
}
208

            
209
impl PartialEq for SymbolTablePtrInner {
210
1700
    fn eq(&self, other: &Self) -> bool {
211
1700
        self.value.read().eq(&other.value.read())
212
1700
    }
213
}
214

            
215
impl Eq for SymbolTablePtrInner {}
216

            
217
/// The global symbol table, mapping names to their definitions.
218
///
219
/// Names in the symbol table are unique, including between different types of object stored in the
220
/// symbol table. For example, you cannot have a letting and decision variable with the same name.
221
///
222
/// # Symbol Kinds
223
///
224
/// The symbol table tracks the following types of symbol:
225
///
226
/// ## Decision Variables
227
///
228
/// ```text
229
/// find NAME: DOMAIN
230
/// ```
231
///
232
/// See [`DecisionVariable`](super::DecisionVariable).
233
///
234
/// ## Lettings
235
///
236
/// Lettings define constants, of which there are two types:
237
///
238
///   + **Constant values**: `letting val be A`, where A is an [`Expression`].
239
///
240
///     A can be any integer, boolean, or matrix expression.
241
///     A can include references to other lettings, model parameters, and, unlike Savile Row,
242
///     decision variables.
243
///
244
///   + **Constant domains**: `letting Domain be domain D`, where D is a [`Domain`].
245
///
246
///     D can include references to other lettings and model parameters, and, unlike Savile Row,
247
///     decision variables.
248
///
249
/// Unless otherwise stated, these follow the semantics specified in section 2.2.2 of the Savile
250
/// Row manual (version 1.9.1 at time of writing).
251
#[serde_as]
252
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
253
pub struct SymbolTable {
254
    #[serde_as(as = "Vec<(_,PtrAsInner)>")]
255
    table: IndexMap<Name, DeclarationPtr>,
256

            
257
    #[serde_as(as = "Option<AsId>")]
258
    parent: Option<SymbolTablePtr>,
259

            
260
    next_machine_name: i32,
261
}
262

            
263
impl SymbolTable {
264
    /// Creates an empty symbol table.
265
777542
    pub fn new() -> SymbolTable {
266
777542
        SymbolTable::new_inner(None)
267
777542
    }
268

            
269
    /// Creates an empty symbol table with the given parent.
270
20496
    pub fn with_parent(parent: SymbolTablePtr) -> SymbolTable {
271
20496
        SymbolTable::new_inner(Some(parent))
272
20496
    }
273

            
274
798038
    fn new_inner(parent: Option<SymbolTablePtr>) -> SymbolTable {
275
798038
        let id = SYMBOL_TABLE_ID_COUNTER.fetch_add(1, Ordering::Relaxed);
276
798038
        trace!(
277
            "new symbol table: id = {id}  parent_id = {}",
278
7860
            parent
279
7860
                .as_ref()
280
7860
                .map(|x| x.id().to_string())
281
7860
                .unwrap_or(String::from("none"))
282
        );
283
798038
        SymbolTable {
284
798038
            table: IndexMap::new(),
285
798038
            next_machine_name: 0,
286
798038
            parent,
287
798038
        }
288
798038
    }
289

            
290
    /// Looks up the declaration with the given name in the current scope only.
291
    ///
292
    /// Returns `None` if there is no declaration with that name in the current scope.
293
1229287570
    pub fn lookup_local(&self, name: &Name) -> Option<DeclarationPtr> {
294
1229287570
        self.table.get(name).cloned()
295
1229287570
    }
296

            
297
    /// Looks up the declaration with the given name, checking all enclosing scopes.
298
    ///
299
    /// Returns `None` if there is no declaration with that name in scope.
300
1228968154
    pub fn lookup(&self, name: &Name) -> Option<DeclarationPtr> {
301
1228968154
        self.lookup_local(name).or_else(|| {
302
1629104
            self.parent
303
1629104
                .as_ref()
304
1629104
                .and_then(|parent| parent.read().lookup(name))
305
1629104
        })
306
1228968154
    }
307

            
308
    /// Inserts a declaration into the symbol table.
309
    ///
310
    /// Returns `None` if there is already a symbol with this name in the local scope.
311
7227171
    pub fn insert(&mut self, declaration: DeclarationPtr) -> Option<()> {
312
7227171
        let name = declaration.name().clone();
313
7227171
        if let Entry::Vacant(e) = self.table.entry(name) {
314
3716551
            e.insert(declaration);
315
3716551
            Some(())
316
        } else {
317
3510620
            None
318
        }
319
7227171
    }
320

            
321
    /// Updates or adds a declaration in the immediate local scope.
322
201764
    pub fn update_insert(&mut self, declaration: DeclarationPtr) {
323
201764
        let name = declaration.name().clone();
324
201764
        self.table.insert(name, declaration);
325
201764
    }
326

            
327
    /// Looks up the return type for name if it has one and is in scope.
328
    pub fn return_type(&self, name: &Name) -> Option<ReturnType> {
329
        self.lookup(name).map(|x| x.return_type())
330
    }
331

            
332
    /// Looks up the return type for name if has one and is in the local scope.
333
    pub fn return_type_local(&self, name: &Name) -> Option<ReturnType> {
334
        self.lookup_local(name).map(|x| x.return_type())
335
    }
336

            
337
    /// Looks up the domain of name if it has one and is in scope.
338
    ///
339
    /// This method can return domain references: if a ground domain is always required, use
340
    /// [`SymbolTable::resolve_domain`].
341
962812
    pub fn domain(&self, name: &Name) -> Option<DomainPtr> {
342
962812
        if let Name::WithRepresentation(name, _) = name {
343
195676
            self.lookup(name)?.domain()
344
        } else {
345
767136
            self.lookup(name)?.domain()
346
        }
347
962812
    }
348

            
349
    /// Looks up the domain of name, resolving domain references to ground domains.
350
    ///
351
    /// See [`SymbolTable::domain`].
352
962812
    pub fn resolve_domain(&self, name: &Name) -> Option<Moo<GroundDomain>> {
353
962812
        self.domain(name)?.resolve().ok()
354
962812
    }
355

            
356
    /// Iterates over entries in the LOCAL symbol table.
357
23712470
    pub fn into_iter_local(self) -> impl Iterator<Item = (Name, DeclarationPtr)> {
358
23712470
        self.table.into_iter()
359
23712470
    }
360

            
361
    /// Iterates over entries in the LOCAL symbol table, by reference.
362
936916
    pub fn iter_local(&self) -> impl Iterator<Item = (&Name, &DeclarationPtr)> {
363
936916
        self.table.iter()
364
936916
    }
365

            
366
    /// Iterates over entries in the LOCAL symbol table, by reference.
367
    pub fn iter_local_mut(&mut self) -> impl Iterator<Item = (&Name, &mut DeclarationPtr)> {
368
        self.table.iter_mut()
369
    }
370

            
371
    /// Extends the symbol table with the given symbol table, updating the gensym counter if
372
    /// necessary.
373
661824
    pub fn extend(&mut self, other: SymbolTable) {
374
661824
        if other.table.keys().count() > self.table.keys().count() {
375
161112
            let new_vars = other.table.keys().collect::<BTreeSet<_>>();
376
161112
            let old_vars = self.table.keys().collect::<BTreeSet<_>>();
377

            
378
3763348
            for added_var in new_vars.difference(&old_vars) {
379
3763348
                let next_var = &mut self.next_machine_name;
380
3763348
                if let Name::Machine(m) = *added_var
381
3562052
                    && *m >= *next_var
382
3562052
                {
383
3562052
                    *next_var = *m + 1;
384
3562116
                }
385
            }
386
500712
        }
387

            
388
661824
        self.table.extend(other.table);
389
661824
    }
390

            
391
    /// Creates a new find declaration in this symbol table with a unique name, and returns its
392
    /// declaration.
393
3587044
    pub fn gen_find(&mut self, domain: &DomainPtr) -> DeclarationPtr {
394
3587044
        let decl = DeclarationPtr::new_find(self.gen_sym(), domain.clone());
395
3587044
        self.insert(decl.clone());
396
3587044
        decl
397
3587044
    }
398

            
399
    // Reserves a unique machine name in the symbol table
400
3587056
    pub fn gen_sym(&mut self) -> Name {
401
3587056
        let num = self.next_machine_name;
402
3587056
        self.next_machine_name += 1;
403
3587056
        Name::Machine(num)
404
3587056
    }
405

            
406
    /// Gets the parent of this symbol table as a mutable reference.
407
    ///
408
    /// This function provides no sanity checks.
409
3400
    pub fn parent_mut_unchecked(&mut self) -> &mut Option<SymbolTablePtr> {
410
3400
        &mut self.parent
411
3400
    }
412

            
413
    /// Gets the parent of this symbol table.
414
592824
    pub fn parent(&self) -> &Option<SymbolTablePtr> {
415
592824
        &self.parent
416
592824
    }
417

            
418
    /// Gets the representation `representation` for `name`.
419
    ///
420
    /// # Returns
421
    ///
422
    /// + `None` if `name` does not exist, is not a decision variable, or does not have that representation.
423
111624
    pub fn get_representation(
424
111624
        &self,
425
111624
        name: &Name,
426
111624
        representation: &[&str],
427
111624
    ) -> Option<Vec<Box<dyn Representation>>> {
428
        // TODO: move representation stuff to declaration / variable to avoid cloning? (we have to
429
        // move inside of an rc here, so cannot return borrows)
430
        //
431
        // Also would prevent constant "does exist" "is var" checks.
432
        //
433
        // The reason it is not there now is because I'm getting serde issues...
434
        //
435
        // Also might run into issues putting get_or_add into declaration/variable, as that
436
        // requires us to mutably borrow both the symbol table, and the variable inside the symbol
437
        // table..
438

            
439
111624
        let decl = self.lookup(name)?;
440
109224
        let var = &decl.as_find()?;
441

            
442
109224
        var.representations
443
109224
            .iter()
444
109224
            .find(|x| &x.iter().map(|r| r.repr_name()).collect_vec()[..] == representation)
445
109224
            .cloned()
446
111624
    }
447

            
448
    /// Gets all initialised representations for `name`.
449
    ///
450
    /// # Returns
451
    ///
452
    /// + `None` if `name` does not exist, or is not a decision variable.
453
5259152
    pub fn representations_for(&self, name: &Name) -> Option<Vec<Vec<Box<dyn Representation>>>> {
454
5259152
        let decl = self.lookup(name)?;
455
5259152
        decl.as_find().map(|x| x.representations.clone())
456
5259152
    }
457

            
458
    /// Gets the representation `representation` for `name`, creating it if it does not exist.
459
    ///
460
    /// If the representation does not exist, this method initialises the representation in this
461
    /// symbol table, adding the representation to `name`, and the declarations for the represented
462
    /// variables to the symbol table.
463
    ///
464
    /// # Usage
465
    ///
466
    /// Representations for variable references should be selected and created by the
467
    /// `select_representation` rule. Therefore, this method should not be used in other rules.
468
    /// Consider using [`get_representation`](`SymbolTable::get_representation`) instead.
469
    ///
470
    /// # Returns
471
    ///
472
    /// + `None` if `name` does not exist, is not a decision variable, or cannot be given that
473
    ///   representation.
474
267288
    pub fn get_or_add_representation(
475
267288
        &mut self,
476
267288
        name: &Name,
477
267288
        representation: &[&str],
478
267288
    ) -> Option<Vec<Box<dyn Representation>>> {
479
        // Lookup the declaration reference
480
267288
        let mut decl = self.lookup(name)?;
481

            
482
257448
        if let Some(var) = decl.as_find()
483
257448
            && let Some(existing_reprs) = var
484
257448
                .representations
485
257448
                .iter()
486
257448
                .find(|x| &x.iter().map(|r| r.repr_name()).collect_vec()[..] == representation)
487
257448
                .cloned()
488
        {
489
225284
            return Some(existing_reprs); // Found: return early
490
32164
        }
491
        // Representation not found
492

            
493
        // TODO: nested representations logic...
494
32164
        if representation.len() != 1 {
495
            bug!("nested representations not implemented")
496
32164
        }
497
32164
        let repr_name_str = representation[0];
498
32164
        let repr_init_fn = get_repr_rule(repr_name_str)?;
499

            
500
32164
        let reprs = vec![repr_init_fn(name, self)?];
501

            
502
        // Get mutable access to the variable part
503
32164
        let mut var = decl.as_find_mut()?;
504

            
505
32164
        for repr_instance in &reprs {
506
32164
            repr_instance
507
32164
                .declaration_down()
508
32164
                .ok()?
509
32164
                .into_iter()
510
199156
                .for_each(|x| self.update_insert(x));
511
        }
512

            
513
32164
        var.representations.push(reprs.clone());
514

            
515
32164
        Some(reprs)
516
267288
    }
517
}
518

            
519
impl IntoIterator for SymbolTable {
520
    type Item = (Name, DeclarationPtr);
521

            
522
    type IntoIter = SymbolTableIter;
523

            
524
    /// Iterates over symbol table entries in scope.
525
77524
    fn into_iter(self) -> Self::IntoIter {
526
77524
        SymbolTableIter {
527
77524
            inner: self.table.into_iter(),
528
77524
            parent: self.parent,
529
77524
        }
530
77524
    }
531
}
532

            
533
/// Iterator over all symbol table entries in scope.
534
pub struct SymbolTableIter {
535
    // iterator over the current scopes' btreemap
536
    inner: indexmap::map::IntoIter<Name, DeclarationPtr>,
537

            
538
    // the parent scope
539
    parent: Option<SymbolTablePtr>,
540
}
541

            
542
impl Iterator for SymbolTableIter {
543
    type Item = (Name, DeclarationPtr);
544

            
545
4803456
    fn next(&mut self) -> Option<Self::Item> {
546
4803456
        let mut val = self.inner.next();
547

            
548
        // Go up the tree until we find a parent symbol table with declarations to iterate over.
549
        //
550
        // Note that the parent symbol table may be empty - this is why this is a loop!
551
4803456
        while val.is_none() {
552
77524
            let parent = self.parent.clone()?;
553

            
554
            let guard = parent.read();
555
            self.inner = guard.table.clone().into_iter();
556
            self.parent.clone_from(&guard.parent);
557

            
558
            val = self.inner.next();
559
        }
560

            
561
4725932
        val
562
4803456
    }
563
}
564

            
565
impl Default for SymbolTable {
566
    fn default() -> Self {
567
        Self::new_inner(None)
568
    }
569
}
570

            
571
// TODO: if we could override `Uniplate` impl but still derive `Biplate` instances,
572
//       we could remove some of this manual code
573
impl Uniplate for SymbolTable {
574
    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
575
        // do not recurse up parents, that would be weird?
576
        let self2 = self.clone();
577
        (Tree::Zero, Box::new(move |_| self2.clone()))
578
    }
579
}
580

            
581
impl Biplate<SymbolTablePtr> for SymbolTable {
582
70480
    fn biplate(
583
70480
        &self,
584
70480
    ) -> (
585
70480
        Tree<SymbolTablePtr>,
586
70480
        Box<dyn Fn(Tree<SymbolTablePtr>) -> Self>,
587
70480
    ) {
588
70480
        let self2 = self.clone();
589
70480
        (Tree::Zero, Box::new(move |_| self2.clone()))
590
70480
    }
591
}
592

            
593
impl Biplate<Expression> for SymbolTable {
594
1436332
    fn biplate(&self) -> (Tree<Expression>, Box<dyn Fn(Tree<Expression>) -> Self>) {
595
1436332
        let (child_trees, ctxs): (VecDeque<_>, Vec<_>) = self
596
1436332
            .table
597
1436332
            .values()
598
1436332
            .map(Biplate::<Expression>::biplate)
599
1436332
            .unzip();
600

            
601
1436332
        let tree = Tree::Many(child_trees);
602

            
603
1436332
        let self2 = self.clone();
604
1436332
        let ctx = Box::new(move |tree| {
605
12528
            let Tree::Many(exprs) = tree else {
606
                panic!("unexpected children structure");
607
            };
608

            
609
12528
            let mut self3 = self2.clone();
610
12528
            let self3_iter = self3.table.iter_mut();
611
41324
            for (ctx, tree, (_, decl)) in izip!(&ctxs, exprs, self3_iter) {
612
                // update declaration inside the pointer instead of creating a new one, so all
613
                // things referencing this keep referencing this.
614
41324
                *decl = ctx(tree)
615
            }
616

            
617
12528
            self3
618
12528
        });
619

            
620
1436332
        (tree, ctx)
621
1436332
    }
622
}
623

            
624
impl Biplate<Comprehension> for SymbolTable {
625
400
    fn biplate(
626
400
        &self,
627
400
    ) -> (
628
400
        Tree<Comprehension>,
629
400
        Box<dyn Fn(Tree<Comprehension>) -> Self>,
630
400
    ) {
631
400
        let (expr_tree, expr_ctx) = <SymbolTable as Biplate<Expression>>::biplate(self);
632

            
633
400
        let (exprs, recons_expr_tree) = expr_tree.list();
634

            
635
400
        let (comprehension_tree, comprehension_ctx) =
636
400
            <VecDeque<Expression> as Biplate<Comprehension>>::biplate(&exprs);
637

            
638
400
        let ctx = Box::new(move |x| {
639
            // 1. turn comprehension tree into a list of expressions
640
400
            let exprs = comprehension_ctx(x);
641

            
642
            // 2. turn list of expressions into an expression tree
643
400
            let expr_tree = recons_expr_tree(exprs);
644

            
645
            // 3. turn expression tree into a symbol table
646
400
            expr_ctx(expr_tree)
647
400
        });
648

            
649
400
        (comprehension_tree, ctx)
650
400
    }
651
}
652

            
653
impl Biplate<Model> for SymbolTable {
654
    // walk into expressions
655
    fn biplate(&self) -> (Tree<Model>, Box<dyn Fn(Tree<Model>) -> Self>) {
656
        let (expr_tree, expr_ctx) = <SymbolTable as Biplate<Expression>>::biplate(self);
657

            
658
        let (exprs, recons_expr_tree) = expr_tree.list();
659

            
660
        let (submodel_tree, submodel_ctx) =
661
            <VecDeque<Expression> as Biplate<Model>>::biplate(&exprs);
662

            
663
        let ctx = Box::new(move |x| {
664
            // 1. turn submodel tree into a list of expressions
665
            let exprs = submodel_ctx(x);
666

            
667
            // 2. turn list of expressions into an expression tree
668
            let expr_tree = recons_expr_tree(exprs);
669

            
670
            // 3. turn expression tree into a symbol table
671
            expr_ctx(expr_tree)
672
        });
673
        (submodel_tree, ctx)
674
    }
675
}