use std::fmt;
use std::str::FromStr;
use crate::*;
use fmt::{Debug, Display, Formatter};
use thiserror::Error;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Var(VarInner);
impl Var {
pub fn from_u32(num: u32) -> Self {
Var(VarInner::Num(num))
}
pub fn as_u32(&self) -> Option<u32> {
match self.0 {
VarInner::Num(num) => Some(num),
_ => None,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum VarInner {
Sym(Symbol),
Num(u32),
}
#[derive(Debug, Error)]
pub enum VarParseError {
#[error("pattern variable {0:?} should have a leading question mark")]
MissingQuestionMark(String),
#[error("number pattern variable {0:?} was malformed")]
BadNumber(String),
}
impl FromStr for Var {
type Err = VarParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
use VarParseError::*;
match s.as_bytes() {
[b'?', b'#', ..] => s[2..]
.parse()
.map(|num| Var(VarInner::Num(num)))
.map_err(|_| BadNumber(s.to_owned())),
[b'?', ..] if s.len() > 1 => Ok(Var(VarInner::Sym(Symbol::from(s)))),
_ => Err(MissingQuestionMark(s.to_owned())),
}
}
}
impl Display for Var {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self.0 {
VarInner::Sym(sym) => write!(f, "{}", sym),
VarInner::Num(num) => write!(f, "?#{}", num),
}
}
}
impl Debug for Var {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self.0 {
VarInner::Sym(sym) => write!(f, "{:?}", sym),
VarInner::Num(num) => write!(f, "?#{}", num),
}
}
}
impl From<u32> for Var {
fn from(num: u32) -> Self {
Var(VarInner::Num(num))
}
}
impl From<Symbol> for Var {
fn from(sym: Symbol) -> Self {
Var(VarInner::Sym(sym))
}
}
#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Subst {
pub(crate) vec: smallvec::SmallVec<[(Var, Id); 3]>,
}
impl Subst {
pub fn with_capacity(capacity: usize) -> Self {
Self {
vec: smallvec::SmallVec::with_capacity(capacity),
}
}
pub fn insert(&mut self, var: Var, id: Id) -> Option<Id> {
for pair in &mut self.vec {
if pair.0 == var {
return Some(std::mem::replace(&mut pair.1, id));
}
}
self.vec.push((var, id));
None
}
#[inline(never)]
pub fn get(&self, var: Var) -> Option<&Id> {
self.vec
.iter()
.find_map(|(v, id)| if *v == var { Some(id) } else { None })
}
}
impl std::ops::Index<Var> for Subst {
type Output = Id;
fn index(&self, var: Var) -> &Self::Output {
match self.get(var) {
Some(id) => id,
None => panic!("Var '{}={}' not found in {:?}", var, var, self),
}
}
}
impl Debug for Subst {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let len = self.vec.len();
write!(f, "{{")?;
for i in 0..len {
let (var, id) = &self.vec[i];
write!(f, "{}: {}", var, id)?;
if i < len - 1 {
write!(f, ", ")?;
}
}
write!(f, "}}")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn var_parse() {
assert_eq!(Var::from_str("?a").unwrap().to_string(), "?a");
assert_eq!(Var::from_str("?abc 123").unwrap().to_string(), "?abc 123");
assert!(Var::from_str("a").is_err());
assert!(Var::from_str("a?").is_err());
assert!(Var::from_str("?").is_err());
assert!(Var::from_str("?#").is_err());
assert!(Var::from_str("?#foo").is_err());
assert_eq!(Var::from_str("?#0").unwrap(), Var(VarInner::Num(0)));
assert_eq!(Var::from_str("?#010").unwrap(), Var(VarInner::Num(10)));
assert_eq!(
Var::from_str("?#10").unwrap(),
Var::from_str("?#0010").unwrap()
);
assert_eq!(Var::from_str("?#010").unwrap(), Var(VarInner::Num(10)));
}
}