2024-11-11 22:50:58 +00:00
|
|
|
use crate::value::*;
|
2024-12-05 16:51:42 +00:00
|
|
|
use imbl::*;
|
2024-12-04 20:03:09 +00:00
|
|
|
use std::rc::Rc;
|
2024-11-21 22:10:50 +00:00
|
|
|
// use std::fmt;
|
2024-11-11 22:50:58 +00:00
|
|
|
|
2024-11-15 02:30:42 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2024-11-11 22:50:58 +00:00
|
|
|
pub enum Base<'src> {
|
2024-12-05 01:19:41 +00:00
|
|
|
Unary(fn(&Value<'src>) -> Value<'src>),
|
|
|
|
Binary(fn(&Value<'src>, &Value<'src>) -> Value<'src>),
|
|
|
|
Ternary(fn(&Value<'src>, &Value<'src>, &Value<'src>) -> Value<'src>),
|
2024-11-11 22:50:58 +00:00
|
|
|
}
|
|
|
|
|
2024-12-05 01:19:41 +00:00
|
|
|
pub fn eq<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
|
|
|
Value::Boolean(x == y)
|
2024-11-15 02:30:42 +00:00
|
|
|
}
|
|
|
|
|
2024-12-05 01:19:41 +00:00
|
|
|
pub fn add<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
2024-11-15 02:30:42 +00:00
|
|
|
match (x, y) {
|
2024-12-05 01:19:41 +00:00
|
|
|
(Value::Number(x), Value::Number(y)) => Value::Number(x + y),
|
|
|
|
_ => unreachable!("internal Ludus error"),
|
2024-11-15 02:30:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-05 01:19:41 +00:00
|
|
|
pub fn sub<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
2024-11-15 02:30:42 +00:00
|
|
|
match (x, y) {
|
2024-12-05 01:19:41 +00:00
|
|
|
(Value::Number(x), Value::Number(y)) => Value::Number(x - y),
|
|
|
|
_ => unreachable!("internal Ludus error"),
|
2024-11-15 02:30:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-05 01:19:41 +00:00
|
|
|
pub fn unbox<'src>(x: &Value<'src>) -> Value<'src> {
|
2024-11-15 02:30:42 +00:00
|
|
|
match x {
|
2024-12-05 01:19:41 +00:00
|
|
|
Value::Box(_, cell) => cell.borrow().clone(),
|
|
|
|
_ => unreachable!("internal Ludus error"),
|
2024-11-15 02:30:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-05 01:19:41 +00:00
|
|
|
pub fn store<'src>(b: &Value<'src>, val: &Value<'src>) -> Value<'src> {
|
2024-11-15 02:30:42 +00:00
|
|
|
if let Value::Box(_, cell) = b {
|
|
|
|
cell.replace(val.clone());
|
2024-12-05 01:19:41 +00:00
|
|
|
val.clone()
|
2024-11-15 02:30:42 +00:00
|
|
|
} else {
|
2024-12-05 01:19:41 +00:00
|
|
|
unreachable!("internal Ludus error")
|
2024-11-11 22:50:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-04 20:03:09 +00:00
|
|
|
// TODO: do better than returning just the docstr
|
|
|
|
// name, patterns, AND docstring
|
2024-12-05 01:19:41 +00:00
|
|
|
pub fn doc<'src>(f: &Value<'src>) -> Value<'src> {
|
2024-12-04 20:03:09 +00:00
|
|
|
match f {
|
|
|
|
Value::Fn(f) => {
|
|
|
|
let Fn { name, doc, .. } = **f;
|
|
|
|
if let Some(docstr) = doc {
|
2024-12-05 01:19:41 +00:00
|
|
|
Value::AllocatedString(Rc::new(format!("{name}: {docstr}")))
|
2024-12-04 20:03:09 +00:00
|
|
|
} else {
|
2024-12-05 01:19:41 +00:00
|
|
|
Value::InternedString(doc.unwrap_or("no documentation found"))
|
2024-12-04 20:03:09 +00:00
|
|
|
}
|
|
|
|
}
|
2024-12-05 01:19:41 +00:00
|
|
|
_ => Value::InternedString("no documentation found"),
|
2024-12-04 20:03:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-05 01:19:41 +00:00
|
|
|
pub fn and<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
|
|
|
Value::Boolean(x.bool() && y.bool())
|
|
|
|
}
|
2024-11-15 02:30:42 +00:00
|
|
|
|
2024-12-05 01:19:41 +00:00
|
|
|
pub fn assoc<'src>(dict: &Value<'src>, key: &Value<'src>, value: &Value<'src>) -> Value<'src> {
|
|
|
|
match (dict, key) {
|
|
|
|
(Value::Dict(d), Value::Keyword(k)) => Value::Dict(d.update(k, value.clone())),
|
|
|
|
_ => unreachable!("internal Ludus error"),
|
|
|
|
}
|
|
|
|
}
|
2024-11-15 02:30:42 +00:00
|
|
|
|
2024-12-05 01:19:41 +00:00
|
|
|
pub fn r#bool<'src>(x: &Value<'src>) -> Value<'src> {
|
|
|
|
Value::Boolean(x.bool())
|
|
|
|
}
|
2024-11-11 22:50:58 +00:00
|
|
|
|
2024-12-05 01:19:41 +00:00
|
|
|
pub fn chars<'src>(x: &Value<'src>) -> Value<'src> {
|
|
|
|
match x {
|
|
|
|
Value::InternedString(s) => {
|
|
|
|
let chars = s.chars();
|
|
|
|
|
2024-12-05 16:51:42 +00:00
|
|
|
let mut charlist = vector![];
|
2024-12-05 01:19:41 +00:00
|
|
|
for char in chars {
|
|
|
|
if char.is_ascii() {
|
|
|
|
charlist.push_back(Value::AllocatedString(Rc::new(char.to_string())))
|
|
|
|
} else {
|
|
|
|
return Value::Tuple(Rc::new(vec![
|
|
|
|
Value::Keyword("err"),
|
|
|
|
Value::AllocatedString(Rc::new(format!(
|
|
|
|
"{char} is not an ascii character"
|
|
|
|
))),
|
|
|
|
]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Value::Tuple(Rc::new(vec![Value::Keyword("ok"), Value::List(charlist)]))
|
|
|
|
}
|
|
|
|
Value::AllocatedString(s) => {
|
|
|
|
let chars = s.chars();
|
|
|
|
|
2024-12-05 16:51:42 +00:00
|
|
|
let mut charlist = vector![];
|
2024-12-05 01:19:41 +00:00
|
|
|
for char in chars {
|
|
|
|
if char.is_ascii() {
|
|
|
|
charlist.push_back(Value::AllocatedString(Rc::new(char.to_string())))
|
|
|
|
} else {
|
|
|
|
return Value::Tuple(Rc::new(vec![
|
|
|
|
Value::Keyword("err"),
|
|
|
|
Value::AllocatedString(Rc::new(format!(
|
|
|
|
"{char} is not an ascii character"
|
|
|
|
))),
|
|
|
|
]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Value::Tuple(Rc::new(vec![Value::Keyword("ok"), Value::List(charlist)]))
|
|
|
|
}
|
|
|
|
_ => unreachable!("internal Ludus error"),
|
|
|
|
}
|
|
|
|
}
|
2024-12-04 20:03:09 +00:00
|
|
|
|
2024-12-05 16:51:42 +00:00
|
|
|
// TODO: figure out how to get to opportunistic mutation here
|
|
|
|
pub fn concat<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
|
|
|
match (x, y) {
|
|
|
|
(Value::InternedString(x), Value::InternedString(y)) => {
|
|
|
|
Value::AllocatedString(Rc::new(format!("{x}{y}")))
|
|
|
|
}
|
|
|
|
(Value::AllocatedString(x), Value::AllocatedString(y)) => {
|
|
|
|
Value::AllocatedString(Rc::new(format!("{x}{y}")))
|
|
|
|
}
|
|
|
|
(Value::AllocatedString(x), Value::InternedString(y)) => {
|
|
|
|
Value::AllocatedString(Rc::new(format!("{x}{y}")))
|
|
|
|
}
|
|
|
|
(Value::InternedString(x), Value::AllocatedString(y)) => {
|
|
|
|
Value::AllocatedString(Rc::new(format!("{x}{y}")))
|
|
|
|
}
|
|
|
|
(Value::List(x), Value::List(y)) => {
|
|
|
|
let mut newlist = x.clone();
|
|
|
|
newlist.append(y.clone());
|
|
|
|
Value::List(newlist)
|
|
|
|
}
|
|
|
|
_ => unreachable!("internal Ludus error"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-05 01:19:41 +00:00
|
|
|
pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> {
|
|
|
|
vec![
|
|
|
|
("eq?", Value::Base(Base::Binary(eq))),
|
|
|
|
("add", Value::Base(Base::Binary(add))),
|
|
|
|
("sub", Value::Base(Base::Binary(sub))),
|
|
|
|
("unbox", Value::Base(Base::Unary(unbox))),
|
|
|
|
("store!", Value::Base(Base::Binary(store))),
|
|
|
|
("doc!", Value::Base(Base::Unary(doc))),
|
|
|
|
("and", Value::Base(Base::Binary(and))),
|
|
|
|
("assoc", Value::Base(Base::Ternary(assoc))),
|
|
|
|
("bool", Value::Base(Base::Unary(r#bool))),
|
|
|
|
("chars", Value::Base(Base::Unary(chars))),
|
2024-12-05 16:51:42 +00:00
|
|
|
("concat", Value::Base(Base::Binary(concat))),
|
2024-12-05 01:19:41 +00:00
|
|
|
]
|
2024-11-11 22:50:58 +00:00
|
|
|
}
|
|
|
|
|
2024-12-05 01:19:41 +00:00
|
|
|
// * [ ] atan_2 (x) -> number
|
|
|
|
// * [ ] ceil (x) -> number
|
|
|
|
// * [ ] conj (x, y) -> list
|
|
|
|
// * [ ] cos (x) -> number
|
|
|
|
// * [ ] dec (x) -> number
|
|
|
|
// * [ ] disj (x) -> set
|
|
|
|
// * [ ] dissoc (x, y) -> dict
|
|
|
|
// * [ ] div (x, y) -> number
|
|
|
|
// * [ ] doc (x) -> string
|
|
|
|
// * [ ] downcase (x) -> string
|
|
|
|
// * [ ] first (x) -> value
|
|
|
|
// * [ ] floor (x) -> number
|
|
|
|
// * [ ] get (x, y) -> value
|
|
|
|
// * [ ] gt (x, y) -> bool
|
|
|
|
// * [ ] gte! (x, y) -> bool
|
|
|
|
// * [ ] inc (x) -> number
|
|
|
|
// * [ ] last (x) -> value
|
|
|
|
// * [ ] lt (x) -> bool
|
|
|
|
// * [ ] lte (x) -> bool
|
|
|
|
// * [ ] mod (x, y) -> number
|
|
|
|
// * [ ] or (x, y) -> value
|
|
|
|
// * [ ] pi
|
|
|
|
// * [ ] print! (x) -> :ok
|
|
|
|
// * [ ] prn (x) -> value
|
|
|
|
// * [ ] push (x) -> list
|
|
|
|
// * [ ] random () -> number
|
|
|
|
// * [ ] range () -> list
|
|
|
|
// * [ ] rest (x) -> coll
|
|
|
|
// * [ ] round (x) -> number
|
|
|
|
// * [ ] show (x) -> string
|
|
|
|
// * [ ] sin (x) -> number
|
|
|
|
// * [ ] slice (x, y, z) -> list
|
|
|
|
// * [ ] split (x, y) -> list(string)
|
|
|
|
// * [ ] sqrt (x) -> number
|
|
|
|
// * [ ] str_slice (x, y, z) -> string
|
|
|
|
// * [ ] stringify (x) -> string
|
|
|
|
// * [ ] sub (x, y) -> number
|
|
|
|
// * [ ] tan (x) -> number
|
|
|
|
// * [ ] to_list (x) -> list
|
|
|
|
// * [ ] to_number (x) -> number
|
|
|
|
// * [ ] trim (x) -> string
|
|
|
|
// * [ ] triml (x) -> string
|
|
|
|
// * [ ] trimr (x) -> string
|
|
|
|
// * [ ] type (x) -> keyword
|
|
|
|
// * [ ] upcase (x) -> string
|
|
|
|
// * [x] add (x, y) -> number
|
2024-12-05 19:02:41 +00:00
|
|
|
// * [x] and (x, y) -> value
|
|
|
|
// * [x] assoc (x, y) -> dict
|
|
|
|
// * [x] bool (x) -> bool
|
|
|
|
// * [x] chars (x) -> list
|
|
|
|
// * [x] concat (x, y) -> value
|
2024-12-05 01:19:41 +00:00
|
|
|
// * [x] eq (x, y) -> bool
|
|
|
|
// * [x] store! (x, y) -> value
|
|
|
|
// * [x] unbox (x) -> value
|