1use std::fmt;
2use std::str::FromStr;
3
4use crate::*;
5use fmt::{Debug, Display, Formatter};
6use thiserror::Error;
7
8#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct Var(VarInner);
16
17impl Var {
18 pub fn from_u32(num: u32) -> Self {
30 Var(VarInner::Num(num))
31 }
32
33 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#[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 pub fn with_capacity(capacity: usize) -> Self {
113 Self {
114 vec: smallvec::SmallVec::with_capacity(capacity),
115 }
116 }
117
118 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 #[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 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}