keep adding to base, pull type function from value to base
This commit is contained in:
parent
96906fdb9f
commit
5e10a87cbc
310
src/base.rs
310
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::<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"),
|
||||
}
|
||||
}
|
||||
|
||||
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~
|
||||
|
|
|
@ -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() {
|
||||
|
|
20
src/value.rs
20
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> {
|
||||
|
|
Loading…
Reference in New Issue
Block a user