139 lines
3.2 KiB
Rust
139 lines
3.2 KiB
Rust
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<T: Into<EcoString>> From<T> 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<Regex> =
|
|
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<Symbol, Value>,
|
|
}
|
|
|
|
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<Value>,
|
|
}
|
|
|
|
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, "<CODE>"),
|
|
Func => write!(f, "<LAMBDA>"),
|
|
PrimOp(x) => write!(f, "<PRIMOP {x}>"),
|
|
PartialPrimOp(x) => write!(f, "<PARTIAL PRIMOP {x}>"),
|
|
Repeated => write!(f, "<REPEATED>"),
|
|
}
|
|
}
|
|
}
|
|
|