1
use std::fmt;
2

            
3
use ahash::HashSet;
4
use mcrl2::aterm::ATermRef;
5
use mcrl2::data::is_data_application;
6
use mcrl2::data::is_data_function_symbol;
7
use mcrl2::data::is_data_variable;
8
use mcrl2::data::DataExpressionRef;
9
use mcrl2::data::DataFunctionSymbolRef;
10
use mcrl2::data::DataVariableRef;
11
use sabre::set_automaton::is_supported_rule;
12
use sabre::RewriteSpecification;
13

            
14
/// Finds all data symbols in the term and adds them to the symbol index.
15
1252
fn find_variables(t: &DataExpressionRef<'_>, variables: &mut HashSet<String>) {
16
42706
    for child in t.iter() {
17
42706
        if is_data_variable(&child) {
18
2105
            variables.insert(DataVariableRef::from(child.copy()).name().into());
19
40601
        }
20
    }
21
1252
}
22

            
23
pub struct SimpleTermFormatter<'a> {
24
    term: ATermRef<'a>,
25
}
26

            
27
impl SimpleTermFormatter<'_> {
28
5072
    pub fn new<'b>(term: &'b ATermRef<'b>) -> SimpleTermFormatter<'b> {
29
5072
        SimpleTermFormatter { term: term.copy() }
30
5072
    }
31
}
32

            
33
impl fmt::Display for SimpleTermFormatter<'_> {
34
5072
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35
5072
        if is_data_function_symbol(&self.term) {
36
2074
            let symbol = DataFunctionSymbolRef::from(self.term.copy());
37
2074
            write!(f, "{}_{}", symbol.name(), symbol.operation_id())
38
2998
        } else if is_data_application(&self.term) {
39
1519
            let mut args = self.term.arguments();
40
1519

            
41
1519
            let head = args.next().unwrap();
42
1519
            write!(f, "{}", SimpleTermFormatter::new(&head))?;
43

            
44
1519
            let mut first = true;
45
3992
            for arg in args {
46
2473
                if !first {
47
954
                    write!(f, ", ")?;
48
                } else {
49
1519
                    write!(f, "(")?;
50
                }
51

            
52
2473
                write!(f, "{}", SimpleTermFormatter::new(&arg))?;
53
2473
                first = false;
54
            }
55

            
56
1519
            if !first {
57
1519
                write!(f, ")")?;
58
            }
59

            
60
1519
            Ok(())
61
1479
        } else if is_data_variable(&self.term) {
62
1479
            write!(f, "{}", DataVariableRef::from(self.term.copy()).name())
63
        } else {
64
            write!(f, "{}", self.term)
65
        }
66
5072
    }
67
}
68

            
69
pub struct TrsFormatter<'a> {
70
    spec: &'a RewriteSpecification,
71
}
72

            
73
impl TrsFormatter<'_> {
74
1
    pub fn new(spec: &RewriteSpecification) -> TrsFormatter {
75
1
        TrsFormatter { spec }
76
1
    }
77
}
78

            
79
impl fmt::Display for TrsFormatter<'_> {
80
1
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81
        // Find all the variables in the specification
82
1
        let variables = {
83
1
            let mut variables = HashSet::default();
84

            
85
563
            for rule in &self.spec.rewrite_rules {
86
562
                find_variables(&rule.lhs.copy(), &mut variables);
87
562
                find_variables(&rule.rhs.copy(), &mut variables);
88

            
89
626
                for cond in &rule.conditions {
90
64
                    find_variables(&cond.lhs.copy(), &mut variables);
91
64
                    find_variables(&cond.rhs.copy(), &mut variables);
92
64
                }
93
            }
94

            
95
1
            variables
96
1
        };
97
1

            
98
1
        // Print the list of variables.
99
1
        writeln!(f, "(VAR ")?;
100
31
        for var in variables {
101
30
            writeln!(f, "\t {} ", var)?;
102
        }
103
1
        writeln!(f, ") ")?;
104

            
105
        // Print the list of rules.
106
1
        writeln!(f, "(RULES ")?;
107
563
        for rule in &self.spec.rewrite_rules {
108
562
            if is_supported_rule(rule) {
109
500
                let mut output = format!(
110
500
                    "\t {} -> {}",
111
500
                    SimpleTermFormatter::new(&rule.lhs),
112
500
                    SimpleTermFormatter::new(&rule.rhs)
113
500
                );
114
540
                for cond in &rule.conditions {
115
40
                    if cond.equality {
116
40
                        output += &format!(
117
40
                            " COND ==({},{}) -> true",
118
40
                            SimpleTermFormatter::new(&cond.lhs),
119
40
                            SimpleTermFormatter::new(&cond.rhs)
120
40
                        )
121
                    } else {
122
                        output += &format!(
123
                            " COND !=({},{}) -> true",
124
                            SimpleTermFormatter::new(&cond.lhs),
125
                            SimpleTermFormatter::new(&cond.rhs)
126
                        )
127
                    };
128
                }
129

            
130
500
                writeln!(
131
500
                    f,
132
500
                    "{}",
133
500
                    output.replace('|', "bar").replace('=', "eq").replace("COND", "|")
134
500
                )?;
135
62
            }
136
        }
137
1
        writeln!(f, ")")?;
138

            
139
1
        Ok(())
140
1
    }
141
}
142

            
143
#[cfg(test)]
144
mod tests {
145
    use super::*;
146

            
147
    use mcrl2::data::DataSpecification;
148

            
149
    #[test]
150
1
    fn test_convert_trs_format() {
151
1
        // Although we do not check the output simply convert a concrete term rewrite system as test.
152
1
        let spec = DataSpecification::new(include_str!("../../../examples/REC/mcrl2/benchsym20.dataspec")).unwrap();
153
1
        let trs = RewriteSpecification::from(spec);
154
1

            
155
1
        println!("{}", TrsFormatter::new(&trs));
156
1
    }
157
}