use hashbrown::HashMap; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; use std::ops::Deref; use std::sync::LazyLock; use derive_more::{Constructor, IsVariant, Unwrap}; use ecow::EcoString; use regex::Regex; use rpds::VectorSync; use super::common::*; #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Constructor)] pub struct Symbol(EcoString); impl> From for Symbol { fn from(value: T) -> Self { Symbol(value.into()) } } impl Display for Symbol { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { if self.normal() { write!(f, r#""{}""#, self.0) } else { write!(f, "{}", self.0) } } } static REGEX: LazyLock = LazyLock::new(|| Regex::new(r#"^[a-zA-Z\_][a-zA-Z0-9\_\'\-]*$"#).unwrap()); impl Symbol { fn normal(&self) -> bool { !REGEX.is_match(self) } } impl Deref for Symbol { type Target = str; fn deref(&self) -> &Self::Target { &self.0 } } impl Symbol { pub fn into_inner(self) -> EcoString { self.0 } pub fn as_inner(&self) -> &EcoString { &self.0 } } #[derive(Constructor, Clone, PartialEq)] pub struct AttrSet { data: HashMap, } impl Debug for AttrSet { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { use Value::*; write!(f, "{{ ")?; for (k, v) in self.data.iter() { match v { List(_) => write!(f, "{k:?} = [ ... ]; ")?, AttrSet(_) => write!(f, "{k:?} = {{ ... }}; ")?, v => write!(f, "{k:?} = {v:?}; ")?, } } write!(f, "}}") } } impl Display for AttrSet { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { use Value::*; write!(f, "{{ ")?; for (k, v) in self.data.iter() { write!(f, "{k} = ")?; match v { AttrSet(_) => write!(f, "{{ ... }}"), List(_) => write!(f, "[ ... ]"), v => write!(f, "{v}") }?; write!(f, "; ")?; } write!(f, "}}") } } #[derive(Constructor, Clone, Debug, PartialEq)] pub struct List { data: VectorSync, } impl Display for List { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { write!(f, "[ ")?; for v in self.data.iter() { write!(f, "{v} ")?; } write!(f, "]") } } #[derive(IsVariant, Unwrap, Clone, Debug, PartialEq)] pub enum Value { Const(Const), AttrSet(AttrSet), List(List), Catchable(Catchable), Thunk, Func, PrimOp(&'static str), PartialPrimOp(&'static str), Repeated, } impl Display for Value { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { use Value::*; match self { Const(x) => write!(f, "{x}"), AttrSet(x) => write!(f, "{x}"), List(x) => write!(f, "{x}"), Catchable(x) => write!(f, "{x}"), Thunk => write!(f, ""), Func => write!(f, ""), PrimOp(x) => write!(f, ""), PartialPrimOp(x) => write!(f, ""), Repeated => write!(f, ""), } } }