rudus/src/value.rs

212 lines
7.3 KiB
Rust
Raw Normal View History

use crate::base::*;
2024-10-31 20:59:26 +00:00
use crate::parser::*;
use imbl::*;
use std::cell::RefCell;
2024-10-31 20:59:26 +00:00
use std::fmt;
use std::rc::Rc;
2024-11-21 23:50:13 +00:00
use struct_scalpel::Dissectible;
2024-10-31 20:59:26 +00:00
#[derive(Clone, Debug)]
2024-10-31 20:59:26 +00:00
pub struct Fn<'src> {
2024-11-11 01:12:19 +00:00
pub name: &'src str,
pub body: &'src Vec<MatchClause<'src>>,
2024-12-04 20:03:09 +00:00
pub doc: &'src Option<&'src str>,
2024-10-31 20:59:26 +00:00
}
2024-11-21 23:50:13 +00:00
#[derive(Debug, Dissectible)]
2024-11-06 22:37:57 +00:00
pub enum Value<'src> {
2024-10-31 20:59:26 +00:00
Nil,
2024-11-11 01:12:19 +00:00
Placeholder,
2024-10-31 20:59:26 +00:00
Boolean(bool),
Number(f64),
2024-11-06 22:37:57 +00:00
Keyword(&'src str),
2024-12-04 20:03:09 +00:00
// 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>>),
2024-11-11 01:12:19 +00:00
Args(Rc<Vec<Self>>),
// ref-counted, immutable, persistent
2024-11-09 19:10:08 +00:00
List(Vector<Self>),
// ref-counted, immutable, persistent
2024-11-21 21:57:52 +00:00
// dicts may only use keywords as keys
2024-11-09 19:10:08 +00:00
Dict(HashMap<&'src str, Self>),
Box(&'src str, Rc<RefCell<Self>>),
2024-11-11 01:12:19 +00:00
Fn(Rc<Fn<'src>>),
2024-11-15 02:30:42 +00:00
Base(Base<'src>),
2024-11-21 21:57:52 +00:00
Recur(Vec<Self>),
2024-10-31 20:59:26 +00:00
// 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
}
2024-11-06 22:37:57 +00:00
impl<'src> Clone for Value<'src> {
fn clone(&self) -> Value<'src> {
match self {
Value::Nil => Value::Nil,
2024-11-22 01:00:49 +00:00
Value::Boolean(b) => Value::Boolean(*b),
2024-12-04 20:03:09 +00:00
Value::InternedString(s) => Value::InternedString(s),
Value::AllocatedString(s) => Value::AllocatedString(s.clone()),
Value::Keyword(s) => Value::Keyword(s),
2024-11-22 01:00:49 +00:00
Value::Number(n) => Value::Number(*n),
Value::Tuple(t) => Value::Tuple(t.clone()),
2024-11-11 01:12:19 +00:00
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()),
2024-11-11 01:12:19 +00:00
Value::Placeholder => Value::Placeholder,
Value::Base(b) => Value::Base(b.clone()),
2024-11-21 21:57:52 +00:00
Value::Recur(..) => unreachable!(),
}
}
}
2024-11-22 01:00:49 +00:00
impl fmt::Display for Value<'_> {
2024-10-31 20:59:26 +00:00
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),
2024-12-04 20:03:09 +00:00
Value::InternedString(s) => write!(f, "\"{}\"", s),
Value::AllocatedString(s) => write!(f, "\"{}\"", s),
2024-11-11 01:12:19 +00:00
Value::Fn(fun) => write!(f, "fn {}", fun.name),
Value::Tuple(t) | Value::Args(t) => write!(
2024-10-31 20:59:26 +00:00
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(", ")
),
2024-11-11 01:12:19 +00:00
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()
)
}
2024-11-11 01:12:19 +00:00
Value::Placeholder => write!(f, "_"),
Value::Base(base) => {
let name = match base {
Base::Unary(name, _) => name,
Base::Binary(name, _) => name,
2024-11-21 22:10:50 +00:00
// Base::Ternary(name, _) => name,
};
write!(f, "base fn {}", name)
}
2024-11-21 21:57:52 +00:00
Value::Recur(..) => unreachable!(),
2024-10-31 20:59:26 +00:00
}
}
}
2024-11-22 01:00:49 +00:00
impl Value<'_> {
pub fn bool(&self) -> bool {
2024-11-22 01:00:49 +00:00
matches!(self, Value::Nil | Value::Boolean(false))
}
pub fn ludus_type(&self) -> Value {
match self {
Value::Nil => Value::Keyword("nil"),
Value::Number(_) => Value::Keyword("number"),
Value::Boolean(_) => Value::Keyword("boolean"),
Value::Keyword(_) => Value::Keyword("keyword"),
Value::Tuple(_) => Value::Keyword("tuple"),
2024-12-04 20:03:09 +00:00
Value::InternedString(_) => Value::Keyword("string"),
Value::AllocatedString(_) => Value::Keyword("string"),
Value::List(_) => Value::Keyword("list"),
Value::Dict(_) => Value::Keyword("dict"),
Value::Fn(_) => Value::Keyword("fn"),
Value::Box(_, _) => Value::Keyword("box"),
Value::Placeholder => unreachable!(),
Value::Args(_) => unreachable!(),
Value::Base(_) => Value::Keyword("fn"),
2024-11-21 22:02:54 +00:00
Value::Recur(..) => unreachable!(),
}
}
}
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,
2024-12-04 20:03:09 +00:00
(Value::InternedString(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,
}
}
}
2024-11-22 01:00:49 +00:00
impl Eq for Value<'_> {}
2024-12-05 00:07:03 +00:00
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!(),
}
}
}