1
#![forbid(unsafe_code)]
2

            
3
use std::fmt;
4

            
5
use itertools::Itertools;
6
use merc_data::DataExpression;
7

            
8
/// A rewrite specification is a set of rewrite rules, given by [Rule].
9
#[derive(Debug, Default, Clone)]
10
pub struct RewriteSpecification {
11
    rewrite_rules: Vec<Rule>,
12
}
13

            
14
impl RewriteSpecification {
15
    /// Create a new, empty rewrite specification.
16
31
    pub fn new(rewrite_rules: Vec<Rule>) -> RewriteSpecification {
17
31
        RewriteSpecification { rewrite_rules }
18
31
    }
19

            
20
    /// Returns the rewrite rules of this specification.
21
57
    pub fn rewrite_rules(&self) -> &[Rule] {
22
57
        &self.rewrite_rules
23
57
    }
24
}
25

            
26
/// A condition of a conditional rewrite rule.
27
///
28
/// Either `lhs == rhs` or `lhs != rhs` depending on equality being true.
29
#[derive(Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
30
pub struct Condition {
31
    pub lhs: DataExpression,
32
    pub rhs: DataExpression,
33
    pub equality: bool,
34
}
35

            
36
impl Condition {
37
    /// Create a new condition with the given left-hand side, right-hand side and equality.
38
    pub fn new(lhs: DataExpression, rhs: DataExpression, equality: bool) -> Condition {
39
        Condition { lhs, rhs, equality }
40
    }
41
}
42

            
43
/// A rewrite rule.
44
#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
45
pub struct Rule {
46
    /// A conjunction of clauses
47
    pub conditions: Vec<Condition>,
48
    pub lhs: DataExpression,
49
    pub rhs: DataExpression,
50
}
51

            
52
impl Rule {
53
    /// Create a rewrite rule with the given conditions, left-hand side and right-hand side.
54
    pub fn with_condition(conditions: Vec<Condition>, lhs: DataExpression, rhs: DataExpression) -> Rule {
55
        Rule { conditions, lhs, rhs }
56
    }
57

            
58
    /// Create a rewrite rule without conditions.
59
    pub fn new(lhs: DataExpression, rhs: DataExpression) -> Rule {
60
        Rule {
61
            conditions: Vec::new(),
62
            lhs,
63
            rhs,
64
        }
65
    }
66
}
67

            
68
impl fmt::Display for RewriteSpecification {
69
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70
        for rule in &self.rewrite_rules {
71
            writeln!(f, "{rule}")?;
72
        }
73
        Ok(())
74
    }
75
}
76

            
77
impl fmt::Display for Rule {
78
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79
        if self.conditions.is_empty() {
80
            write!(f, "{} = {}", self.lhs, self.rhs)
81
        } else {
82
            write!(
83
                f,
84
                "{} -> {} = {}",
85
                self.conditions.iter().format(", "),
86
                self.lhs,
87
                self.rhs
88
            )
89
        }
90
    }
91
}
92

            
93
impl fmt::Display for Condition {
94
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95
        if self.equality {
96
            write!(f, "{} == {}", self.lhs, self.rhs)
97
        } else {
98
            write!(f, "{} <> {}", self.lhs, self.rhs)
99
        }
100
    }
101
}