Skip to main content

haloumi_ir/
traits.rs

1//! Common traits used in IR objects.
2
3use std::iter::Sum;
4
5use crate::diagnostics::Diagnostic;
6
7/// Represents a constant-foldable object.
8pub trait ConstantFolding {
9    /// Error type.
10    type Error;
11    /// Object's type for constants.
12    type T;
13
14    /// Folds the object in-place.
15    fn constant_fold(&mut self) -> Result<(), Self::Error>;
16
17    /// Moves the object after folding it.
18    fn constant_folded(mut self) -> Result<Self, Self::Error>
19    where
20        Self: Sized,
21    {
22        self.constant_fold()?;
23        Ok(self)
24    }
25
26    /// May return the object as a constant value.
27    fn const_value(&self) -> Option<Self::T> {
28        None
29    }
30}
31
32impl<T: ConstantFolding> ConstantFolding for Box<T> {
33    type Error = T::Error;
34
35    type T = T::T;
36
37    fn constant_fold(&mut self) -> Result<(), Self::Error> {
38        self.as_mut().constant_fold()
39    }
40
41    fn constant_folded(self) -> Result<Self, Self::Error>
42    where
43        Self: Sized,
44    {
45        (*self).constant_folded().map(Box::new)
46    }
47
48    fn const_value(&self) -> Option<Self::T> {
49        self.as_ref().const_value()
50    }
51}
52
53impl<E: ConstantFolding> ConstantFolding for Vec<E> {
54    type Error = E::Error;
55
56    type T = Vec<E::T>;
57
58    fn constant_fold(&mut self) -> Result<(), Self::Error> {
59        self.iter_mut().try_for_each(|e| e.constant_fold())
60    }
61
62    fn const_value(&self) -> Option<Self::T> {
63        self.iter().map(|e| e.const_value()).collect()
64    }
65}
66
67impl<E: ConstantFolding> ConstantFolding for [E] {
68    type Error = E::Error;
69
70    type T = Vec<E::T>;
71
72    fn constant_fold(&mut self) -> Result<(), Self::Error> {
73        self.iter_mut().try_for_each(|e| e.constant_fold())
74    }
75
76    fn const_value(&self) -> Option<Self::T> {
77        self.iter().map(|e| e.const_value()).collect()
78    }
79}
80
81/// Represents an object that has a canonical form.
82pub trait Canonicalize {
83    /// Canonicalizes the object in-place.
84    fn canonicalize(&mut self);
85
86    /// Transforms the object into its canonical version.
87    fn canonicalized(mut self) -> Self
88    where
89        Self: Sized,
90    {
91        self.canonicalize();
92        self
93    }
94}
95
96impl<E: Canonicalize> Canonicalize for Vec<E> {
97    fn canonicalize(&mut self) {
98        for e in self {
99            e.canonicalize();
100        }
101    }
102}
103
104impl<E: Canonicalize> Canonicalize for [E] {
105    fn canonicalize(&mut self) {
106        for e in self {
107            e.canonicalize();
108        }
109    }
110}
111
112impl<T: Canonicalize> Canonicalize for Box<T> {
113    fn canonicalize(&mut self) {
114        self.as_mut().canonicalize()
115    }
116}
117
118/// Trait for evaluating IR objects.
119pub trait Evaluate<Output> {
120    /// Evaluate the IR object and return a result.
121    fn evaluate(&self) -> Output;
122}
123
124impl<O, T: Evaluate<O>> Evaluate<O> for Box<T> {
125    fn evaluate(&self) -> O {
126        self.as_ref().evaluate()
127    }
128}
129
130impl<O, T: Evaluate<O>> Evaluate<Option<O>> for Option<T> {
131    fn evaluate(&self) -> Option<O> {
132        self.as_ref().map(Evaluate::<O>::evaluate)
133    }
134}
135
136impl<O: Sum, T: Evaluate<O>> Evaluate<O> for [T] {
137    fn evaluate(&self) -> O {
138        self.iter().map(Evaluate::<O>::evaluate).sum()
139    }
140}
141
142impl<O: Sum, T: Evaluate<O>> Evaluate<O> for Vec<T> {
143    fn evaluate(&self) -> O {
144        self.iter().map(Evaluate::<O>::evaluate).sum()
145    }
146}
147
148/// Trait for performing validation on the IR.
149pub trait Validatable {
150    /// The type used to represent diagnostics.
151    type Diagnostic: Diagnostic;
152
153    /// Context necessary for validating the IR.
154    type Context: ?Sized;
155
156    /// Performs validation checks, returning either
157    /// `Ok` with a list of non-error diagnostics or `Err` with a list of all the diagnostics.
158    fn validate_with_context(
159        &self,
160        context: &Self::Context,
161    ) -> Result<Vec<Self::Diagnostic>, Vec<Self::Diagnostic>>;
162
163    /// Performs validation checks, returning either
164    /// `Ok` with a list of non-error diagnostics or `Err` with a list of all the diagnostics.
165    fn validate(&self) -> Result<Vec<Self::Diagnostic>, Vec<Self::Diagnostic>>
166    where
167        Self::Context: Default,
168    {
169        self.validate_with_context(&Default::default())
170    }
171}