1
use std::ops::ControlFlow;
2

            
3
use merc_utilities::MercError;
4

            
5
use crate::{RegFrm, StateFrm};
6

            
7
/// Applies the given function recursively to the state formula.
8
///
9
/// The substitution function takes a state formula and returns an optional new
10
/// formula. If it returns `Some(new_formula)`, the substitution is applied and
11
/// the new formula is returned. If it returns `None`, the substitution is not
12
/// applied and the function continues to traverse the formula tree.
13
368
pub fn apply_statefrm<F>(
14
368
    formula: StateFrm,
15
368
    mut function: F,
16
368
) -> Result<StateFrm, MercError> 
17
368
    where F: FnMut(&StateFrm) -> Result<Option<StateFrm>, MercError>
18
{
19
368
    apply_statefrm_rec(formula, &mut function)
20
368
}
21

            
22
/// Visits the state formula and calls the given function on each subformula.
23
///
24
/// The visitor function takes a state formula and returns a `ControlFlow`. If
25
/// it returns `ControlFlow::Break(value)`, the traversal is stopped and the
26
/// value is returned. If it returns `ControlFlow::Continue(())`, the traversal
27
/// continues.
28
722
pub fn visit_statefrm<T>(
29
722
    formula: &StateFrm,
30
722
    mut visitor: impl FnMut(&StateFrm) -> Result<ControlFlow<T>, MercError>,
31
722
) -> Result<Option<T>, MercError> {
32
722
    visit_statefrm_rec(formula, &mut visitor)
33
722
}
34

            
35
/// See [`apply`].
36
795
fn apply_statefrm_rec<F>(
37
795
    formula: StateFrm,
38
795
    apply: &mut F,
39
795
) -> Result<StateFrm, MercError> 
40
795
    where F: FnMut(&StateFrm) -> Result<Option<StateFrm>, MercError>
41
{
42
795
    if let Some(formula) = apply(&formula)? {
43
        // A substitution was made, return the new formula.
44
6
        return Ok(formula);
45
789
    }
46

            
47
789
    match formula {
48
11
        StateFrm::Binary { op, lhs, rhs } => {
49
11
            let new_lhs = apply_statefrm_rec(*lhs, apply)?;
50
11
            let new_rhs = apply_statefrm_rec(*rhs, apply)?;
51
11
            Ok(StateFrm::Binary {
52
11
                op,
53
11
                lhs: Box::new(new_lhs),
54
11
                rhs: Box::new(new_rhs),
55
11
            })
56
        }
57
        StateFrm::FixedPoint {
58
2
            operator,
59
2
            variable,
60
2
            body,
61
        } => {
62
2
            let new_body = apply_statefrm_rec(*body, apply)?;
63
2
            Ok(StateFrm::FixedPoint {
64
2
                operator,
65
2
                variable,
66
2
                body: Box::new(new_body),
67
2
            })
68
        }
69
        StateFrm::Bound { bound, variables, body } => {
70
            let new_body = apply_statefrm_rec(*body, apply)?;
71
            Ok(StateFrm::Bound {
72
                bound,
73
                variables,
74
                body: Box::new(new_body),
75
            })
76
        }
77
        StateFrm::Modality {
78
403
            operator,
79
403
            formula,
80
403
            expr,
81
        } => {
82
403
            let expr = apply_statefrm_rec(*expr, apply)?;
83
403
            Ok(StateFrm::Modality {
84
403
                operator,
85
403
                formula,
86
403
                expr: Box::new(expr),
87
403
            })
88
        }
89
        StateFrm::Quantifier {
90
            quantifier,
91
            variables,
92
            body,
93
        } => {
94
            let new_body = apply_statefrm_rec(*body, apply)?;
95
            Ok(StateFrm::Quantifier {
96
                quantifier,
97
                variables,
98
                body: Box::new(new_body),
99
            })
100
        }
101
        StateFrm::DataValExprRightMult(expr, data_val) => {
102
            let new_expr = apply_statefrm_rec(*expr, apply)?;
103
            Ok(StateFrm::DataValExprRightMult(Box::new(new_expr), data_val))
104
        }
105
        StateFrm::DataValExprLeftMult(data_val, expr) => {
106
            let new_expr = apply_statefrm_rec(*expr, apply)?;
107
            Ok(StateFrm::DataValExprLeftMult(data_val, Box::new(new_expr)))
108
        }
109
        StateFrm::Unary { op, expr } => {
110
            let new_expr = apply_statefrm_rec(*expr, apply)?;
111
            Ok(StateFrm::Unary {
112
                op,
113
                expr: Box::new(new_expr),
114
            })
115
        }
116
        StateFrm::Id(_, _)
117
        | StateFrm::True
118
        | StateFrm::False
119
        | StateFrm::Delay(_)
120
        | StateFrm::Yaled(_)
121
373
        | StateFrm::DataValExpr(_) => Ok(formula),
122
    }
123
795
}
124

            
125
/// See [`visit`].
126
1940
fn visit_statefrm_rec<T>(
127
1940
    formula: &StateFrm,
128
1940
    function: &mut impl FnMut(&StateFrm) -> Result<ControlFlow<T>, MercError>,
129
1940
) -> Result<Option<T>, MercError> {
130
1940
    if let ControlFlow::Break(result) = function(formula)? {
131
        // The visitor requested to break the traversal.
132
        return Ok(Some(result));
133
1940
    }
134

            
135
1940
    match formula {
136
18
        StateFrm::Binary { lhs, rhs, .. } => {
137
18
            visit_statefrm_rec(lhs, function)?;
138
18
            visit_statefrm_rec(rhs, function)?;
139
        }
140
378
        StateFrm::FixedPoint { body, .. } => {
141
378
            visit_statefrm_rec(body, function)?;
142
        }
143
        StateFrm::Bound { body, .. } => {
144
            visit_statefrm_rec(body, function)?;
145
        }
146
804
        StateFrm::Modality { expr, .. } => {
147
804
            visit_statefrm_rec(expr, function)?;
148
        }
149
        StateFrm::Quantifier { body, .. } => {
150
            visit_statefrm_rec(body, function)?;
151
        }
152
        StateFrm::DataValExprRightMult(expr, _data_val) => {
153
            visit_statefrm_rec(expr, function)?;
154
        }
155
        StateFrm::DataValExprLeftMult(_data_val, expr) => {
156
            visit_statefrm_rec(expr, function)?;
157
        }
158
        StateFrm::Unary { expr, .. } => {
159
            visit_statefrm_rec(expr, function)?;
160
        }
161
        StateFrm::Id(_, _)
162
        | StateFrm::True
163
        | StateFrm::False
164
        | StateFrm::Delay(_)
165
        | StateFrm::Yaled(_)
166
740
        | StateFrm::DataValExpr(_) => {}
167
    }
168

            
169
    // The visitor did not break the traversal.
170
1940
    Ok(None)
171
1940
}
172

            
173
/// Applies the given function recursively to the regular formula. The
174
/// substitution function takes a regular formula and returns an optional new
175
/// formula. If it returns `Some(new_formula)`, the substitution is applied and
176
/// the new formula is returned. If it returns `None`, the substitution is not
177
/// applied and the function continues to traverse the formula tree.
178
pub fn apply_regular_formula<F>(
179
    formula: RegFrm,
180
    mut function: F,
181
) -> Result<RegFrm, MercError> 
182
    where F: FnMut(&RegFrm) -> Result<Option<RegFrm>, MercError>
183
{
184
    apply_regular_formula_rec(formula, &mut function)
185
}
186

            
187
/// See [apply_regular_formula].
188
fn apply_regular_formula_rec<F>(formula: RegFrm, apply: &mut F) -> Result<RegFrm, MercError> 
189
    where F: FnMut(&RegFrm) -> Result<Option<RegFrm>, MercError>
190
{
191
    if let Some(formula) = apply(&formula)? {
192
        // A substitution was made, return the new formula.
193
        return Ok(formula);
194
    }
195

            
196
    match formula {
197
        RegFrm::Iteration(reg_frm) => {
198
            let new_reg_frm = apply_regular_formula_rec(*reg_frm, apply)?;
199
            Ok(RegFrm::Iteration(Box::new(new_reg_frm)))
200
        }
201
        RegFrm::Plus(reg_frm) => {
202
            let new_reg_frm = apply_regular_formula_rec(*reg_frm, apply)?;
203
            Ok(RegFrm::Plus(Box::new(new_reg_frm)))
204
        }
205
        RegFrm::Sequence { lhs, rhs } => {
206
            let new_lhs = apply_regular_formula_rec(*lhs, apply)?;
207
            let new_rhs = apply_regular_formula_rec(*rhs, apply)?;
208
            Ok(RegFrm::Sequence {
209
                lhs: Box::new(new_lhs),
210
                rhs: Box::new(new_rhs),
211
            })
212
        }
213
        RegFrm::Choice { lhs, rhs } => {
214
            let new_lhs = apply_regular_formula_rec(*lhs, apply)?;
215
            let new_rhs = apply_regular_formula_rec(*rhs, apply)?;
216
            Ok(RegFrm::Choice {
217
                lhs: Box::new(new_lhs),
218
                rhs: Box::new(new_rhs),
219
            })
220
        }
221
        _ => Ok(formula),
222
    }
223
}
224

            
225
#[cfg(test)]
226
mod tests {
227
    use std::vec;
228

            
229
    use crate::UntypedStateFrmSpec;
230

            
231
    use super::*;
232

            
233
    #[test]
234
1
    fn test_visit_state_frm_variables() {
235
1
        let input = UntypedStateFrmSpec::parse("mu X. [a]X && mu X. X && Y").unwrap();
236

            
237
1
        let mut variables = vec![];
238
8
        apply_statefrm(input.formula, |frm| {
239
8
            if let StateFrm::Id(name, _) = frm {
240
3
                variables.push(name.clone());
241
5
            }
242

            
243
8
            Ok(None)
244
8
        })
245
1
        .unwrap();
246

            
247
1
        assert_eq!(variables, vec!["X", "X", "Y"]);
248
1
    }
249
}