1
//! Serializes a rewrite specification to the AProVE TRS format.
2
//! Format reference: https://aprove.informatik.rwth-aachen.de/help_new/trs.html
3

            
4
use std::fmt;
5

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

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

            
27
pub struct SimpleTermFormatter<'a> {
28
    term: ATermRef<'a>,
29
}
30

            
31
impl SimpleTermFormatter<'_> {
32
    pub fn new<'a, 'b, T: Term<'a, 'b>>(term: &'b T) -> SimpleTermFormatter<'a> {
33
        SimpleTermFormatter { term: term.copy() }
34
    }
35
}
36

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

            
45
            let head = args.next().unwrap();
46
            write!(f, "{}", SimpleTermFormatter::new(&head))?;
47

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

            
56
                write!(f, "{}", SimpleTermFormatter::new(&arg))?;
57
                first = false;
58
            }
59

            
60
            if !first {
61
                write!(f, ")")?;
62
            }
63

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

            
73
pub struct TrsFormatter<'a> {
74
    spec: &'a RewriteSpecification,
75
}
76

            
77
impl TrsFormatter<'_> {
78
    pub fn new(spec: &RewriteSpecification) -> TrsFormatter<'_> {
79
        TrsFormatter { spec }
80
    }
81
}
82

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

            
89
            for rule in self.spec.rewrite_rules().iter() {
90
                find_variables(&rule.lhs.copy(), &mut variables);
91
                find_variables(&rule.rhs.copy(), &mut variables);
92

            
93
                for cond in &rule.conditions {
94
                    find_variables(&cond.lhs.copy(), &mut variables);
95
                    find_variables(&cond.rhs.copy(), &mut variables);
96
                }
97
            }
98

            
99
            variables
100
        };
101

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

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

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

            
143
        Ok(())
144
    }
145
}