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
544040
pub(super) fn submodel_ctx(
12
544040
    m: SubModel,
13
544040
) -> impl Iterator<Item = (Expression, Arc<dyn Fn(Expression) -> SubModel>)> {
14
544040
    SubmodelCtx {
15
544040
        zipper: SubmodelZipper {
16
544040
            inner: Zipper::new(m.root().clone()),
17
544040
        },
18
544040
        submodel: m.clone(),
19
544040
        done: false,
20
544040
    }
21
544040
}
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
10377710
    pub fn go_right(&mut self) -> Option<()> {
39
10377710
        self.inner.go_right()
40
10377710
    }
41

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

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

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

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

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

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

            
80
    #[doc(hidden)]
81
26550
    pub fn new(root_expression: Expression) -> Self {
82
26550
        SubmodelZipper {
83
26550
            inner: Zipper::new(root_expression),
84
26550
        }
85
26550
    }
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
10458680
    fn next(&mut self) -> Option<Self::Item> {
98
10458680
        if self.done {
99
499870
            return None;
100
9958810
        }
101
9958810
        let node = self.zipper.focus().clone();
102
9958810
        let submodel = self.submodel.clone();
103
9958810
        let zipper = self.zipper.clone();
104

            
105
        #[allow(clippy::arc_with_non_send_sync)]
106
9958810
        let ctx = Arc::new(move |x| {
107
44170
            let mut zipper2 = zipper.clone();
108
44170
            *zipper2.focus_mut() = x;
109
44170
            let root = zipper2.rebuild_root();
110
44170
            let mut submodel2 = submodel.clone();
111
44170
            submodel2.replace_root(root);
112
44170
            submodel2
113
44170
        });
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
9958810
        if self.zipper.go_down().is_none() {
118
9857070
            while self.zipper.go_right().is_none() {
119
4884730
                if self.zipper.go_up().is_none() {
120
                    // at the top again, so this will be the last time we return a node
121
500360
                    self.done = true;
122
500360
                    break;
123
4384370
                };
124
            }
125
4486110
        }
126

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