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
    /// Constructor symbols with their arities, as declared in the `CONS` section.
16
    /// Retained because they are part of the specification, but the untyped
17
    /// rewriter does not need them, so [Self::to_rewrite_spec] currently ignores them.
18
    pub constructors: Vec<(String, usize)>,
19
    pub variables: Vec<String>,
20
}
21

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

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

            
42
1642
            rewrite_rules.push(Rule {
43
1642
                lhs: to_untyped_data_expression(rule.lhs.clone(), Some(&variables)),
44
1642
                rhs: to_untyped_data_expression(rule.rhs.clone(), Some(&variables)),
45
1642
                conditions,
46
1642
            });
47
        }
48

            
49
64
        RewriteSpecification::new(rewrite_rules)
50
64
    }
51

            
52
    /// Merges the current specification with another one.
53
94
    pub fn merge(&mut self, include_spec: &RewriteSpecificationSyntax) {
54
94
        self.rewrite_rules.extend_from_slice(&include_spec.rewrite_rules);
55
94
        self.constructors.extend_from_slice(&include_spec.constructors);
56

            
57
320
        for s in &include_spec.variables {
58
320
            if !self.variables.contains(s) {
59
320
                self.variables.push(s.clone());
60
320
            }
61
        }
62
94
    }
63
}
64

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

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

            
87
impl fmt::Display for RewriteRuleSyntax {
88
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89
        write!(f, "{} -> {}", self.lhs, self.rhs)?;
90
        for (i, condition) in self.conditions.iter().enumerate() {
91
            let keyword = if i == 0 { "if" } else { "and-if" };
92
            let comparison = if condition.equality { "=" } else { "<>" };
93
            write!(f, " {keyword} {} {comparison} {}", condition.lhs, condition.rhs)?;
94
        }
95
        Ok(())
96
    }
97
}
98

            
99
/// Syntax tree for conditional part of a rewrite rule
100
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
101
pub struct ConditionSyntax {
102
    pub lhs: ATerm,
103
    pub rhs: ATerm,
104
    pub equality: bool, // The condition either specifies that lhs and rhs are equal or different
105
}