1
#![allow(dead_code)]
2
use std::sync::Arc;
3

            
4
use uniplate::zipper::Zipper;
5

            
6
use crate::ast::{Expression, SubModel};
7

            
8
/// Traverses expressions in this sub-model, but not into inner sub-models.
9
///
10
/// Same types and usage as `Biplate::contexts_bi`.
11
pub(super) fn submodel_ctx(
12
    m: SubModel,
13
) -> impl Iterator<Item = (Expression, Arc<dyn Fn(Expression) -> SubModel>)> {
14
    SubmodelCtx {
15
        zipper: SubmodelZipper {
16
            inner: Zipper::new(m.root().clone()),
17
        },
18
        submodel: m.clone(),
19
        done: false,
20
    }
21
}
22

            
23
/// A zipper that traverses over the current submodel only, and does not traverse into nested
24
/// scopes.
25
#[derive(Clone)]
26
#[doc(hidden)]
27
pub struct SubmodelZipper {
28
    inner: Zipper<Expression>,
29
}
30

            
31
impl SubmodelZipper {
32
    #[doc(hidden)]
33
    pub fn go_left(&mut self) -> Option<()> {
34
        self.inner.go_left()
35
    }
36

            
37
    #[doc(hidden)]
38
    pub fn go_right(&mut self) -> Option<()> {
39
        self.inner.go_right()
40
    }
41

            
42
    #[doc(hidden)]
43
    pub fn go_up(&mut self) -> Option<()> {
44
        self.inner.go_up()
45
    }
46

            
47
    #[doc(hidden)]
48
    pub fn rebuild_root(self) -> Expression {
49
        self.inner.rebuild_root()
50
    }
51

            
52
    #[doc(hidden)]
53
    pub fn go_down(&mut self) -> Option<()> {
54
        // do not enter things that create new submodels
55
        if matches!(
56
            self.inner.focus(),
57
            Expression::Scope(_, _) | Expression::Comprehension(_, _)
58
        ) {
59
            None
60
        } else {
61
            self.inner.go_down()
62
        }
63
    }
64

            
65
    #[doc(hidden)]
66
    pub fn focus(&self) -> &Expression {
67
        self.inner.focus()
68
    }
69

            
70
    #[doc(hidden)]
71
    pub fn replace_focus(&mut self, new_focus: Expression) -> Expression {
72
        self.inner.replace_focus(new_focus)
73
    }
74

            
75
    #[doc(hidden)]
76
    pub fn focus_mut(&mut self) -> &mut Expression {
77
        self.inner.focus_mut()
78
    }
79

            
80
    #[doc(hidden)]
81
    pub fn new(root_expression: Expression) -> Self {
82
        SubmodelZipper {
83
            inner: Zipper::new(root_expression),
84
        }
85
    }
86
}
87

            
88
pub struct SubmodelCtx {
89
    zipper: SubmodelZipper,
90
    submodel: SubModel,
91
    done: bool,
92
}
93

            
94
impl Iterator for SubmodelCtx {
95
    type Item = (Expression, Arc<dyn Fn(Expression) -> SubModel>);
96

            
97
    fn next(&mut self) -> Option<Self::Item> {
98
        if self.done {
99
            return None;
100
        }
101
        let node = self.zipper.focus().clone();
102
        let submodel = self.submodel.clone();
103
        let zipper = self.zipper.clone();
104

            
105
        #[allow(clippy::arc_with_non_send_sync)]
106
        let ctx = Arc::new(move |x| {
107
            let mut zipper2 = zipper.clone();
108
            *zipper2.focus_mut() = x;
109
            let root = zipper2.rebuild_root();
110
            let mut submodel2 = submodel.clone();
111
            submodel2.replace_root(root);
112
            submodel2
113
        });
114

            
115
        // prepare iterator for next element.
116
        // try moving down or right. if we can't move up the tree until we can move right.
117
        if self.zipper.go_down().is_none() {
118
            while self.zipper.go_right().is_none() {
119
                if self.zipper.go_up().is_none() {
120
                    // at the top again, so this will be the last time we return a node
121
                    self.done = true;
122
                    break;
123
                };
124
            }
125
        }
126

            
127
        Some((node, ctx))
128
    }
129
}