1
use core::fmt;
2

            
3
use ahash::AHashSet;
4
use merc_aterm::ATerm;
5
use merc_data::to_untyped_data_expression;
6
use merc_sabre::Condition;
7
use merc_sabre::RewriteSpecification;
8
use merc_sabre::Rule;
9

            
10
/// A rewrite specification contains all the bare info we need for rewriting (in particular no type information) as a syntax tree.
11
/// Parsing a REC file results in a RewriteSpecificationSyntax.
12
#[derive(Clone, Default, Debug)]
13
pub struct RewriteSpecificationSyntax {
14
    pub rewrite_rules: Vec<RewriteRuleSyntax>,
15
    pub constructors: Vec<(String, usize)>,
16
    pub variables: Vec<String>,
17
}
18

            
19
impl RewriteSpecificationSyntax {
20
    /// Converts the syntax tree into a rewrite specification
21
31
    pub fn to_rewrite_spec(&self) -> RewriteSpecification {
22
        // The names for all variables
23
31
        let variables = AHashSet::from_iter(self.variables.clone());
24

            
25
        // Store the rewrite rules in the maximally shared term storage
26
31
        let mut rewrite_rules = Vec::new();
27
815
        for rule in &self.rewrite_rules {
28
            // Convert the conditions.
29
815
            let mut conditions = vec![];
30
815
            for c in &rule.conditions {
31
82
                let condition = Condition {
32
82
                    lhs: to_untyped_data_expression(c.lhs.clone(), Some(&variables)),
33
82
                    rhs: to_untyped_data_expression(c.rhs.clone(), Some(&variables)),
34
82
                    equality: c.equality,
35
82
                };
36
82
                conditions.push(condition);
37
82
            }
38

            
39
815
            rewrite_rules.push(Rule {
40
815
                lhs: to_untyped_data_expression(rule.lhs.clone(), Some(&variables)),
41
815
                rhs: to_untyped_data_expression(rule.rhs.clone(), Some(&variables)),
42
815
                conditions,
43
815
            });
44
        }
45

            
46
31
        RewriteSpecification::new(rewrite_rules)
47
31
    }
48

            
49
    /// Merges the current specification with another one.
50
45
    pub fn merge(&mut self, include_spec: &RewriteSpecificationSyntax) {
51
45
        self.rewrite_rules.extend_from_slice(&include_spec.rewrite_rules);
52
45
        self.constructors.extend_from_slice(&include_spec.constructors);
53

            
54
158
        for s in &include_spec.variables {
55
158
            if !self.variables.contains(s) {
56
158
                self.variables.push(s.clone());
57
158
            }
58
        }
59
45
    }
60
}
61

            
62
impl fmt::Display for RewriteSpecificationSyntax {
63
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64
        writeln!(f, "Variables: ")?;
65
        for variable in &self.variables {
66
            writeln!(f, "{variable}")?;
67
        }
68
        writeln!(f, "Rewrite rules: ")?;
69
        for rule in &self.rewrite_rules {
70
            writeln!(f, "{rule}")?;
71
        }
72
        writeln!(f)
73
    }
74
}
75

            
76
/// Syntax tree for rewrite rules
77
#[derive(Debug, Clone, Eq, PartialEq)]
78
pub struct RewriteRuleSyntax {
79
    pub lhs: ATerm,
80
    pub rhs: ATerm,
81
    pub conditions: Vec<ConditionSyntax>,
82
}
83

            
84
impl fmt::Display for RewriteRuleSyntax {
85
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86
        write!(f, "{} -> {}", self.lhs, self.rhs)
87
    }
88
}
89

            
90
/// Syntax tree for conditional part of a rewrite rule
91
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
92
pub struct ConditionSyntax {
93
    pub lhs: ATerm,
94
    pub rhs: ATerm,
95
    pub equality: bool, // The condition either specifies that lhs and rhs are equal or different
96
}