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

            
4
use uniplate::zipper::Zipper;
5

            
6
use crate::ast::Expression;
7

            
8
/// Traverses expressions in a root expression tree, but not into comprehensions.
9
///
10
/// TODO: Explore whether the rewriter should traverse into comprehensions.
11
///
12
/// Same types and usage as `Biplate::contexts_bi`.
13
1392
pub(super) fn expression_ctx(
14
1392
    root_expression: Expression,
15
1392
) -> impl Iterator<Item = (Expression, Arc<dyn Fn(Expression) -> Expression>)> {
16
1392
    ExpressionCtx {
17
1392
        zipper: ExpressionZipper {
18
1392
            inner: Zipper::new(root_expression),
19
1392
        },
20
1392
        done: false,
21
1392
    }
22
1392
}
23

            
24
/// A zipper that traverses over an expression tree and does not traverse into comprehensions.
25
#[derive(Clone)]
26
#[doc(hidden)]
27
pub struct ExpressionZipper {
28
    inner: Zipper<Expression>,
29
}
30

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

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

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

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

            
52
    #[doc(hidden)]
53
1392
    pub fn go_down(&mut self) -> Option<()> {
54
        // Do not enter comprehensions.
55
1392
        if matches!(self.inner.focus(), Expression::Comprehension(_, _)) {
56
            None
57
        } else {
58
1392
            self.inner.go_down()
59
        }
60
1392
    }
61

            
62
    #[doc(hidden)]
63
1392
    pub fn focus(&self) -> &Expression {
64
1392
        self.inner.focus()
65
1392
    }
66

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

            
72
    #[doc(hidden)]
73
    pub fn focus_mut(&mut self) -> &mut Expression {
74
        self.inner.focus_mut()
75
    }
76

            
77
    #[doc(hidden)]
78
    pub fn new(root_expression: Expression) -> Self {
79
        ExpressionZipper {
80
            inner: Zipper::new(root_expression),
81
        }
82
    }
83
}
84

            
85
pub struct ExpressionCtx {
86
    zipper: ExpressionZipper,
87
    done: bool,
88
}
89

            
90
impl Iterator for ExpressionCtx {
91
    type Item = (Expression, Arc<dyn Fn(Expression) -> Expression>);
92

            
93
2784
    fn next(&mut self) -> Option<Self::Item> {
94
2784
        if self.done {
95
1392
            return None;
96
1392
        }
97
1392
        let node = self.zipper.focus().clone();
98
1392
        let zipper = self.zipper.clone();
99

            
100
        #[allow(clippy::arc_with_non_send_sync)]
101
1392
        let ctx = Arc::new(move |x| {
102
            let mut zipper2 = zipper.clone();
103
            *zipper2.focus_mut() = x;
104
            zipper2.rebuild_root()
105
        });
106

            
107
        // prepare iterator for next element.
108
        // try moving down or right. if we can't move up the tree until we can move right.
109
1392
        if self.zipper.go_down().is_none() {
110
1392
            while self.zipper.go_right().is_none() {
111
1392
                if self.zipper.go_up().is_none() {
112
                    // at the top again, so this will be the last time we return a node
113
1392
                    self.done = true;
114
1392
                    break;
115
                };
116
            }
117
        }
118

            
119
1392
        Some((node, ctx))
120
2784
    }
121
}