From 5e10a87cbc929b6a7a189f9f7c3e343cadfc7ccc Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Fri, 6 Dec 2024 13:21:25 -0500 Subject: [PATCH] keep adding to base, pull type function from value to base --- src/base.rs | 310 +++++++++++++++++++++++++++++++++++++++++++++++---- src/main.rs | 4 +- src/value.rs | 20 ---- src/vm.rs | 2 +- 4 files changed, 290 insertions(+), 46 deletions(-) diff --git a/src/base.rs b/src/base.rs index 7015a09..077beab 100644 --- a/src/base.rs +++ b/src/base.rs @@ -1,7 +1,6 @@ use crate::value::*; use imbl::*; use std::rc::Rc; -// use std::fmt; #[derive(Clone, Debug)] pub enum Base<'src> { @@ -141,6 +140,250 @@ pub fn concat<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> { } } +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::() { + 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::() { + 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"), + } +} + pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> { vec![ ("eq?", Value::Base(Base::Binary(eq))), @@ -154,48 +397,53 @@ pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> { ("bool", Value::Base(Base::Unary(r#bool))), ("chars", Value::Base(Base::Unary(chars))), ("concat", Value::Base(Base::Binary(concat))), + ("append", Value::Base(Base::Binary(append))), + ("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))), + ("range", Value::Base(Base::Binary(range))), + ("slice", Value::Base(Base::Ternary(slice))), + ("list", Value::Base(Base::Unary(list))), + ("number", Value::Base(Base::Unary(number))), + ("type", Value::Base(Base::Unary(r#type))), ] } // * [ ] 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 +// * [x] count (x) -> number +// * [~] disj (x) -> set // * [ ] 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 +// * [x] range () -> list // * [ ] round (x) -> number -// * [ ] show (x) -> string // * [ ] sin (x) -> number -// * [ ] slice (x, y, z) -> list +// * [x] 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 +// * [x] ~str_slice (x, y, z) -> string~ +// * [x] ~stringify (x) -> string~ // * [ ] tan (x) -> number -// * [ ] to_list (x) -> list +// * [x] to_list (x) -> list // * [ ] to_number (x) -> number // * [ ] trim (x) -> string // * [ ] triml (x) -> string @@ -204,10 +452,26 @@ pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> { // * [ ] upcase (x) -> string // * [x] add (x, y) -> number // * [x] and (x, y) -> value +// * [x] append (x, y) -> list // * [x] assoc (x, y) -> dict // * [x] bool (x) -> bool // * [x] chars (x) -> list // * [x] concat (x, y) -> value +// * [x] dec (x) -> number +// * [x] dissoc (x, y) -> dict +// * [x] div (x, y) -> number +// * [x] doc (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 +// * [x] rest (x) -> coll +// * [x] show (x) -> string // * [x] store! (x, y) -> value +// * [x] sub (x, y) -> number // * [x] unbox (x) -> value +// * [x] ~prn (x) -> value~ +// * [x] ~push (x) -> list~ diff --git a/src/main.rs b/src/main.rs index d6c154b..f801a75 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,8 +58,8 @@ use crate::base::*; pub fn main() { let src = " -let foo = [1, 2, 3] -concat([1, 2, 3], [4, 5, 6]) +let foo = 42 +type (\"{foo}\") "; let (tokens, lex_errs) = lexer().parse(src).into_output_errors(); if !lex_errs.is_empty() { diff --git a/src/value.rs b/src/value.rs index 124d60c..e8dea85 100644 --- a/src/value.rs +++ b/src/value.rs @@ -123,26 +123,6 @@ impl Value<'_> { pub fn bool(&self) -> bool { 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"), - 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"), - Value::Recur(..) => unreachable!(), - } - } } impl<'src> PartialEq for Value<'src> { diff --git a/src/vm.rs b/src/vm.rs index bd95f2e..48f92aa 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -69,7 +69,7 @@ pub fn match_pattern<'src, 'a>( Some(ctx) } (Pattern::As(word, type_str), value) => { - let ludus_type = value.ludus_type(); + let ludus_type = r#type(value); let type_kw = Value::Keyword(type_str); if type_kw == ludus_type { ctx.push((word, value.clone()));