rudus/src/base.rs

685 lines
23 KiB
Rust
Raw Normal View History

use crate::value::*;
2024-12-05 16:51:42 +00:00
use imbl::*;
2024-12-06 19:08:34 +00:00
use ran::ran_f64;
2024-12-04 20:03:09 +00:00
use std::rc::Rc;
2024-11-15 02:30:42 +00:00
#[derive(Clone, Debug)]
pub enum Base<'src> {
2024-12-06 19:08:34 +00:00
Nullary(fn() -> Value<'src>),
Unary(fn(&Value<'src>) -> Value<'src>),
Binary(fn(&Value<'src>, &Value<'src>) -> Value<'src>),
Ternary(fn(&Value<'src>, &Value<'src>, &Value<'src>) -> Value<'src>),
}
pub fn eq<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
Value::Boolean(x == y)
2024-11-15 02:30:42 +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) {
(Value::Number(x), Value::Number(y)) => Value::Number(x + y),
_ => unreachable!("internal Ludus error"),
2024-11-15 02:30:42 +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) {
(Value::Number(x), Value::Number(y)) => Value::Number(x - y),
_ => unreachable!("internal Ludus error"),
2024-11-15 02:30:42 +00:00
}
}
pub fn unbox<'src>(x: &Value<'src>) -> Value<'src> {
2024-11-15 02:30:42 +00:00
match x {
Value::Box(_, cell) => cell.borrow().clone(),
_ => unreachable!("internal Ludus error"),
2024-11-15 02:30:42 +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());
val.clone()
2024-11-15 02:30:42 +00:00
} else {
unreachable!("internal Ludus error")
}
}
2024-12-04 20:03:09 +00:00
// TODO: do better than returning just the docstr
// name, patterns, AND docstring
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 {
Value::AllocatedString(Rc::new(format!("{name}: {docstr}")))
2024-12-04 20:03:09 +00:00
} else {
Value::InternedString(doc.unwrap_or("no documentation found"))
2024-12-04 20:03:09 +00:00
}
}
_ => Value::InternedString("no documentation found"),
2024-12-04 20:03:09 +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
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
pub fn r#bool<'src>(x: &Value<'src>) -> Value<'src> {
Value::Boolean(x.bool())
}
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![];
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![];
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"),
}
}
pub fn append<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
match x {
Value::List(list) => {
let mut newlist = list.clone();
newlist.push_back(y.clone());
Value::List(newlist)
}
_ => unreachable!("internal Ludus error"),
}
}
pub fn dec<'src>(x: &Value<'src>) -> Value<'src> {
match x {
Value::Number(n) => Value::Number(n - 1.0),
_ => unreachable!("internal Ludus error"),
}
}
pub fn inc<'src>(x: &Value<'src>) -> Value<'src> {
match x {
Value::Number(n) => Value::Number(n + 1.0),
_ => unreachable!("internal Ludus error"),
}
}
pub fn div<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
match (x, y) {
(Value::Number(x), Value::Number(y)) => Value::Number(x / y),
_ => unreachable!("internal Ludus error"),
}
}
pub fn mult<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
match (x, y) {
(Value::Number(x), Value::Number(y)) => Value::Number(x * y),
_ => unreachable!("internal Ludus error"),
}
}
pub fn dissoc<'src>(dict: &Value<'src>, key: &Value<'src>) -> Value<'src> {
match (dict, key) {
(Value::Dict(dict), Value::Keyword(key)) => {
let mut new = dict.clone();
new.remove(key);
Value::Dict(new)
}
_ => unreachable!("internal Ludus error"),
}
}
pub fn first<'src>(ordered: &Value<'src>) -> Value<'src> {
match ordered {
Value::List(list) => match list.front() {
Some(n) => n.clone(),
None => Value::Nil,
},
Value::Tuple(tuple) => match tuple.first() {
Some(n) => n.clone(),
None => Value::Nil,
},
_ => unreachable!("internal Ludus error"),
}
}
// TODO: figure out how to handle negative numbers
// the cast from f64 to usize discards sign info
pub fn at<'src>(ordered: &Value<'src>, i: &Value<'src>) -> Value<'src> {
match (ordered, i) {
(Value::List(list), Value::Number(n)) => {
let i = *n as usize;
match list.get(i) {
Some(n) => n.clone(),
None => Value::Nil,
}
}
(Value::Tuple(tuple), Value::Number(n)) => {
let i = *n as usize;
match tuple.get(i) {
Some(n) => n.clone(),
None => Value::Nil,
}
}
_ => unreachable!("internal Ludus error"),
}
}
pub fn get<'src>(dict: &Value<'src>, key: &Value<'src>) -> Value<'src> {
match (dict, key) {
(Value::Dict(dict), Value::Keyword(key)) => match dict.get(key) {
Some(x) => x.clone(),
None => Value::Nil,
},
_ => unreachable!("internal Ludus error"),
}
}
pub fn last<'src>(ordered: &Value<'src>) -> Value<'src> {
match ordered {
Value::List(list) => match list.last() {
Some(x) => x.clone(),
None => Value::Nil,
},
Value::Tuple(tuple) => match tuple.last() {
Some(x) => x.clone(),
None => Value::Nil,
},
_ => unreachable!("internal Ludus error"),
}
}
pub fn or<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
Value::Boolean(x.bool() || y.bool())
}
pub fn print<'src>(x: &Value<'src>) -> Value<'src> {
println!("{}", x);
Value::Keyword("ok")
}
pub fn show<'src>(x: &Value<'src>) -> Value<'src> {
Value::AllocatedString(Rc::new(format!("{x}")))
}
pub fn rest<'src>(ordered: &Value<'src>) -> Value<'src> {
match ordered {
Value::List(list) => Value::List(list.clone().split_at(1).1),
Value::Tuple(tuple) => Value::List(Vector::from_iter(tuple.iter().next().cloned())),
_ => unreachable!("internal Ludus error"),
}
}
pub fn count<'src>(coll: &Value<'src>) -> Value<'src> {
match coll {
Value::Dict(d) => Value::Number(d.len() as f64),
Value::List(l) => Value::Number(l.len() as f64),
Value::Tuple(t) => Value::Number(t.len() as f64),
Value::AllocatedString(s) => Value::Number(s.len() as f64),
Value::InternedString(s) => Value::Number(s.len() as f64),
_ => unreachable!("internal Ludus error"),
}
}
pub fn range<'src>(start: &Value<'src>, end: &Value<'src>) -> Value<'src> {
match (start, end) {
(Value::Number(start), Value::Number(end)) => {
let start = *start as isize;
let end = *end as isize;
let mut range = Vector::new();
for n in start..end {
range.push_back(Value::Number(n as f64))
}
Value::List(range)
}
_ => unreachable!("internal Ludus error"),
}
}
pub fn slice<'src>(ordered: &Value<'src>, start: &Value<'src>, end: &Value<'src>) -> Value<'src> {
match (ordered, start, end) {
(Value::List(list), Value::Number(start), Value::Number(end)) => {
let mut newlist = list.clone();
let start = std::cmp::max(*start as usize, 0);
let end = std::cmp::min(*end as usize, list.len());
Value::List(newlist.slice(start..end))
}
// TODO: figure out something better to do than return an empty string on a bad slice
(Value::AllocatedString(string), Value::Number(start), Value::Number(end)) => {
let start = std::cmp::max(*start as usize, 0);
let end = std::cmp::min(*end as usize, string.len());
Value::AllocatedString(Rc::new(
string
.clone()
.as_str()
.get(start..end)
.unwrap_or("")
.to_string(),
))
}
(Value::InternedString(string), Value::Number(start), Value::Number(end)) => {
let start = std::cmp::max(*start as usize, 0);
let end = std::cmp::min(*end as usize, string.len());
Value::AllocatedString(Rc::new(string.get(start..end).unwrap_or("").to_string()))
}
_ => unreachable!("internal Ludus error"),
}
}
pub fn list<'src>(x: &Value<'src>) -> Value<'src> {
match x {
Value::List(_) => x.clone(),
Value::Tuple(t) => Value::List(Vector::from_iter(t.iter().cloned())),
Value::Dict(d) => {
let kvs = d.iter();
let mut list = vector![];
for (key, value) in kvs {
let kv = Value::Tuple(Rc::new(vec![Value::Keyword(key), value.clone()]));
list.push_back(kv);
}
Value::List(list)
}
_ => Value::List(vector![x.clone()]),
}
}
pub fn number<'src>(x: &Value<'src>) -> Value<'src> {
match x {
Value::InternedString(string) => match string.parse::<f64>() {
Ok(n) => Value::Tuple(Rc::new(vec![Value::Keyword("ok"), Value::Number(n)])),
Err(_) => Value::Tuple(Rc::new(vec![
Value::Keyword("err"),
Value::AllocatedString(Rc::new(format!("could not parse `{string}` as a number"))),
])),
},
Value::AllocatedString(string) => match string.parse::<f64>() {
Ok(n) => Value::Tuple(Rc::new(vec![Value::Keyword("ok"), Value::Number(n)])),
Err(_) => Value::Tuple(Rc::new(vec![
Value::Keyword("err"),
Value::AllocatedString(Rc::new(format!("could not parse `{string}` as a number"))),
])),
},
_ => unreachable!("internal Ludus error"),
}
}
pub fn r#type<'src>(x: &Value<'src>) -> Value<'src> {
match x {
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"),
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!("internal Ludus error"),
Value::Args(_) => unreachable!("internal Ludus error"),
Value::Base(_) => Value::Keyword("fn"),
Value::Recur(..) => unreachable!("internal Ludus error"),
}
}
2024-12-06 19:08:34 +00:00
pub fn split<'src>(source: &Value<'src>, splitter: &Value) -> Value<'src> {
match (source, splitter) {
(Value::AllocatedString(source), Value::AllocatedString(splitter)) => {
let parts = source.split_terminator(splitter.as_str());
let mut list = vector![];
for part in parts {
list.push_back(Value::AllocatedString(Rc::new(part.to_string())));
}
Value::List(list)
}
(Value::AllocatedString(source), Value::InternedString(splitter)) => {
let parts = source.split_terminator(splitter);
let mut list = vector![];
for part in parts {
list.push_back(Value::AllocatedString(Rc::new(part.to_string())));
}
Value::List(list)
}
(Value::InternedString(source), Value::AllocatedString(splitter)) => {
let parts = source.split_terminator(splitter.as_str());
let mut list = vector![];
for part in parts {
list.push_back(Value::AllocatedString(Rc::new(part.to_string())));
}
Value::List(list)
}
(Value::InternedString(source), Value::InternedString(splitter)) => {
let parts = source.split_terminator(splitter);
let mut list = vector![];
for part in parts {
list.push_back(Value::AllocatedString(Rc::new(part.to_string())));
}
Value::List(list)
}
_ => unreachable!("internal Ludus error"),
}
}
pub fn upcase<'src>(string: &Value<'src>) -> Value<'src> {
match string {
Value::AllocatedString(string) => Value::AllocatedString(Rc::new(string.to_uppercase())),
Value::InternedString(string) => Value::AllocatedString(Rc::new(string.to_uppercase())),
_ => unreachable!("internal Ludus error"),
}
}
pub fn downcase<'src>(string: &Value<'src>) -> Value<'src> {
match string {
Value::AllocatedString(string) => Value::AllocatedString(Rc::new(string.to_lowercase())),
Value::InternedString(string) => Value::AllocatedString(Rc::new(string.to_lowercase())),
_ => unreachable!("internal Ludus error"),
}
}
pub fn trim<'src>(string: &Value<'src>) -> Value<'src> {
match string {
Value::AllocatedString(string) => {
Value::AllocatedString(Rc::new(string.trim().to_string()))
}
Value::InternedString(string) => Value::AllocatedString(Rc::new(string.trim().to_string())),
_ => unreachable!("internal Ludus error"),
}
}
pub fn triml<'src>(string: &Value<'src>) -> Value<'src> {
match string {
Value::AllocatedString(string) => {
Value::AllocatedString(Rc::new(string.trim_start().to_string()))
}
Value::InternedString(string) => {
Value::AllocatedString(Rc::new(string.trim_start().to_string()))
}
_ => unreachable!("internal Ludus error"),
}
}
pub fn trimr<'src>(string: &Value<'src>) -> Value<'src> {
match string {
Value::AllocatedString(string) => {
Value::AllocatedString(Rc::new(string.trim_end().to_string()))
}
Value::InternedString(string) => {
Value::AllocatedString(Rc::new(string.trim_end().to_string()))
}
_ => unreachable!("internal Ludus error"),
}
}
pub fn atan_2<'src>(x: &Value, y: &Value) -> Value<'src> {
match (x, y) {
(Value::Number(x), Value::Number(y)) => Value::Number(x.atan2(*y)),
_ => unreachable!("internal Ludus error"),
}
}
pub fn ceil<'src>(x: &Value) -> Value<'src> {
match x {
Value::Number(x) => Value::Number(x.ceil()),
_ => unreachable!("internal Ludus error"),
}
}
pub fn cos<'src>(x: &Value) -> Value<'src> {
match x {
Value::Number(x) => Value::Number(x.cos()),
_ => unreachable!("internal Ludus error"),
}
}
pub fn floor<'src>(x: &Value) -> Value<'src> {
match x {
Value::Number(x) => Value::Number(x.floor()),
_ => unreachable!("internal Ludus error"),
}
}
pub fn random<'src>() -> Value<'src> {
Value::Number(ran_f64())
}
pub fn round<'src>(x: &Value) -> Value<'src> {
match x {
Value::Number(x) => Value::Number(x.round()),
_ => unreachable!("internal Ludus error"),
}
}
pub fn sin<'src>(x: &Value) -> Value<'src> {
match x {
Value::Number(x) => Value::Number(x.sin()),
_ => unreachable!("internal Ludus error"),
}
}
pub fn sqrt<'src>(x: &Value) -> Value<'src> {
match x {
Value::Number(x) => Value::Number(x.sqrt()),
_ => unreachable!("internal Ludus error"),
}
}
pub fn tan<'src>(x: &Value) -> Value<'src> {
match x {
Value::Number(x) => Value::Number(x.tan()),
_ => unreachable!("internal Ludus error"),
}
}
pub fn gt<'src>(x: &Value, y: &Value) -> Value<'src> {
match (x, y) {
(Value::Number(x), Value::Number(y)) => Value::Boolean(x > y),
_ => unreachable!("internal Ludus error"),
}
}
pub fn gte<'src>(x: &Value, y: &Value) -> Value<'src> {
match (x, y) {
(Value::Number(x), Value::Number(y)) => Value::Boolean(x >= y),
_ => unreachable!("internal Ludus error"),
}
}
pub fn lt<'src>(x: &Value, y: &Value) -> Value<'src> {
match (x, y) {
(Value::Number(x), Value::Number(y)) => Value::Boolean(x < y),
_ => unreachable!("internal Ludus error"),
}
}
pub fn lte<'src>(x: &Value, y: &Value) -> Value<'src> {
match (x, y) {
(Value::Number(x), Value::Number(y)) => Value::Boolean(x <= y),
_ => unreachable!("internal Ludus error"),
}
}
pub fn r#mod<'src>(x: &Value, y: &Value) -> Value<'src> {
match (x, y) {
(Value::Number(x), Value::Number(y)) => Value::Number(x % y),
_ => unreachable!("internal Ludus error"),
}
}
pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> {
vec![
("add", Value::Base(Base::Binary(add))),
("and", Value::Base(Base::Binary(and))),
2024-12-06 19:08:34 +00:00
("append", Value::Base(Base::Binary(append))),
("assoc", Value::Base(Base::Ternary(assoc))),
2024-12-06 19:08:34 +00:00
("at", Value::Base(Base::Binary(at))),
("atan_2", Value::Base(Base::Binary(atan_2))),
("bool", Value::Base(Base::Unary(r#bool))),
2024-12-06 19:08:34 +00:00
("ceil", Value::Base(Base::Unary(ceil))),
("chars", Value::Base(Base::Unary(chars))),
2024-12-05 16:51:42 +00:00
("concat", Value::Base(Base::Binary(concat))),
2024-12-06 19:08:34 +00:00
("cos", Value::Base(Base::Unary(cos))),
("count", Value::Base(Base::Unary(count))),
("dec", Value::Base(Base::Unary(dec))),
("dissoc", Value::Base(Base::Binary(dissoc))),
2024-12-06 19:08:34 +00:00
("div", Value::Base(Base::Binary(div))),
("doc!", Value::Base(Base::Unary(doc))),
("downcase", Value::Base(Base::Unary(downcase))),
("eq?", Value::Base(Base::Binary(eq))),
("first", Value::Base(Base::Unary(first))),
2024-12-06 19:08:34 +00:00
("floor", Value::Base(Base::Unary(floor))),
("get", Value::Base(Base::Binary(get))),
2024-12-06 19:08:34 +00:00
("gt?", Value::Base(Base::Binary(gt))),
("gte?", Value::Base(Base::Binary(gte))),
("inc", Value::Base(Base::Unary(inc))),
("last", Value::Base(Base::Unary(last))),
2024-12-06 19:08:34 +00:00
("list", Value::Base(Base::Unary(list))),
("lt?", Value::Base(Base::Binary(lt))),
("lte?", Value::Base(Base::Binary(lte))),
("mod", Value::Base(Base::Binary(r#mod))),
("mult", Value::Base(Base::Binary(mult))),
("number", Value::Base(Base::Unary(number))),
("or", Value::Base(Base::Binary(or))),
2024-12-06 19:08:34 +00:00
("pi", Value::Number(std::f64::consts::PI)),
("print!", Value::Base(Base::Unary(print))),
2024-12-06 19:08:34 +00:00
("random", Value::Base(Base::Nullary(random))),
("range", Value::Base(Base::Binary(range))),
2024-12-06 19:08:34 +00:00
("rest", Value::Base(Base::Unary(rest))),
("round", Value::Base(Base::Unary(round))),
("show", Value::Base(Base::Unary(show))),
("sin", Value::Base(Base::Unary(sin))),
("slice", Value::Base(Base::Ternary(slice))),
2024-12-06 19:08:34 +00:00
("split", Value::Base(Base::Binary(split))),
("sqrt", Value::Base(Base::Unary(sqrt))),
("sqrt_2", Value::Number(std::f64::consts::SQRT_2)),
("store!", Value::Base(Base::Binary(store))),
("sub", Value::Base(Base::Binary(sub))),
("tan", Value::Base(Base::Unary(tan))),
("trim", Value::Base(Base::Unary(trim))),
("triml", Value::Base(Base::Unary(triml))),
("trimr", Value::Base(Base::Unary(trimr))),
("type", Value::Base(Base::Unary(r#type))),
2024-12-06 19:08:34 +00:00
("unbox", Value::Base(Base::Unary(unbox))),
("upcase", Value::Base(Base::Unary(upcase))),
]
}
2024-12-06 19:08:34 +00:00
// * [x] atan_2 (x) -> number
// * [x] ceil (x) -> number
// * [x] cos (x) -> number
// * [x] floor (x) -> number
// * [x] gt (x, y) -> bool
// * [x] gte! (x, y) -> bool
// * [x] lt (x) -> bool
// * [x] lte (x) -> bool
// * [x] mod (x, y) -> number
// * [x] pi
// * [x] random () -> number
// * [x] round (x) -> number
// * [x] sin (x) -> number
// * [x] sqrt (x) -> number
// * [x] tan (x) -> number
// * [x] add (x, y) -> number
2024-12-05 19:02:41 +00:00
// * [x] and (x, y) -> value
// * [x] append (x, y) -> list
2024-12-05 19:02:41 +00:00
// * [x] assoc (x, y) -> dict
// * [x] bool (x) -> bool
// * [x] chars (x) -> list
// * [x] concat (x, y) -> value
2024-12-06 19:08:34 +00:00
// * [x] count (x) -> number
// * [x] dec (x) -> number
// * [x] dissoc (x, y) -> dict
// * [x] div (x, y) -> number
// * [x] doc (x) -> string
2024-12-06 19:08:34 +00:00
// * [x] downcase (x) -> string
// * [x] eq (x, y) -> bool
// * [x] first (x) -> value
// * [x] get (x, y) -> value
// * [x] inc (x) -> number
// * [x] last (x) -> value
// * [x] or (x, y) -> value
// * [x] print! (x) -> :ok
2024-12-06 19:08:34 +00:00
// * [x] range () -> list
// * [x] rest (x) -> coll
// * [x] show (x) -> string
2024-12-06 19:08:34 +00:00
// * [x] slice (x, y, z) -> list
// * [x] split (x, y) -> list(string)
// * [x] store! (x, y) -> value
// * [x] sub (x, y) -> number
2024-12-06 19:08:34 +00:00
// * [x] to_list (x) -> list
// * [x] to_number (x) -> number
// * [x] trim (x) -> string
// * [x] triml (x) -> string
// * [x] trimr (x) -> string
// * [x] type (x) -> keyword
// * [x] unbox (x) -> value
2024-12-06 19:08:34 +00:00
// * [x] upcase (x) -> string
// * [x] ~prn (x) -> value~
// * [x] ~push (x) -> list~
2024-12-06 19:08:34 +00:00
// * [x] ~str_slice (x, y, z) -> string~
// * [x] ~stringify (x) -> string~
// * [~] disj (x) -> set