egg/
subst.rs

1use std::fmt;
2use std::str::FromStr;
3
4use crate::*;
5use fmt::{Debug, Display, Formatter};
6use thiserror::Error;
7
8/// A variable for use in [`Pattern`]s or [`Subst`]s.
9///
10/// This implements [`FromStr`], and will only parse if it has a
11/// leading `?`.
12///
13/// [`FromStr`]: std::str::FromStr
14#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct Var(VarInner);
16
17impl Var {
18    /// Create a new variable from a u32.
19    ///
20    /// You can also use special syntax `?#3`, `?#42` to denote a numeric variable.
21    /// These avoid some symbol interning, and can also be created manually from
22    /// using this function or the `From` impl.
23    ///
24    /// ```rust
25    /// # use egg::*;
26    /// assert_eq!(Var::from(12), "?#12".parse().unwrap());
27    /// assert_eq!(Var::from_u32(12), "?#12".parse().unwrap());
28    /// ```
29    pub fn from_u32(num: u32) -> Self {
30        Var(VarInner::Num(num))
31    }
32
33    /// If this variable was created from a u32, get it back out.
34    pub fn as_u32(&self) -> Option<u32> {
35        match self.0 {
36            VarInner::Num(num) => Some(num),
37            _ => None,
38        }
39    }
40}
41
42#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
43enum VarInner {
44    Sym(Symbol),
45    Num(u32),
46}
47
48#[derive(Debug, Error)]
49pub enum VarParseError {
50    #[error("pattern variable {0:?} should have a leading question mark")]
51    MissingQuestionMark(String),
52    #[error("number pattern variable {0:?} was malformed")]
53    BadNumber(String),
54}
55
56impl FromStr for Var {
57    type Err = VarParseError;
58
59    fn from_str(s: &str) -> Result<Self, Self::Err> {
60        use VarParseError::*;
61
62        match s.as_bytes() {
63            [b'?', b'#', ..] => s[2..]
64                .parse()
65                .map(|num| Var(VarInner::Num(num)))
66                .map_err(|_| BadNumber(s.to_owned())),
67            [b'?', ..] if s.len() > 1 => Ok(Var(VarInner::Sym(Symbol::from(s)))),
68            _ => Err(MissingQuestionMark(s.to_owned())),
69        }
70    }
71}
72
73impl Display for Var {
74    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
75        match self.0 {
76            VarInner::Sym(sym) => write!(f, "{}", sym),
77            VarInner::Num(num) => write!(f, "?#{}", num),
78        }
79    }
80}
81
82impl Debug for Var {
83    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
84        match self.0 {
85            VarInner::Sym(sym) => write!(f, "{:?}", sym),
86            VarInner::Num(num) => write!(f, "?#{}", num),
87        }
88    }
89}
90
91impl From<u32> for Var {
92    fn from(num: u32) -> Self {
93        Var(VarInner::Num(num))
94    }
95}
96
97impl From<Symbol> for Var {
98    fn from(sym: Symbol) -> Self {
99        Var(VarInner::Sym(sym))
100    }
101}
102
103/// A substitution mapping [`Var`]s to eclass [`Id`]s.
104///
105#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
106pub struct Subst {
107    pub(crate) vec: smallvec::SmallVec<[(Var, Id); 3]>,
108}
109
110impl Subst {
111    /// Create a `Subst` with the given initial capacity
112    pub fn with_capacity(capacity: usize) -> Self {
113        Self {
114            vec: smallvec::SmallVec::with_capacity(capacity),
115        }
116    }
117
118    /// Insert something, returning the old `Id` if present.
119    pub fn insert(&mut self, var: Var, id: Id) -> Option<Id> {
120        for pair in &mut self.vec {
121            if pair.0 == var {
122                return Some(std::mem::replace(&mut pair.1, id));
123            }
124        }
125        self.vec.push((var, id));
126        None
127    }
128
129    /// Retrieve a `Var`, returning `None` if not present.
130    #[inline(never)]
131    pub fn get(&self, var: Var) -> Option<&Id> {
132        self.vec
133            .iter()
134            .find_map(|(v, id)| if *v == var { Some(id) } else { None })
135    }
136}
137
138impl std::ops::Index<Var> for Subst {
139    type Output = Id;
140
141    fn index(&self, var: Var) -> &Self::Output {
142        match self.get(var) {
143            Some(id) => id,
144            None => panic!("Var '{}={}' not found in {:?}", var, var, self),
145        }
146    }
147}
148
149impl Debug for Subst {
150    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
151        let len = self.vec.len();
152        write!(f, "{{")?;
153        for i in 0..len {
154            let (var, id) = &self.vec[i];
155            write!(f, "{}: {}", var, id)?;
156            if i < len - 1 {
157                write!(f, ", ")?;
158            }
159        }
160        write!(f, "}}")
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use super::*;
167
168    #[test]
169    fn var_parse() {
170        assert_eq!(Var::from_str("?a").unwrap().to_string(), "?a");
171        assert_eq!(Var::from_str("?abc 123").unwrap().to_string(), "?abc 123");
172        assert!(Var::from_str("a").is_err());
173        assert!(Var::from_str("a?").is_err());
174        assert!(Var::from_str("?").is_err());
175        assert!(Var::from_str("?#").is_err());
176        assert!(Var::from_str("?#foo").is_err());
177
178        // numeric vars
179        assert_eq!(Var::from_str("?#0").unwrap(), Var(VarInner::Num(0)));
180        assert_eq!(Var::from_str("?#010").unwrap(), Var(VarInner::Num(10)));
181        assert_eq!(
182            Var::from_str("?#10").unwrap(),
183            Var::from_str("?#0010").unwrap()
184        );
185        assert_eq!(Var::from_str("?#010").unwrap(), Var(VarInner::Num(10)));
186    }
187}