188 lines
6.4 KiB
Rust
188 lines
6.4 KiB
Rust
use crate::base::*;
|
|
use crate::parser::*;
|
|
use imbl::*;
|
|
use std::cell::RefCell;
|
|
use std::fmt;
|
|
use std::rc::Rc;
|
|
use struct_scalpel::Dissectible;
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Fn<'src> {
|
|
pub name: &'src str,
|
|
pub body: &'src Vec<MatchClause<'src>>,
|
|
pub doc: &'src Option<&'src str>,
|
|
}
|
|
|
|
#[derive(Debug, Dissectible)]
|
|
pub enum Value<'src> {
|
|
Nil,
|
|
Placeholder,
|
|
Boolean(bool),
|
|
Number(f64),
|
|
Keyword(&'src str),
|
|
// TODO: add a "runtime-generated" string type that wraps a Rust String
|
|
// this is necessary for nice documentation and string interpolation
|
|
InternedString(&'src str),
|
|
AllocatedString(Rc<String>),
|
|
// on the heap for now
|
|
Tuple(Rc<Vec<Self>>),
|
|
Args(Rc<Vec<Self>>),
|
|
// ref-counted, immutable, persistent
|
|
List(Vector<Self>),
|
|
// ref-counted, immutable, persistent
|
|
// dicts may only use keywords as keys
|
|
Dict(HashMap<&'src str, Self>),
|
|
Box(&'src str, Rc<RefCell<Self>>),
|
|
Fn(Rc<Fn<'src>>),
|
|
Base(Base<'src>),
|
|
Recur(Vec<Self>),
|
|
// Set(HashSet<Self>),
|
|
// Sets are hard
|
|
// Sets require Eq
|
|
// Eq is not implemented on f64, because NaNs
|
|
// We could use ordered_float::NotNan
|
|
// Let's defer that
|
|
// We're not really using sets in Ludus
|
|
|
|
// Other things we're not implementing yet:
|
|
// pkgs, nses, tests
|
|
}
|
|
|
|
impl<'src> Clone for Value<'src> {
|
|
fn clone(&self) -> Value<'src> {
|
|
match self {
|
|
Value::Nil => Value::Nil,
|
|
Value::Boolean(b) => Value::Boolean(*b),
|
|
Value::InternedString(s) => Value::InternedString(s),
|
|
Value::AllocatedString(s) => Value::AllocatedString(s.clone()),
|
|
Value::Keyword(s) => Value::Keyword(s),
|
|
Value::Number(n) => Value::Number(*n),
|
|
Value::Tuple(t) => Value::Tuple(t.clone()),
|
|
Value::Args(a) => Value::Args(a.clone()),
|
|
Value::Fn(f) => Value::Fn(f.clone()),
|
|
Value::List(l) => Value::List(l.clone()),
|
|
Value::Dict(d) => Value::Dict(d.clone()),
|
|
Value::Box(name, b) => Value::Box(name, b.clone()),
|
|
Value::Placeholder => Value::Placeholder,
|
|
Value::Base(b) => Value::Base(b.clone()),
|
|
Value::Recur(..) => unreachable!(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Value<'_> {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
Value::Nil => write!(f, "nil"),
|
|
Value::Boolean(b) => write!(f, "{}", b),
|
|
Value::Number(n) => write!(f, "{}", n),
|
|
Value::Keyword(k) => write!(f, ":{}", k),
|
|
Value::InternedString(s) => write!(f, "\"{}\"", s),
|
|
Value::AllocatedString(s) => write!(f, "\"{}\"", s),
|
|
Value::Fn(fun) => write!(f, "fn {}", fun.name),
|
|
Value::Tuple(t) | Value::Args(t) => write!(
|
|
f,
|
|
"({})",
|
|
t.iter()
|
|
.map(|x| x.to_string())
|
|
.collect::<Vec<_>>()
|
|
.join(", ")
|
|
),
|
|
Value::List(l) => write!(
|
|
f,
|
|
"[{}]",
|
|
l.iter()
|
|
.map(|x| x.to_string())
|
|
.collect::<Vec<_>>()
|
|
.join(", ")
|
|
),
|
|
Value::Dict(d) => write!(
|
|
f,
|
|
"#{{{}}}",
|
|
d.iter()
|
|
.map(|(k, v)| format!(":{k} {v}"))
|
|
.collect::<Vec<_>>()
|
|
.join(", ")
|
|
),
|
|
Value::Box(name, value) => {
|
|
write!(
|
|
f,
|
|
"box {}: [{}]",
|
|
name,
|
|
&value.try_borrow().unwrap().to_string()
|
|
)
|
|
}
|
|
Value::Placeholder => write!(f, "_"),
|
|
Value::Base(..) => unreachable!(),
|
|
Value::Recur(..) => unreachable!(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Value<'_> {
|
|
pub fn bool(&self) -> bool {
|
|
matches!(self, Value::Nil | Value::Boolean(false))
|
|
}
|
|
}
|
|
|
|
impl<'src> PartialEq for Value<'src> {
|
|
fn eq(&self, other: &Value<'src>) -> bool {
|
|
match (self, other) {
|
|
// value equality types
|
|
(Value::Nil, Value::Nil) => true,
|
|
(Value::Boolean(x), Value::Boolean(y)) => x == y,
|
|
(Value::Number(x), Value::Number(y)) => x == y,
|
|
(Value::InternedString(x), Value::InternedString(y)) => x == y,
|
|
(Value::AllocatedString(x), Value::AllocatedString(y)) => x == y,
|
|
(Value::InternedString(x), Value::AllocatedString(y)) => *x == **y,
|
|
(Value::AllocatedString(x), Value::InternedString(y)) => **x == *y,
|
|
(Value::Keyword(x), Value::Keyword(y)) => x == y,
|
|
(Value::Tuple(x), Value::Tuple(y)) => x == y,
|
|
(Value::List(x), Value::List(y)) => x == y,
|
|
(Value::Dict(x), Value::Dict(y)) => x == y,
|
|
// reference equality types
|
|
(Value::Fn(x), Value::Fn(y)) => Rc::<Fn<'_>>::as_ptr(x) == Rc::<Fn<'_>>::as_ptr(y),
|
|
(Value::Box(_, x), Value::Box(_, y)) => {
|
|
Rc::<RefCell<Value<'_>>>::as_ptr(x) == Rc::<RefCell<Value<'_>>>::as_ptr(y)
|
|
}
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Eq for Value<'_> {}
|
|
|
|
impl Value<'_> {
|
|
pub fn interpolate(&self) -> String {
|
|
match self {
|
|
Value::Nil => String::new(),
|
|
Value::Boolean(b) => format!("{b}"),
|
|
Value::Number(n) => format!("{n}"),
|
|
Value::Keyword(k) => format!(":{k}"),
|
|
Value::AllocatedString(s) => format!("{s}"),
|
|
Value::InternedString(s) => s.to_string(),
|
|
Value::Box(_, x) => x.borrow().interpolate(),
|
|
Value::Tuple(xs) => xs
|
|
.iter()
|
|
.map(|x| x.interpolate())
|
|
.collect::<Vec<_>>()
|
|
.join(", "),
|
|
Value::List(xs) => xs
|
|
.iter()
|
|
.map(|x| x.interpolate())
|
|
.collect::<Vec<_>>()
|
|
.join(", "),
|
|
Value::Dict(xs) => xs
|
|
.iter()
|
|
.map(|(k, v)| format!(":{} {}", k, v.interpolate()))
|
|
.collect::<Vec<_>>()
|
|
.join(", "),
|
|
Value::Fn(x) => format!("fn {}", x.name.to_string()),
|
|
Value::Placeholder => unreachable!(),
|
|
Value::Args(_) => unreachable!(),
|
|
Value::Recur(_) => unreachable!(),
|
|
Value::Base(_) => unreachable!(),
|
|
}
|
|
}
|
|
}
|