1
use std::convert::Infallible;
2
use std::ops::ControlFlow;
3

            
4
use merc_utilities::MercError;
5

            
6
use crate::ActFrm;
7
use crate::RegFrm;
8
use crate::SortExpression;
9
use crate::StateFrm;
10

            
11
/// Visits the state formula and calls the given function on each subformula.
12
///
13
/// The visitor function takes a state formula and returns a `ControlFlow`. If
14
/// it returns `ControlFlow::Break(value)`, the traversal is stopped and the
15
/// value is returned. If it returns `ControlFlow::Continue(())`, the traversal
16
/// continues.
17
9454
pub fn visit_statefrm<T, F>(formula: &StateFrm, mut visitor: F) -> Result<Option<T>, MercError>
18
9454
where
19
9454
    F: FnMut(&StateFrm) -> Result<ControlFlow<T>, MercError>,
20
{
21
9454
    visit_statefrm_rec(formula, &mut visitor)
22
9454
}
23

            
24
/// Visits all sort expressions in the sort expression.
25
3
pub fn visit_sort_expr<T, F>(sort_expr: &SortExpression, mut visitor: F) -> Option<T>
26
3
where
27
3
    F: FnMut(&SortExpression) -> ControlFlow<T>,
28
{
29
3
    try_visit_sort_expr(sort_expr, |sort_expr| -> Result<_, Infallible> {
30
3
        Ok(visitor(sort_expr))
31
3
    })
32
3
    .expect("Inner function does not fail")
33
3
}
34

            
35
/// Visits all sort expressions in the sort expression, allowing the visitor to return an error.
36
3
pub fn try_visit_sort_expr<E, T, F>(sort_expr: &SortExpression, mut visitor: F) -> Result<Option<T>, E>
37
3
where
38
3
    F: FnMut(&SortExpression) -> Result<ControlFlow<T>, E>,
39
{
40
3
    visit_sort_expr_rec(sort_expr, &mut visitor)
41
3
}
42

            
43
/// See [`visit_statefrm`].
44
87972
fn visit_statefrm_rec<T, F>(formula: &StateFrm, function: &mut F) -> Result<Option<T>, MercError>
45
87972
where
46
87972
    F: FnMut(&StateFrm) -> Result<ControlFlow<T>, MercError>,
47
{
48
87972
    if let ControlFlow::Break(result) = function(formula)? {
49
        // The visitor requested to break the traversal.
50
1
        return Ok(Some(result));
51
87971
    }
52

            
53
87971
    match formula {
54
14678
        StateFrm::Binary { lhs, rhs, .. } => {
55
14678
            if let Some(result) = visit_statefrm_rec(lhs, function)? {
56
                return Ok(Some(result));
57
14678
            }
58
14678
            if let Some(result) = visit_statefrm_rec(rhs, function)? {
59
2
                return Ok(Some(result));
60
14676
            }
61
        }
62
10457
        StateFrm::FixedPoint { body, .. } => {
63
10457
            if let Some(result) = visit_statefrm_rec(body, function)? {
64
1
                return Ok(Some(result));
65
10456
            }
66
        }
67
        StateFrm::Bound { body, .. } => {
68
            if let Some(result) = visit_statefrm_rec(body, function)? {
69
                return Ok(Some(result));
70
            }
71
        }
72
38705
        StateFrm::Modality { expr, .. } => {
73
38705
            if let Some(result) = visit_statefrm_rec(expr, function)? {
74
                return Ok(Some(result));
75
38705
            }
76
        }
77
        StateFrm::Quantifier { body, .. } => {
78
            if let Some(result) = visit_statefrm_rec(body, function)? {
79
                return Ok(Some(result));
80
            }
81
        }
82
        StateFrm::DataValExprRightMult(expr, _data_val) => {
83
            if let Some(result) = visit_statefrm_rec(expr, function)? {
84
                return Ok(Some(result));
85
            }
86
        }
87
        StateFrm::DataValExprLeftMult(_data_val, expr) => {
88
            if let Some(result) = visit_statefrm_rec(expr, function)? {
89
                return Ok(Some(result));
90
            }
91
        }
92
        StateFrm::Unary { expr, .. } => {
93
            if let Some(result) = visit_statefrm_rec(expr, function)? {
94
                return Ok(Some(result));
95
            }
96
        }
97
        StateFrm::Id(_, _)
98
        | StateFrm::True
99
        | StateFrm::False
100
        | StateFrm::Delay(_)
101
        | StateFrm::Yaled(_)
102
24131
        | StateFrm::DataValExpr(_) => {}
103
    }
104

            
105
    // The visitor did not break the traversal.
106
87968
    Ok(None)
107
87972
}
108

            
109
/// See [`visit_sort_expr`].
110
3
fn visit_sort_expr_rec<E, T, F>(sort_expr: &SortExpression, function: &mut F) -> Result<Option<T>, E>
111
3
where
112
3
    F: FnMut(&SortExpression) -> Result<ControlFlow<T>, E>,
113
{
114
3
    if let ControlFlow::Break(result) = function(sort_expr)? {
115
        // The visitor requested to break the traversal.
116
        return Ok(Some(result));
117
3
    }
118

            
119
3
    match sort_expr {
120
        SortExpression::Product { lhs, rhs } => {
121
            if let Some(result) = visit_sort_expr_rec(lhs, function)? {
122
                return Ok(Some(result));
123
            }
124
            if let Some(result) = visit_sort_expr_rec(rhs, function)? {
125
                return Ok(Some(result));
126
            }
127
        }
128
        SortExpression::Function { domain, range } => {
129
            if let Some(result) = visit_sort_expr_rec(domain, function)? {
130
                return Ok(Some(result));
131
            }
132
            if let Some(result) = visit_sort_expr_rec(range, function)? {
133
                return Ok(Some(result));
134
            }
135
        }
136
        SortExpression::Struct { inner } => {
137
            for constructors in inner {
138
                for (_name, sort) in &constructors.args {
139
                    if let Some(result) = visit_sort_expr_rec(sort, function)? {
140
                        return Ok(Some(result));
141
                    }
142
                }
143
            }
144
        }
145
        SortExpression::Complex(_complex_sort, sort_expression) => {
146
            if let Some(result) = visit_sort_expr_rec(sort_expression, function)? {
147
                return Ok(Some(result));
148
            }
149
        }
150
        SortExpression::FlattenedFunction { domain, range } => {
151
            for domain_sort in domain {
152
                visit_sort_expr_rec(domain_sort, function)?;
153
            }
154
            visit_sort_expr_rec(range, function)?;
155
        }
156
3
        SortExpression::Reference(_) | SortExpression::Simple(_) | SortExpression::Resolved(_, _) => {}
157
    }
158

            
159
    // The visitor did not break the traversal.
160
3
    Ok(None)
161
3
}
162

            
163
/// Maps the given `function` recursively to the regular formula.
164
9673
pub fn visit_regular_formula<T, F>(formula: &RegFrm, mut function: F) -> Result<Option<T>, MercError>
165
9673
where
166
9673
    F: FnMut(&RegFrm) -> Result<ControlFlow<T>, MercError>,
167
{
168
9673
    visit_regular_formula_rec(formula, &mut function)
169
9673
}
170

            
171
/// See [visit_regular_formula].
172
14665
fn visit_regular_formula_rec<T, F>(formula: &RegFrm, visit: &mut F) -> Result<Option<T>, MercError>
173
14665
where
174
14665
    F: FnMut(&RegFrm) -> Result<ControlFlow<T>, MercError>,
175
{
176
14665
    if let ControlFlow::Break(result) = visit(formula)? {
177
        // A substitution was made, return the new formula.
178
        return Ok(Some(result));
179
14665
    }
180

            
181
14665
    match formula {
182
4992
        RegFrm::Iteration(reg_frm) => {
183
4992
            if let Some(result) = visit_regular_formula_rec(reg_frm, visit)? {
184
                return Ok(Some(result));
185
4992
            }
186
        }
187
        RegFrm::Plus(reg_frm) => {
188
            if let Some(result) = visit_regular_formula_rec(reg_frm, visit)? {
189
                return Ok(Some(result));
190
            }
191
        }
192
        RegFrm::Sequence { lhs, rhs } => {
193
            if let Some(result) = visit_regular_formula_rec(lhs, visit)? {
194
                return Ok(Some(result));
195
            }
196
            if let Some(result) = visit_regular_formula_rec(rhs, visit)? {
197
                return Ok(Some(result));
198
            }
199
        }
200
        RegFrm::Choice { lhs, rhs } => {
201
            if let Some(result) = visit_regular_formula_rec(lhs, visit)? {
202
                return Ok(Some(result));
203
            }
204
            if let Some(result) = visit_regular_formula_rec(rhs, visit)? {
205
                return Ok(Some(result));
206
            }
207
        }
208
9673
        _ => {}
209
    }
210

            
211
14665
    Ok(None)
212
14665
}
213

            
214
/// Visitor for action formulas.
215
///
216
9673
pub fn visit_action_formula<T, F>(formula: &ActFrm, mut visitor: F) -> Result<Option<T>, MercError>
217
9673
where
218
9673
    F: FnMut(&ActFrm) -> Result<ControlFlow<T>, MercError>,
219
{
220
9673
    visit_action_formula_rec(formula, &mut visitor)
221
9673
}
222

            
223
9674
fn visit_action_formula_rec<T, F>(formula: &ActFrm, visitor: &mut F) -> Result<Option<T>, MercError>
224
9674
where
225
9674
    F: FnMut(&ActFrm) -> Result<ControlFlow<T>, MercError>,
226
{
227
9674
    if let ControlFlow::Break(result) = visitor(formula)? {
228
        // The visitor requested to break the traversal.
229
        return Ok(Some(result));
230
9674
    }
231

            
232
9674
    match formula {
233
1
        ActFrm::Negation(act_frm) => {
234
1
            if let Some(result) = visit_action_formula_rec(act_frm, visitor)? {
235
                return Ok(Some(result));
236
1
            }
237
        }
238
        ActFrm::Quantifier {
239
            quantifier: _,
240
            variables: _,
241
            body,
242
        } => {
243
            if let Some(result) = visit_action_formula_rec(body, visitor)? {
244
                return Ok(Some(result));
245
            }
246
        }
247
        ActFrm::Binary { op: _, lhs, rhs } => {
248
            if let Some(result) = visit_action_formula_rec(lhs, visitor)? {
249
                return Ok(Some(result));
250
            }
251
            if let Some(result) = visit_action_formula_rec(rhs, visitor)? {
252
                return Ok(Some(result));
253
            }
254
        }
255
9673
        ActFrm::True | ActFrm::False | ActFrm::MultAct(_) | ActFrm::DataExprVal(_) => {}
256
    }
257

            
258
    // The visitor did not break the traversal.
259
9674
    Ok(None)
260
9674
}