1
use std::fmt;
2

            
3
use ahash::HashSet;
4
use merc_aterm::ATermRef;
5
use merc_aterm::Term;
6
use merc_data::DataExpressionRef;
7
use merc_data::DataFunctionSymbolRef;
8
use merc_data::DataVariableRef;
9
use merc_data::is_data_application;
10
use merc_data::is_data_function_symbol;
11
use merc_data::is_data_variable;
12
use merc_sabre::RewriteSpecification;
13
use merc_sabre::is_supported_rule;
14

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

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

            
28
impl SimpleTermFormatter<'_> {
29
    pub fn new<'a, 'b>(term: &'b impl Term<'a, 'b>) -> SimpleTermFormatter<'a> {
30
        SimpleTermFormatter { term: term.copy() }
31
    }
32
}
33

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

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

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

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

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

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

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

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

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

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

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

            
96
            variables
97
        };
98

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

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

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

            
140
        Ok(())
141
    }
142
}