use ordered_float::OrderedFloat; use std::{ fmt::{Display, Write}, hash::Hash, }; pub type Span = std::ops::Range<usize>; /// A spanned item #[derive(Clone, Debug)] pub struct Spanned<T> { pub item: T, pub span: Span, } impl<T> Spanned<T> { pub fn new(item: T, span: Span) -> Self { Self { item, span } } } impl<T: Display> Display for Spanned<T> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{} \x1B[2m@ {:?}\x1B[22m", self.item, self.span) } } impl<T: PartialEq> PartialEq for Spanned<T> { fn eq(&self, other: &Self) -> bool { self.item == other.item } } impl<T: Eq> Eq for Spanned<T> {} impl<T: Hash> Hash for Spanned<T> { fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.item.hash(state); } } /// A Wisp AST #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum Expr<'s> { List(Vec<Spanned<Self>>), Vector(Vec<Spanned<Self>>), Pair((Box<Spanned<Self>>, Box<Spanned<Self>>)), Quote(Box<Spanned<Self>>), Symbol(&'s str), Keyword(&'s str), Number(OrderedFloat<f64>), String(&'s str), } impl<'s> Display for Expr<'s> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::List(list) => fmt_list(f, list), Self::Vector(vec) => { write!(f, "#")?; fmt_list(f, vec) } Self::Pair((l, r)) => write!(f, "{l} . {r}"), Self::Quote(expr) => write!(f, "'{expr}"), Self::Symbol(sym) => write!(f, "{sym}"), Self::Keyword(kw) => write!(f, ":{kw}"), Self::Number(n) => write!(f, "{n}"), Self::String(s) => write!(f, "\"{s}\""), } } } fn fmt_list(f: &mut impl Write, iterable: &[Spanned<Expr>]) -> std::fmt::Result { let mut iter = iterable.iter(); write!(f, "(")?; if let Some(i) = iter.next() { write!(f, "{i}")?; } for i in iter { write!(f, " {i}")?; } write!(f, ")") }