finish base, I think

This commit is contained in:
Scott Richmond 2024-12-06 14:08:34 -05:00
parent 5e10a87cbc
commit 13c14fd38f
4 changed files with 270 additions and 53 deletions

View File

@ -11,3 +11,4 @@ chumsky = { git = "https://github.com/zesterer/chumsky", features = ["label"] }
imbl = "3.0.0" imbl = "3.0.0"
struct_scalpel = "0.1.1" struct_scalpel = "0.1.1"
tailcall = "1.0.1" tailcall = "1.0.1"
ran = "2.0.1"

View File

@ -1,9 +1,11 @@
use crate::value::*; use crate::value::*;
use imbl::*; use imbl::*;
use ran::ran_f64;
use std::rc::Rc; use std::rc::Rc;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Base<'src> { pub enum Base<'src> {
Nullary(fn() -> Value<'src>),
Unary(fn(&Value<'src>) -> Value<'src>), Unary(fn(&Value<'src>) -> Value<'src>),
Binary(fn(&Value<'src>, &Value<'src>) -> Value<'src>), Binary(fn(&Value<'src>, &Value<'src>) -> Value<'src>),
Ternary(fn(&Value<'src>, &Value<'src>, &Value<'src>) -> Value<'src>), Ternary(fn(&Value<'src>, &Value<'src>, &Value<'src>) -> Value<'src>),
@ -384,72 +386,262 @@ pub fn r#type<'src>(x: &Value<'src>) -> Value<'src> {
} }
} }
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>)> { pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> {
vec![ vec![
("eq?", Value::Base(Base::Binary(eq))),
("add", Value::Base(Base::Binary(add))), ("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))), ("and", Value::Base(Base::Binary(and))),
("append", Value::Base(Base::Binary(append))),
("assoc", Value::Base(Base::Ternary(assoc))), ("assoc", Value::Base(Base::Ternary(assoc))),
("at", Value::Base(Base::Binary(at))),
("atan_2", Value::Base(Base::Binary(atan_2))),
("bool", Value::Base(Base::Unary(r#bool))), ("bool", Value::Base(Base::Unary(r#bool))),
("ceil", Value::Base(Base::Unary(ceil))),
("chars", Value::Base(Base::Unary(chars))), ("chars", Value::Base(Base::Unary(chars))),
("concat", Value::Base(Base::Binary(concat))), ("concat", Value::Base(Base::Binary(concat))),
("append", Value::Base(Base::Binary(append))), ("cos", Value::Base(Base::Unary(cos))),
("dec", Value::Base(Base::Unary(dec))),
("inc", Value::Base(Base::Unary(inc))),
("div", Value::Base(Base::Binary(div))),
("mult", Value::Base(Base::Binary(mult))),
("dissoc", Value::Base(Base::Binary(dissoc))),
("first", Value::Base(Base::Unary(first))),
("at", Value::Base(Base::Binary(at))),
("get", Value::Base(Base::Binary(get))),
("last", Value::Base(Base::Unary(last))),
("or", Value::Base(Base::Binary(or))),
("print!", Value::Base(Base::Unary(print))),
("show", Value::Base(Base::Unary(show))),
("rest", Value::Base(Base::Unary(rest))),
("count", Value::Base(Base::Unary(count))), ("count", Value::Base(Base::Unary(count))),
("range", Value::Base(Base::Binary(range))), ("dec", Value::Base(Base::Unary(dec))),
("slice", Value::Base(Base::Ternary(slice))), ("dissoc", Value::Base(Base::Binary(dissoc))),
("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))),
("floor", Value::Base(Base::Unary(floor))),
("get", Value::Base(Base::Binary(get))),
("gt?", Value::Base(Base::Binary(gt))),
("gte?", Value::Base(Base::Binary(gte))),
("inc", Value::Base(Base::Unary(inc))),
("last", Value::Base(Base::Unary(last))),
("list", Value::Base(Base::Unary(list))), ("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))), ("number", Value::Base(Base::Unary(number))),
("or", Value::Base(Base::Binary(or))),
("pi", Value::Number(std::f64::consts::PI)),
("print!", Value::Base(Base::Unary(print))),
("random", Value::Base(Base::Nullary(random))),
("range", Value::Base(Base::Binary(range))),
("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))),
("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))), ("type", Value::Base(Base::Unary(r#type))),
("unbox", Value::Base(Base::Unary(unbox))),
("upcase", Value::Base(Base::Unary(upcase))),
] ]
} }
// * [ ] atan_2 (x) -> number // * [x] atan_2 (x) -> number
// * [ ] ceil (x) -> number // * [x] ceil (x) -> number
// * [ ] cos (x) -> number // * [x] cos (x) -> number
// * [x] count (x) -> number // * [x] floor (x) -> number
// * [~] disj (x) -> set // * [x] gt (x, y) -> bool
// * [ ] downcase (x) -> string // * [x] gte! (x, y) -> bool
// * [ ] floor (x) -> number // * [x] lt (x) -> bool
// * [ ] gt (x, y) -> bool // * [x] lte (x) -> bool
// * [ ] gte! (x, y) -> bool // * [x] mod (x, y) -> number
// * [ ] lt (x) -> bool // * [x] pi
// * [ ] lte (x) -> bool // * [x] random () -> number
// * [ ] mod (x, y) -> number // * [x] round (x) -> number
// * [ ] pi // * [x] sin (x) -> number
// * [ ] random () -> number // * [x] sqrt (x) -> number
// * [x] range () -> list // * [x] tan (x) -> number
// * [ ] round (x) -> number
// * [ ] sin (x) -> number
// * [x] slice (x, y, z) -> list
// * [ ] split (x, y) -> list(string)
// * [ ] sqrt (x) -> number
// * [x] ~str_slice (x, y, z) -> string~
// * [x] ~stringify (x) -> string~
// * [ ] tan (x) -> number
// * [x] 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 // * [x] add (x, y) -> number
// * [x] and (x, y) -> value // * [x] and (x, y) -> value
// * [x] append (x, y) -> list // * [x] append (x, y) -> list
@ -457,10 +649,12 @@ pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> {
// * [x] bool (x) -> bool // * [x] bool (x) -> bool
// * [x] chars (x) -> list // * [x] chars (x) -> list
// * [x] concat (x, y) -> value // * [x] concat (x, y) -> value
// * [x] count (x) -> number
// * [x] dec (x) -> number // * [x] dec (x) -> number
// * [x] dissoc (x, y) -> dict // * [x] dissoc (x, y) -> dict
// * [x] div (x, y) -> number // * [x] div (x, y) -> number
// * [x] doc (x) -> string // * [x] doc (x) -> string
// * [x] downcase (x) -> string
// * [x] eq (x, y) -> bool // * [x] eq (x, y) -> bool
// * [x] first (x) -> value // * [x] first (x) -> value
// * [x] get (x, y) -> value // * [x] get (x, y) -> value
@ -468,10 +662,23 @@ pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> {
// * [x] last (x) -> value // * [x] last (x) -> value
// * [x] or (x, y) -> value // * [x] or (x, y) -> value
// * [x] print! (x) -> :ok // * [x] print! (x) -> :ok
// * [x] range () -> list
// * [x] rest (x) -> coll // * [x] rest (x) -> coll
// * [x] show (x) -> string // * [x] show (x) -> string
// * [x] slice (x, y, z) -> list
// * [x] split (x, y) -> list(string)
// * [x] store! (x, y) -> value // * [x] store! (x, y) -> value
// * [x] sub (x, y) -> number // * [x] sub (x, y) -> number
// * [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 // * [x] unbox (x) -> value
// * [x] upcase (x) -> string
// * [x] ~prn (x) -> value~ // * [x] ~prn (x) -> value~
// * [x] ~push (x) -> list~ // * [x] ~push (x) -> list~
// * [x] ~str_slice (x, y, z) -> string~
// * [x] ~stringify (x) -> string~
// * [~] disj (x) -> set

View File

@ -58,8 +58,8 @@ use crate::base::*;
pub fn main() { pub fn main() {
let src = " let src = "
let foo = 42 let foo = \" fOobArbaz \"
type (\"{foo}\") trimr (foo)
"; ";
let (tokens, lex_errs) = lexer().parse(src).into_output_errors(); let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
if !lex_errs.is_empty() { if !lex_errs.is_empty() {

View File

@ -242,6 +242,15 @@ pub fn apply<'src>(
msg: "you may only call a function".to_string(), msg: "you may only call a function".to_string(),
}), }),
(Value::Base(f), Value::Tuple(args)) => match f { (Value::Base(f), Value::Tuple(args)) => match f {
Base::Nullary(f) => {
if args.len() != 0 {
Err(LudusError {
msg: "wrong arity: expected 0 arguments".to_string(),
})
} else {
Ok(f())
}
}
Base::Unary(f) => { Base::Unary(f) => {
if args.len() != 1 { if args.len() != 1 {
Err(LudusError { Err(LudusError {