diff --git a/src/interpreter/value/mod.rs b/src/interpreter/value/mod.rs index c3ef5ea..51d5267 100644 --- a/src/interpreter/value/mod.rs +++ b/src/interpreter/value/mod.rs @@ -7,6 +7,7 @@ pub use pair::DotPair; pub use string::Str; use crate::syntax::ast::{Expr, Spanned}; +use pair::list; use std::{collections::BTreeMap, fmt::Display, rc::Rc}; pub type OrderedF64 = ordered_float::OrderedFloat; @@ -15,7 +16,7 @@ pub type OrderedF64 = ordered_float::OrderedFloat; pub enum Value<'s> { #[default] Nil, - DotPair(Rc>), + DotPair(DotPair<'s>), Vector(Rc>), Map(Rc>), Symbol(Str<'s>), @@ -36,14 +37,11 @@ impl<'s> From> for Value<'s> { fn from(e: Expr<'s>) -> Self { match e { Expr::List(v) => v.into_iter().rev().fold(Self::Nil, |acc, x| { - Value::DotPair(Rc::new(DotPair(x.into(), acc))) + Value::DotPair(DotPair::new(x.into(), acc)) }), Expr::Vector(v) => Self::Vector(Rc::new(v.into_iter().map(Into::into).collect())), - Expr::Pair((l, r)) => Self::DotPair(Rc::new(DotPair((*l).into(), (*r).into()))), - Expr::Quote(e) => Self::DotPair(Rc::new(DotPair( - Self::Symbol("quote".into()), - Self::DotPair(Rc::new(DotPair((*e).into(), Self::Nil))), - ))), + Expr::Pair((l, r)) => Self::DotPair(DotPair::new((*l).into(), (*r).into())), + Expr::Quote(e) => list!(Self::Symbol("quote".into()), (*e).into()), Expr::Symbol("nil") => Self::Nil, Expr::Symbol(s) => Self::Symbol(s.into()), Expr::Keyword(s) => Self::Keyword(s.into()), @@ -57,7 +55,7 @@ impl<'s> Display for Value<'s> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Value::Nil => "nil".fmt(f), - Value::DotPair(p) => write!(f, "({} . {})", p.0, p.1), + Value::DotPair(p) => p.fmt(f), Value::Vector(v) => fmt_sequence(f, v.as_ref(), "#(", ")", |i, f| i.fmt(f)), Value::Map(m) => { fmt_sequence(f, m.as_ref(), "(", ")", |(k, v), f| write!(f, "{k} -> {v}")) diff --git a/src/interpreter/value/pair.rs b/src/interpreter/value/pair.rs index 6923cc7..279f7b4 100644 --- a/src/interpreter/value/pair.rs +++ b/src/interpreter/value/pair.rs @@ -1,4 +1,60 @@ use super::Value; +use std::{fmt::Display, rc::Rc}; #[derive(Debug, Clone, PartialEq, Eq)] -pub struct DotPair<'s>(pub Value<'s>, pub Value<'s>); +pub struct DotPair<'s>(pub Rc<(Value<'s>, Value<'s>)>); +impl<'s> DotPair<'s> { + pub fn new(first: Value<'s>, second: Value<'s>) -> Self { + Self(Rc::new((first, second))) + } + + pub fn first(&self) -> &Value<'s> { + &self.0 .0 + } + + pub fn second(&self) -> &Value<'s> { + &self.0 .1 + } +} + +impl<'s> Display for DotPair<'s> { + fn fmt(mut self: &Self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + "(".fmt(f)?; + loop { + self.first().fmt(f)?; + match self.second() { + Value::Nil => break, + Value::DotPair(p) => { + " ".fmt(f)?; + self = p; + } + val => break write!(f, " . {val}")?, + } + } + ")".fmt(f)?; + Ok(()) + } +} + +macro_rules! list { + () => { + $crate::interpreter::value::Value::Nil + }; + + ($item: expr $(,)?) => { + Value::DotPair( + $crate::interpreter::value::DotPair::new($item, $crate::interpreter::value::Value::Nil) + ) + }; + + ($first: expr, $($rest: expr),* $(,)?) => { + Value::DotPair( + $crate::interpreter::value::DotPair::new( + $first, + $crate::interpreter::value::pair::list!($($rest),*) + ) + ) + }; +} + +pub(crate) use list;