start pulling base fns into bytecode interpreter
This commit is contained in:
parent
615fef6ebc
commit
fc245348b4
436
src/base.rs
436
src/base.rs
|
@ -4,40 +4,44 @@ use ran::ran_f64;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum BaseFn<'src> {
|
pub enum BaseFn {
|
||||||
Nullary(fn() -> Value<'src>),
|
Nullary(fn() -> Value),
|
||||||
Unary(fn(&Value<'src>) -> Value<'src>),
|
Unary(fn(&Value) -> Value),
|
||||||
Binary(fn(&Value<'src>, &Value<'src>) -> Value<'src>),
|
Binary(fn(&Value, &Value) -> Value),
|
||||||
Ternary(fn(&Value<'src>, &Value<'src>, &Value<'src>) -> Value<'src>),
|
Ternary(fn(&Value, &Value, &Value) -> Value),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eq<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
pub fn eq(x: &Value, y: &Value) -> Value {
|
||||||
Value::Boolean(x == y)
|
if x == y {
|
||||||
|
Value::True
|
||||||
|
} else {
|
||||||
|
Value::False
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
pub fn add(x: &Value, y: &Value) -> Value {
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
(Value::Number(x), Value::Number(y)) => Value::Number(x + y),
|
(Value::Number(x), Value::Number(y)) => Value::Number(x + y),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
pub fn sub(x: &Value, y: &Value) -> Value {
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
(Value::Number(x), Value::Number(y)) => Value::Number(x - y),
|
(Value::Number(x), Value::Number(y)) => Value::Number(x - y),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unbox<'src>(x: &Value<'src>) -> Value<'src> {
|
pub fn unbox(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::Box(_, cell) => cell.borrow().clone(),
|
Value::Box(cell) => cell.as_ref().borrow().clone(),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store<'src>(b: &Value<'src>, val: &Value<'src>) -> Value<'src> {
|
pub fn store(b: &Value, val: &Value) -> Value {
|
||||||
if let Value::Box(_, cell) = b {
|
if let Value::Box(cell) = b {
|
||||||
cell.replace(val.clone());
|
cell.replace(val.clone());
|
||||||
val.clone()
|
val.clone()
|
||||||
} else {
|
} else {
|
||||||
|
@ -47,103 +51,97 @@ pub fn store<'src>(b: &Value<'src>, val: &Value<'src>) -> Value<'src> {
|
||||||
|
|
||||||
// TODO: do better than returning just the docstr
|
// TODO: do better than returning just the docstr
|
||||||
// name, patterns, AND docstring
|
// name, patterns, AND docstring
|
||||||
pub fn doc<'src>(f: &Value<'src>) -> Value<'src> {
|
pub fn doc(f: &Value) -> Value {
|
||||||
match f {
|
match f {
|
||||||
Value::Fn(f) => {
|
Value::Fn(f) => {
|
||||||
let name = &f.borrow().name;
|
let lfn = f.as_ref().get().unwrap();
|
||||||
let doc = &f.borrow().doc;
|
let name = lfn.name;
|
||||||
|
let doc = lfn.doc;
|
||||||
if let Some(docstr) = doc {
|
if let Some(docstr) = doc {
|
||||||
Value::AllocatedString(Rc::new(format!("{name}: {docstr}")))
|
Value::String(Rc::new(format!("{name}: {docstr}")))
|
||||||
} else {
|
} else {
|
||||||
Value::AllocatedString(Rc::new(format!("{name}: no documentation found")))
|
Value::String(Rc::new(format!("{name}: no documentation found")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Value::InternedString("no documentation found"),
|
_ => Value::Interned("no documentation found"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn and<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
pub fn assoc(dict: &Value, key: &Value, value: &Value) -> Value {
|
||||||
Value::Boolean(x.bool() && y.bool())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn assoc<'src>(dict: &Value<'src>, key: &Value<'src>, value: &Value<'src>) -> Value<'src> {
|
|
||||||
match (dict, key) {
|
match (dict, key) {
|
||||||
(Value::Dict(d), Value::Keyword(k)) => Value::Dict(d.update(k, value.clone())),
|
(Value::Dict(d), Value::Keyword(k)) => Value::Dict(Box::new(d.update(k, value.clone()))),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn r#bool<'src>(x: &Value<'src>) -> Value<'src> {
|
pub fn r#bool(x: &Value) -> Value {
|
||||||
Value::Boolean(x.bool())
|
match x {
|
||||||
|
Value::Nil | Value::False => Value::False,
|
||||||
|
_ => Value::True,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chars<'src>(x: &Value<'src>) -> Value<'src> {
|
pub fn chars(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::InternedString(s) => {
|
Value::Interned(s) => {
|
||||||
let chars = s.chars();
|
let chars = s.chars();
|
||||||
|
|
||||||
let mut charlist = vector![];
|
let mut charlist = vector![];
|
||||||
for char in chars {
|
for char in chars {
|
||||||
if char.is_ascii() {
|
if char.is_ascii() {
|
||||||
charlist.push_back(Value::AllocatedString(Rc::new(char.to_string())))
|
charlist.push_back(Value::String(Rc::new(char.to_string())))
|
||||||
} else {
|
} else {
|
||||||
return Value::Tuple(Rc::new(vec![
|
return Value::Tuple(Rc::new(vec![
|
||||||
Value::Keyword("err"),
|
Value::Keyword("err"),
|
||||||
Value::AllocatedString(Rc::new(format!(
|
Value::String(Rc::new(format!("{char} is not an ascii character"))),
|
||||||
"{char} is not an ascii character"
|
|
||||||
))),
|
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::Tuple(Rc::new(vec![Value::Keyword("ok"), Value::List(charlist)]))
|
Value::Tuple(Rc::new(vec![
|
||||||
|
Value::Keyword("ok"),
|
||||||
|
Value::List(Box::new(charlist)),
|
||||||
|
]))
|
||||||
}
|
}
|
||||||
Value::AllocatedString(s) => {
|
Value::String(s) => {
|
||||||
let chars = s.chars();
|
let chars = s.chars();
|
||||||
|
|
||||||
let mut charlist = vector![];
|
let mut charlist = vector![];
|
||||||
for char in chars {
|
for char in chars {
|
||||||
if char.is_ascii() {
|
if char.is_ascii() {
|
||||||
charlist.push_back(Value::AllocatedString(Rc::new(char.to_string())))
|
charlist.push_back(Value::String(Rc::new(char.to_string())))
|
||||||
} else {
|
} else {
|
||||||
return Value::Tuple(Rc::new(vec![
|
return Value::Tuple(Rc::new(vec![
|
||||||
Value::Keyword("err"),
|
Value::Keyword("err"),
|
||||||
Value::AllocatedString(Rc::new(format!(
|
Value::String(Rc::new(format!("{char} is not an ascii character"))),
|
||||||
"{char} is not an ascii character"
|
|
||||||
))),
|
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::Tuple(Rc::new(vec![Value::Keyword("ok"), Value::List(charlist)]))
|
Value::Tuple(Rc::new(vec![
|
||||||
|
Value::Keyword("ok"),
|
||||||
|
Value::List(Box::new(charlist)),
|
||||||
|
]))
|
||||||
}
|
}
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: figure out how to get to opportunistic mutation here
|
// TODO: figure out how to get to opportunistic mutation here
|
||||||
pub fn concat<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
pub fn concat(x: &Value, y: &Value) -> Value {
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
(Value::InternedString(x), Value::InternedString(y)) => {
|
(Value::Interned(x), Value::Interned(y)) => Value::String(Rc::new(format!("{x}{y}"))),
|
||||||
Value::AllocatedString(Rc::new(format!("{x}{y}")))
|
(Value::String(x), Value::String(y)) => Value::String(Rc::new(format!("{x}{y}"))),
|
||||||
}
|
(Value::String(x), Value::Interned(y)) => Value::String(Rc::new(format!("{x}{y}"))),
|
||||||
(Value::AllocatedString(x), Value::AllocatedString(y)) => {
|
(Value::Interned(x), Value::String(y)) => Value::String(Rc::new(format!("{x}{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)) => {
|
(Value::List(x), Value::List(y)) => {
|
||||||
let mut newlist = x.clone();
|
let mut newlist = *x.clone();
|
||||||
newlist.append(y.clone());
|
newlist.append(*y.clone());
|
||||||
Value::List(newlist)
|
Value::List(Box::new(newlist))
|
||||||
}
|
}
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
pub fn append(x: &Value, y: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::List(list) => {
|
Value::List(list) => {
|
||||||
let mut newlist = list.clone();
|
let mut newlist = list.clone();
|
||||||
|
@ -154,35 +152,35 @@ pub fn append<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dec<'src>(x: &Value<'src>) -> Value<'src> {
|
pub fn dec(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::Number(n) => Value::Number(n - 1.0),
|
Value::Number(n) => Value::Number(n - 1.0),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inc<'src>(x: &Value<'src>) -> Value<'src> {
|
pub fn inc(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::Number(n) => Value::Number(n + 1.0),
|
Value::Number(n) => Value::Number(n + 1.0),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn div<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
pub fn div(x: &Value, y: &Value) -> Value {
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
(Value::Number(x), Value::Number(y)) => Value::Number(x / y),
|
(Value::Number(x), Value::Number(y)) => Value::Number(x / y),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mult<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
pub fn mult(x: &Value, y: &Value) -> Value {
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
(Value::Number(x), Value::Number(y)) => Value::Number(x * y),
|
(Value::Number(x), Value::Number(y)) => Value::Number(x * y),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dissoc<'src>(dict: &Value<'src>, key: &Value<'src>) -> Value<'src> {
|
pub fn dissoc(dict: &Value, key: &Value) -> Value {
|
||||||
match (dict, key) {
|
match (dict, key) {
|
||||||
(Value::Dict(dict), Value::Keyword(key)) => {
|
(Value::Dict(dict), Value::Keyword(key)) => {
|
||||||
let mut new = dict.clone();
|
let mut new = dict.clone();
|
||||||
|
@ -193,7 +191,7 @@ pub fn dissoc<'src>(dict: &Value<'src>, key: &Value<'src>) -> Value<'src> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn first<'src>(ordered: &Value<'src>) -> Value<'src> {
|
pub fn first(ordered: &Value) -> Value {
|
||||||
match ordered {
|
match ordered {
|
||||||
Value::List(list) => match list.front() {
|
Value::List(list) => match list.front() {
|
||||||
Some(n) => n.clone(),
|
Some(n) => n.clone(),
|
||||||
|
@ -209,7 +207,7 @@ pub fn first<'src>(ordered: &Value<'src>) -> Value<'src> {
|
||||||
|
|
||||||
// TODO: figure out how to handle negative numbers
|
// TODO: figure out how to handle negative numbers
|
||||||
// the cast from f64 to usize discards sign info
|
// the cast from f64 to usize discards sign info
|
||||||
pub fn at<'src>(ordered: &Value<'src>, i: &Value<'src>) -> Value<'src> {
|
pub fn at(ordered: &Value, i: &Value) -> Value {
|
||||||
match (ordered, i) {
|
match (ordered, i) {
|
||||||
(Value::List(list), Value::Number(n)) => {
|
(Value::List(list), Value::Number(n)) => {
|
||||||
let i = *n as usize;
|
let i = *n as usize;
|
||||||
|
@ -229,7 +227,7 @@ pub fn at<'src>(ordered: &Value<'src>, i: &Value<'src>) -> Value<'src> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get<'src>(dict: &Value<'src>, key: &Value<'src>) -> Value<'src> {
|
pub fn get(dict: &Value, key: &Value) -> Value {
|
||||||
match (dict, key) {
|
match (dict, key) {
|
||||||
(Value::Dict(dict), Value::Keyword(key)) => match dict.get(key) {
|
(Value::Dict(dict), Value::Keyword(key)) => match dict.get(key) {
|
||||||
Some(x) => x.clone(),
|
Some(x) => x.clone(),
|
||||||
|
@ -239,7 +237,7 @@ pub fn get<'src>(dict: &Value<'src>, key: &Value<'src>) -> Value<'src> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn last<'src>(ordered: &Value<'src>) -> Value<'src> {
|
pub fn last(ordered: &Value) -> Value {
|
||||||
match ordered {
|
match ordered {
|
||||||
Value::List(list) => match list.last() {
|
Value::List(list) => match list.last() {
|
||||||
Some(x) => x.clone(),
|
Some(x) => x.clone(),
|
||||||
|
@ -253,12 +251,8 @@ pub fn last<'src>(ordered: &Value<'src>) -> Value<'src> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn or<'src>(x: &Value<'src>, y: &Value<'src>) -> Value<'src> {
|
|
||||||
Value::Boolean(x.bool() || y.bool())
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: fix this: x is a list of all the args passed to Ludus's print!
|
// TODO: fix this: x is a list of all the args passed to Ludus's print!
|
||||||
pub fn print<'src>(x: &Value<'src>) -> Value<'src> {
|
pub fn print(x: &Value) -> Value {
|
||||||
let Value::List(args) = x else {
|
let Value::List(args) = x else {
|
||||||
unreachable!("internal Ludus error")
|
unreachable!("internal Ludus error")
|
||||||
};
|
};
|
||||||
|
@ -271,30 +265,32 @@ pub fn print<'src>(x: &Value<'src>) -> Value<'src> {
|
||||||
Value::Keyword("ok")
|
Value::Keyword("ok")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show<'src>(x: &Value<'src>) -> Value<'src> {
|
pub fn show(x: &Value) -> Value {
|
||||||
Value::AllocatedString(Rc::new(format!("{x}")))
|
Value::String(Rc::new(format!("{x}")))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rest<'src>(ordered: &Value<'src>) -> Value<'src> {
|
pub fn rest(ordered: &Value) -> Value {
|
||||||
match ordered {
|
match ordered {
|
||||||
Value::List(list) => Value::List(list.clone().split_at(1).1),
|
Value::List(list) => Value::List(Box::new(list.clone().split_at(1).1)),
|
||||||
Value::Tuple(tuple) => Value::List(Vector::from_iter(tuple.iter().next().cloned())),
|
Value::Tuple(tuple) => {
|
||||||
|
Value::List(Box::new(Vector::from_iter(tuple.iter().next().cloned())))
|
||||||
|
}
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count<'src>(coll: &Value<'src>) -> Value<'src> {
|
pub fn count(coll: &Value) -> Value {
|
||||||
match coll {
|
match coll {
|
||||||
Value::Dict(d) => Value::Number(d.len() as f64),
|
Value::Dict(d) => Value::Number(d.len() as f64),
|
||||||
Value::List(l) => Value::Number(l.len() as f64),
|
Value::List(l) => Value::Number(l.len() as f64),
|
||||||
Value::Tuple(t) => Value::Number(t.len() as f64),
|
Value::Tuple(t) => Value::Number(t.len() as f64),
|
||||||
Value::AllocatedString(s) => Value::Number(s.len() as f64),
|
Value::String(s) => Value::Number(s.len() as f64),
|
||||||
Value::InternedString(s) => Value::Number(s.len() as f64),
|
Value::Interned(s) => Value::Number(s.len() as f64),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn range<'src>(start: &Value<'src>, end: &Value<'src>) -> Value<'src> {
|
pub fn range(start: &Value, end: &Value) -> Value {
|
||||||
match (start, end) {
|
match (start, end) {
|
||||||
(Value::Number(start), Value::Number(end)) => {
|
(Value::Number(start), Value::Number(end)) => {
|
||||||
let start = *start as isize;
|
let start = *start as isize;
|
||||||
|
@ -303,25 +299,25 @@ pub fn range<'src>(start: &Value<'src>, end: &Value<'src>) -> Value<'src> {
|
||||||
for n in start..end {
|
for n in start..end {
|
||||||
range.push_back(Value::Number(n as f64))
|
range.push_back(Value::Number(n as f64))
|
||||||
}
|
}
|
||||||
Value::List(range)
|
Value::List(Box::new(range))
|
||||||
}
|
}
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn slice<'src>(ordered: &Value<'src>, start: &Value<'src>, end: &Value<'src>) -> Value<'src> {
|
pub fn slice(ordered: &Value, start: &Value, end: &Value) -> Value {
|
||||||
match (ordered, start, end) {
|
match (ordered, start, end) {
|
||||||
(Value::List(list), Value::Number(start), Value::Number(end)) => {
|
(Value::List(list), Value::Number(start), Value::Number(end)) => {
|
||||||
let mut newlist = list.clone();
|
let mut newlist = list.clone();
|
||||||
let start = std::cmp::max(*start as usize, 0);
|
let start = std::cmp::max(*start as usize, 0);
|
||||||
let end = std::cmp::min(*end as usize, list.len());
|
let end = std::cmp::min(*end as usize, list.len());
|
||||||
Value::List(newlist.slice(start..end))
|
Value::List(Box::new(newlist.slice(start..end)))
|
||||||
}
|
}
|
||||||
// TODO: figure out something better to do than return an empty string on a bad slice
|
// 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)) => {
|
(Value::String(string), Value::Number(start), Value::Number(end)) => {
|
||||||
let start = std::cmp::max(*start as usize, 0);
|
let start = std::cmp::max(*start as usize, 0);
|
||||||
let end = std::cmp::min(*end as usize, string.len());
|
let end = std::cmp::min(*end as usize, string.len());
|
||||||
Value::AllocatedString(Rc::new(
|
Value::String(Rc::new(
|
||||||
string
|
string
|
||||||
.clone()
|
.clone()
|
||||||
.as_str()
|
.as_str()
|
||||||
|
@ -330,19 +326,19 @@ pub fn slice<'src>(ordered: &Value<'src>, start: &Value<'src>, end: &Value<'src>
|
||||||
.to_string(),
|
.to_string(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
(Value::InternedString(string), Value::Number(start), Value::Number(end)) => {
|
(Value::Interned(string), Value::Number(start), Value::Number(end)) => {
|
||||||
let start = std::cmp::max(*start as usize, 0);
|
let start = std::cmp::max(*start as usize, 0);
|
||||||
let end = std::cmp::min(*end as usize, string.len());
|
let end = std::cmp::min(*end as usize, string.len());
|
||||||
Value::AllocatedString(Rc::new(string.get(start..end).unwrap_or("").to_string()))
|
Value::String(Rc::new(string.get(start..end).unwrap_or("").to_string()))
|
||||||
}
|
}
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list<'src>(x: &Value<'src>) -> Value<'src> {
|
pub fn list(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::List(_) => x.clone(),
|
Value::List(_) => x.clone(),
|
||||||
Value::Tuple(t) => Value::List(Vector::from_iter(t.iter().cloned())),
|
Value::Tuple(t) => Value::List(Box::new(Vector::from_iter(t.iter().cloned()))),
|
||||||
Value::Dict(d) => {
|
Value::Dict(d) => {
|
||||||
let kvs = d.iter();
|
let kvs = d.iter();
|
||||||
let mut list = vector![];
|
let mut list = vector![];
|
||||||
|
@ -350,292 +346,300 @@ pub fn list<'src>(x: &Value<'src>) -> Value<'src> {
|
||||||
let kv = Value::Tuple(Rc::new(vec![Value::Keyword(key), value.clone()]));
|
let kv = Value::Tuple(Rc::new(vec![Value::Keyword(key), value.clone()]));
|
||||||
list.push_back(kv);
|
list.push_back(kv);
|
||||||
}
|
}
|
||||||
Value::List(list)
|
Value::List(Box::new(list))
|
||||||
}
|
}
|
||||||
_ => Value::List(vector![x.clone()]),
|
_ => Value::List(Box::new(vector![x.clone()])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn number<'src>(x: &Value<'src>) -> Value<'src> {
|
pub fn number(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::InternedString(string) => match string.parse::<f64>() {
|
Value::Interned(string) => match string.parse::<f64>() {
|
||||||
Ok(n) => Value::Tuple(Rc::new(vec![Value::Keyword("ok"), Value::Number(n)])),
|
Ok(n) => Value::Tuple(Rc::new(vec![Value::Keyword("ok"), Value::Number(n)])),
|
||||||
Err(_) => Value::Tuple(Rc::new(vec![
|
Err(_) => Value::Tuple(Rc::new(vec![
|
||||||
Value::Keyword("err"),
|
Value::Keyword("err"),
|
||||||
Value::AllocatedString(Rc::new(format!("could not parse `{string}` as a number"))),
|
Value::String(Rc::new(format!("could not parse `{string}` as a number"))),
|
||||||
])),
|
])),
|
||||||
},
|
},
|
||||||
Value::AllocatedString(string) => match string.parse::<f64>() {
|
Value::String(string) => match string.parse::<f64>() {
|
||||||
Ok(n) => Value::Tuple(Rc::new(vec![Value::Keyword("ok"), Value::Number(n)])),
|
Ok(n) => Value::Tuple(Rc::new(vec![Value::Keyword("ok"), Value::Number(n)])),
|
||||||
Err(_) => Value::Tuple(Rc::new(vec![
|
Err(_) => Value::Tuple(Rc::new(vec![
|
||||||
Value::Keyword("err"),
|
Value::Keyword("err"),
|
||||||
Value::AllocatedString(Rc::new(format!("could not parse `{string}` as a number"))),
|
Value::String(Rc::new(format!("could not parse `{string}` as a number"))),
|
||||||
])),
|
])),
|
||||||
},
|
},
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn r#type<'src>(x: &Value<'src>) -> Value<'src> {
|
pub fn r#type(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::Nil => Value::Keyword("nil"),
|
Value::Nil => Value::Keyword("nil"),
|
||||||
Value::Number(_) => Value::Keyword("number"),
|
Value::Number(_) => Value::Keyword("number"),
|
||||||
Value::Boolean(_) => Value::Keyword("boolean"),
|
Value::True | Value::False => Value::Keyword("bool"),
|
||||||
Value::Keyword(_) => Value::Keyword("keyword"),
|
Value::Keyword(_) => Value::Keyword("keyword"),
|
||||||
Value::Tuple(_) => Value::Keyword("tuple"),
|
Value::Tuple(_) => Value::Keyword("tuple"),
|
||||||
Value::InternedString(_) => Value::Keyword("string"),
|
Value::Interned(_) => Value::Keyword("string"),
|
||||||
Value::AllocatedString(_) => Value::Keyword("string"),
|
Value::String(_) => Value::Keyword("string"),
|
||||||
Value::List(_) => Value::Keyword("list"),
|
Value::List(_) => Value::Keyword("list"),
|
||||||
Value::Dict(_) => Value::Keyword("dict"),
|
Value::Dict(_) => Value::Keyword("dict"),
|
||||||
Value::Fn(_) => Value::Keyword("fn"),
|
Value::Fn(_) => Value::Keyword("fn"),
|
||||||
Value::Box(_, _) => Value::Keyword("box"),
|
Value::Box(_) => Value::Keyword("box"),
|
||||||
Value::Placeholder => unreachable!("internal Ludus error"),
|
Value::BaseFn(_) => Value::Keyword("fn"),
|
||||||
Value::Args(_) => unreachable!("internal Ludus error"),
|
Value::Nothing => unreachable!(),
|
||||||
Value::Base(_) => Value::Keyword("fn"),
|
|
||||||
Value::Recur(..) => unreachable!("internal Ludus error"),
|
|
||||||
Value::FnDecl(_) => Value::Keyword("fn"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split<'src>(source: &Value<'src>, splitter: &Value) -> Value<'src> {
|
pub fn split(source: &Value, splitter: &Value) -> Value {
|
||||||
match (source, splitter) {
|
match (source, splitter) {
|
||||||
(Value::AllocatedString(source), Value::AllocatedString(splitter)) => {
|
(Value::String(source), Value::String(splitter)) => {
|
||||||
let parts = source.split_terminator(splitter.as_str());
|
let parts = source.split_terminator(splitter.as_str());
|
||||||
let mut list = vector![];
|
let mut list = vector![];
|
||||||
for part in parts {
|
for part in parts {
|
||||||
list.push_back(Value::AllocatedString(Rc::new(part.to_string())));
|
list.push_back(Value::String(Rc::new(part.to_string())));
|
||||||
}
|
}
|
||||||
Value::List(list)
|
Value::List(Box::new(list))
|
||||||
}
|
}
|
||||||
(Value::AllocatedString(source), Value::InternedString(splitter)) => {
|
(Value::String(source), Value::Interned(splitter)) => {
|
||||||
let parts = source.split_terminator(splitter);
|
let parts = source.split_terminator(splitter);
|
||||||
let mut list = vector![];
|
let mut list = vector![];
|
||||||
for part in parts {
|
for part in parts {
|
||||||
list.push_back(Value::AllocatedString(Rc::new(part.to_string())));
|
list.push_back(Value::String(Rc::new(part.to_string())));
|
||||||
}
|
}
|
||||||
Value::List(list)
|
Value::List(Box::new(list))
|
||||||
}
|
}
|
||||||
(Value::InternedString(source), Value::AllocatedString(splitter)) => {
|
(Value::Interned(source), Value::String(splitter)) => {
|
||||||
let parts = source.split_terminator(splitter.as_str());
|
let parts = source.split_terminator(splitter.as_str());
|
||||||
let mut list = vector![];
|
let mut list = vector![];
|
||||||
for part in parts {
|
for part in parts {
|
||||||
list.push_back(Value::AllocatedString(Rc::new(part.to_string())));
|
list.push_back(Value::String(Rc::new(part.to_string())));
|
||||||
}
|
}
|
||||||
Value::List(list)
|
Value::List(Box::new(list))
|
||||||
}
|
}
|
||||||
(Value::InternedString(source), Value::InternedString(splitter)) => {
|
(Value::Interned(source), Value::Interned(splitter)) => {
|
||||||
let parts = source.split_terminator(splitter);
|
let parts = source.split_terminator(splitter);
|
||||||
let mut list = vector![];
|
let mut list = vector![];
|
||||||
for part in parts {
|
for part in parts {
|
||||||
list.push_back(Value::AllocatedString(Rc::new(part.to_string())));
|
list.push_back(Value::String(Rc::new(part.to_string())));
|
||||||
}
|
}
|
||||||
Value::List(list)
|
Value::List(Box::new(list))
|
||||||
}
|
}
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upcase<'src>(string: &Value<'src>) -> Value<'src> {
|
pub fn upcase(string: &Value) -> Value {
|
||||||
match string {
|
match string {
|
||||||
Value::AllocatedString(string) => Value::AllocatedString(Rc::new(string.to_uppercase())),
|
Value::String(string) => Value::String(Rc::new(string.to_uppercase())),
|
||||||
Value::InternedString(string) => Value::AllocatedString(Rc::new(string.to_uppercase())),
|
Value::Interned(string) => Value::String(Rc::new(string.to_uppercase())),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn downcase<'src>(string: &Value<'src>) -> Value<'src> {
|
pub fn downcase(string: &Value) -> Value {
|
||||||
match string {
|
match string {
|
||||||
Value::AllocatedString(string) => Value::AllocatedString(Rc::new(string.to_lowercase())),
|
Value::String(string) => Value::String(Rc::new(string.to_lowercase())),
|
||||||
Value::InternedString(string) => Value::AllocatedString(Rc::new(string.to_lowercase())),
|
Value::Interned(string) => Value::String(Rc::new(string.to_lowercase())),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trim<'src>(string: &Value<'src>) -> Value<'src> {
|
pub fn trim(string: &Value) -> Value {
|
||||||
match string {
|
match string {
|
||||||
Value::AllocatedString(string) => {
|
Value::String(string) => Value::String(Rc::new(string.trim().to_string())),
|
||||||
Value::AllocatedString(Rc::new(string.trim().to_string()))
|
Value::Interned(string) => Value::String(Rc::new(string.trim().to_string())),
|
||||||
}
|
|
||||||
Value::InternedString(string) => Value::AllocatedString(Rc::new(string.trim().to_string())),
|
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn triml<'src>(string: &Value<'src>) -> Value<'src> {
|
pub fn triml(string: &Value) -> Value {
|
||||||
match string {
|
match string {
|
||||||
Value::AllocatedString(string) => {
|
Value::String(string) => Value::String(Rc::new(string.trim_start().to_string())),
|
||||||
Value::AllocatedString(Rc::new(string.trim_start().to_string()))
|
Value::Interned(string) => Value::String(Rc::new(string.trim_start().to_string())),
|
||||||
}
|
|
||||||
Value::InternedString(string) => {
|
|
||||||
Value::AllocatedString(Rc::new(string.trim_start().to_string()))
|
|
||||||
}
|
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trimr<'src>(string: &Value<'src>) -> Value<'src> {
|
pub fn trimr(string: &Value) -> Value {
|
||||||
match string {
|
match string {
|
||||||
Value::AllocatedString(string) => {
|
Value::String(string) => Value::String(Rc::new(string.trim_end().to_string())),
|
||||||
Value::AllocatedString(Rc::new(string.trim_end().to_string()))
|
Value::Interned(string) => Value::String(Rc::new(string.trim_end().to_string())),
|
||||||
}
|
|
||||||
Value::InternedString(string) => {
|
|
||||||
Value::AllocatedString(Rc::new(string.trim_end().to_string()))
|
|
||||||
}
|
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn atan_2<'src>(x: &Value, y: &Value) -> Value<'src> {
|
pub fn atan_2(x: &Value, y: &Value) -> Value {
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
(Value::Number(x), Value::Number(y)) => Value::Number(x.atan2(*y)),
|
(Value::Number(x), Value::Number(y)) => Value::Number(x.atan2(*y)),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ceil<'src>(x: &Value) -> Value<'src> {
|
pub fn ceil(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::Number(x) => Value::Number(x.ceil()),
|
Value::Number(x) => Value::Number(x.ceil()),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cos<'src>(x: &Value) -> Value<'src> {
|
pub fn cos(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::Number(x) => Value::Number(x.cos()),
|
Value::Number(x) => Value::Number(x.cos()),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn floor<'src>(x: &Value) -> Value<'src> {
|
pub fn floor(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::Number(x) => Value::Number(x.floor()),
|
Value::Number(x) => Value::Number(x.floor()),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn random<'src>() -> Value<'src> {
|
pub fn random() -> Value {
|
||||||
Value::Number(ran_f64())
|
Value::Number(ran_f64())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn round<'src>(x: &Value) -> Value<'src> {
|
pub fn round(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::Number(x) => Value::Number(x.round()),
|
Value::Number(x) => Value::Number(x.round()),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sin<'src>(x: &Value) -> Value<'src> {
|
pub fn sin(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::Number(x) => Value::Number(x.sin()),
|
Value::Number(x) => Value::Number(x.sin()),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sqrt<'src>(x: &Value) -> Value<'src> {
|
pub fn sqrt(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::Number(x) => Value::Number(x.sqrt()),
|
Value::Number(x) => Value::Number(x.sqrt()),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tan<'src>(x: &Value) -> Value<'src> {
|
pub fn tan(x: &Value) -> Value {
|
||||||
match x {
|
match x {
|
||||||
Value::Number(x) => Value::Number(x.tan()),
|
Value::Number(x) => Value::Number(x.tan()),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gt<'src>(x: &Value, y: &Value) -> Value<'src> {
|
pub fn gt(x: &Value, y: &Value) -> Value {
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
(Value::Number(x), Value::Number(y)) => Value::Boolean(x > y),
|
(Value::Number(x), Value::Number(y)) => {
|
||||||
|
if x > y {
|
||||||
|
Value::True
|
||||||
|
} else {
|
||||||
|
Value::False
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gte<'src>(x: &Value, y: &Value) -> Value<'src> {
|
pub fn gte(x: &Value, y: &Value) -> Value {
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
(Value::Number(x), Value::Number(y)) => Value::Boolean(x >= y),
|
(Value::Number(x), Value::Number(y)) => {
|
||||||
|
if x >= y {
|
||||||
|
Value::True
|
||||||
|
} else {
|
||||||
|
Value::False
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lt<'src>(x: &Value, y: &Value) -> Value<'src> {
|
pub fn lt(x: &Value, y: &Value) -> Value {
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
(Value::Number(x), Value::Number(y)) => Value::Boolean(x < y),
|
(Value::Number(x), Value::Number(y)) => {
|
||||||
|
if x < y {
|
||||||
|
Value::True
|
||||||
|
} else {
|
||||||
|
Value::False
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lte<'src>(x: &Value, y: &Value) -> Value<'src> {
|
pub fn lte(x: &Value, y: &Value) -> Value {
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
(Value::Number(x), Value::Number(y)) => Value::Boolean(x <= y),
|
(Value::Number(x), Value::Number(y)) => {
|
||||||
|
if x <= y {
|
||||||
|
Value::True
|
||||||
|
} else {
|
||||||
|
Value::False
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn r#mod<'src>(x: &Value, y: &Value) -> Value<'src> {
|
pub fn r#mod(x: &Value, y: &Value) -> Value {
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
(Value::Number(x), Value::Number(y)) => Value::Number(x % y),
|
(Value::Number(x), Value::Number(y)) => Value::Number(x % y),
|
||||||
_ => unreachable!("internal Ludus error"),
|
_ => unreachable!("internal Ludus error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn base<'src>() -> Vec<(String, Value<'src>)> {
|
pub fn base() -> Value {
|
||||||
let members = vec![
|
let members = vec![
|
||||||
("add", Value::Base(BaseFn::Binary(add))),
|
("add", Value::BaseFn(BaseFn::Binary(add))),
|
||||||
("and", Value::Base(BaseFn::Binary(and))),
|
("append", Value::BaseFn(BaseFn::Binary(append))),
|
||||||
("append", Value::Base(BaseFn::Binary(append))),
|
("assoc", Value::BaseFn(BaseFn::Ternary(assoc))),
|
||||||
("assoc", Value::Base(BaseFn::Ternary(assoc))),
|
("at", Value::BaseFn(BaseFn::Binary(at))),
|
||||||
("at", Value::Base(BaseFn::Binary(at))),
|
("atan_2", Value::BaseFn(BaseFn::Binary(atan_2))),
|
||||||
("atan_2", Value::Base(BaseFn::Binary(atan_2))),
|
("bool", Value::BaseFn(BaseFn::Unary(r#bool))),
|
||||||
("bool", Value::Base(BaseFn::Unary(r#bool))),
|
("ceil", Value::BaseFn(BaseFn::Unary(ceil))),
|
||||||
("ceil", Value::Base(BaseFn::Unary(ceil))),
|
("chars", Value::BaseFn(BaseFn::Unary(chars))),
|
||||||
("chars", Value::Base(BaseFn::Unary(chars))),
|
("concat", Value::BaseFn(BaseFn::Binary(concat))),
|
||||||
("concat", Value::Base(BaseFn::Binary(concat))),
|
("cos", Value::BaseFn(BaseFn::Unary(cos))),
|
||||||
("cos", Value::Base(BaseFn::Unary(cos))),
|
("count", Value::BaseFn(BaseFn::Unary(count))),
|
||||||
("count", Value::Base(BaseFn::Unary(count))),
|
("dec", Value::BaseFn(BaseFn::Unary(dec))),
|
||||||
("dec", Value::Base(BaseFn::Unary(dec))),
|
("dissoc", Value::BaseFn(BaseFn::Binary(dissoc))),
|
||||||
("dissoc", Value::Base(BaseFn::Binary(dissoc))),
|
("div", Value::BaseFn(BaseFn::Binary(div))),
|
||||||
("div", Value::Base(BaseFn::Binary(div))),
|
("doc!", Value::BaseFn(BaseFn::Unary(doc))),
|
||||||
("doc!", Value::Base(BaseFn::Unary(doc))),
|
("downcase", Value::BaseFn(BaseFn::Unary(downcase))),
|
||||||
("downcase", Value::Base(BaseFn::Unary(downcase))),
|
("eq?", Value::BaseFn(BaseFn::Binary(eq))),
|
||||||
("eq?", Value::Base(BaseFn::Binary(eq))),
|
("first", Value::BaseFn(BaseFn::Unary(first))),
|
||||||
("first", Value::Base(BaseFn::Unary(first))),
|
("floor", Value::BaseFn(BaseFn::Unary(floor))),
|
||||||
("floor", Value::Base(BaseFn::Unary(floor))),
|
("get", Value::BaseFn(BaseFn::Binary(get))),
|
||||||
("get", Value::Base(BaseFn::Binary(get))),
|
("gt?", Value::BaseFn(BaseFn::Binary(gt))),
|
||||||
("gt?", Value::Base(BaseFn::Binary(gt))),
|
("gte?", Value::BaseFn(BaseFn::Binary(gte))),
|
||||||
("gte?", Value::Base(BaseFn::Binary(gte))),
|
("inc", Value::BaseFn(BaseFn::Unary(inc))),
|
||||||
("inc", Value::Base(BaseFn::Unary(inc))),
|
("last", Value::BaseFn(BaseFn::Unary(last))),
|
||||||
("last", Value::Base(BaseFn::Unary(last))),
|
("list", Value::BaseFn(BaseFn::Unary(list))),
|
||||||
("list", Value::Base(BaseFn::Unary(list))),
|
("lt?", Value::BaseFn(BaseFn::Binary(lt))),
|
||||||
("lt?", Value::Base(BaseFn::Binary(lt))),
|
("lte?", Value::BaseFn(BaseFn::Binary(lte))),
|
||||||
("lte?", Value::Base(BaseFn::Binary(lte))),
|
("mod", Value::BaseFn(BaseFn::Binary(r#mod))),
|
||||||
("mod", Value::Base(BaseFn::Binary(r#mod))),
|
("mult", Value::BaseFn(BaseFn::Binary(mult))),
|
||||||
("mult", Value::Base(BaseFn::Binary(mult))),
|
("number", Value::BaseFn(BaseFn::Unary(number))),
|
||||||
("number", Value::Base(BaseFn::Unary(number))),
|
|
||||||
("or", Value::Base(BaseFn::Binary(or))),
|
|
||||||
("pi", Value::Number(std::f64::consts::PI)),
|
("pi", Value::Number(std::f64::consts::PI)),
|
||||||
("print!", Value::Base(BaseFn::Unary(print))),
|
("print!", Value::BaseFn(BaseFn::Unary(print))),
|
||||||
("random", Value::Base(BaseFn::Nullary(random))),
|
("random", Value::BaseFn(BaseFn::Nullary(random))),
|
||||||
("range", Value::Base(BaseFn::Binary(range))),
|
("range", Value::BaseFn(BaseFn::Binary(range))),
|
||||||
("rest", Value::Base(BaseFn::Unary(rest))),
|
("rest", Value::BaseFn(BaseFn::Unary(rest))),
|
||||||
("round", Value::Base(BaseFn::Unary(round))),
|
("round", Value::BaseFn(BaseFn::Unary(round))),
|
||||||
("show", Value::Base(BaseFn::Unary(show))),
|
("show", Value::BaseFn(BaseFn::Unary(show))),
|
||||||
("sin", Value::Base(BaseFn::Unary(sin))),
|
("sin", Value::BaseFn(BaseFn::Unary(sin))),
|
||||||
("slice", Value::Base(BaseFn::Ternary(slice))),
|
("slice", Value::BaseFn(BaseFn::Ternary(slice))),
|
||||||
("split", Value::Base(BaseFn::Binary(split))),
|
("split", Value::BaseFn(BaseFn::Binary(split))),
|
||||||
("sqrt", Value::Base(BaseFn::Unary(sqrt))),
|
("sqrt", Value::BaseFn(BaseFn::Unary(sqrt))),
|
||||||
("sqrt_2", Value::Number(std::f64::consts::SQRT_2)),
|
("sqrt_2", Value::Number(std::f64::consts::SQRT_2)),
|
||||||
("store!", Value::Base(BaseFn::Binary(store))),
|
("store!", Value::BaseFn(BaseFn::Binary(store))),
|
||||||
("sub", Value::Base(BaseFn::Binary(sub))),
|
("sub", Value::BaseFn(BaseFn::Binary(sub))),
|
||||||
("tan", Value::Base(BaseFn::Unary(tan))),
|
("tan", Value::BaseFn(BaseFn::Unary(tan))),
|
||||||
("trim", Value::Base(BaseFn::Unary(trim))),
|
("trim", Value::BaseFn(BaseFn::Unary(trim))),
|
||||||
("triml", Value::Base(BaseFn::Unary(triml))),
|
("triml", Value::BaseFn(BaseFn::Unary(triml))),
|
||||||
("trimr", Value::Base(BaseFn::Unary(trimr))),
|
("trimr", Value::BaseFn(BaseFn::Unary(trimr))),
|
||||||
("type", Value::Base(BaseFn::Unary(r#type))),
|
("type", Value::BaseFn(BaseFn::Unary(r#type))),
|
||||||
("unbox", Value::Base(BaseFn::Unary(unbox))),
|
("unbox", Value::BaseFn(BaseFn::Unary(unbox))),
|
||||||
("upcase", Value::Base(BaseFn::Unary(upcase))),
|
("upcase", Value::BaseFn(BaseFn::Unary(upcase))),
|
||||||
];
|
];
|
||||||
let pkg = Value::Dict(HashMap::from(members));
|
Value::Dict(Box::new(HashMap::from(members)))
|
||||||
vec![("base".to_string(), pkg)]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1039,23 +1039,6 @@ impl Compiler {
|
||||||
compiler.scope_depth -= 1;
|
compiler.scope_depth -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// let mut the_chunks = vec![];
|
|
||||||
|
|
||||||
// for (arity, chunks) in chunks.iter() {
|
|
||||||
// let mut jump_len: u8 = 0;
|
|
||||||
// for chunk in chunks.iter().rev() {
|
|
||||||
// let chunk_len = chunk.bytecode.len();
|
|
||||||
// chunk.bytecode[chunk_len - 1] = jump_len;
|
|
||||||
// jump_len += chunk_len as u8;
|
|
||||||
// }
|
|
||||||
// let the_chunk = chunks.into_iter().fold(vec![], |chunks, chunk| {
|
|
||||||
// chunks.append();
|
|
||||||
// chunks
|
|
||||||
// });
|
|
||||||
// the_chunks.push((arity, the_chunk))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
let mut the_chunks = vec![];
|
let mut the_chunks = vec![];
|
||||||
|
|
||||||
for (arity, mut compiler) in compilers.into_iter() {
|
for (arity, mut compiler) in compilers.into_iter() {
|
||||||
|
@ -1080,6 +1063,7 @@ impl Compiler {
|
||||||
let init_val = Value::Fn(Rc::new(cell));
|
let init_val = Value::Fn(Rc::new(cell));
|
||||||
self.emit_constant(init_val);
|
self.emit_constant(init_val);
|
||||||
self.bind(name);
|
self.bind(name);
|
||||||
|
|
||||||
// TODO: close over everything accessed in the function
|
// TODO: close over everything accessed in the function
|
||||||
|
|
||||||
// TODO: pull the function off the stack, and set the OnceCell.
|
// TODO: pull the function off the stack, and set the OnceCell.
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::env;
|
||||||
const DEBUG_COMPILE: bool = true;
|
const DEBUG_COMPILE: bool = true;
|
||||||
const DEBUG_RUN: bool = true;
|
const DEBUG_RUN: bool = true;
|
||||||
|
|
||||||
// mod base;
|
mod base;
|
||||||
|
|
||||||
mod spans;
|
mod spans;
|
||||||
use crate::spans::Spanned;
|
use crate::spans::Spanned;
|
||||||
|
@ -82,10 +82,10 @@ fn foo () -> {
|
||||||
(x, y)
|
(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
let x = foo ()
|
let a = foo ()
|
||||||
let y = foo ()
|
let b = foo ()
|
||||||
|
|
||||||
(x, y)
|
(a, b)
|
||||||
";
|
";
|
||||||
run(src);
|
run(src);
|
||||||
}
|
}
|
||||||
|
|
30
src/value.rs
30
src/value.rs
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::base::BaseFn;
|
||||||
use crate::compiler::Chunk;
|
use crate::compiler::Chunk;
|
||||||
use crate::parser::Ast;
|
use crate::parser::Ast;
|
||||||
use crate::spans::Spanned;
|
use crate::spans::Spanned;
|
||||||
|
@ -23,7 +24,7 @@ impl LFn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Nothing,
|
Nothing,
|
||||||
Nil,
|
Nil,
|
||||||
|
@ -38,6 +39,28 @@ pub enum Value {
|
||||||
Dict(Box<HashMap<&'static str, Value>>),
|
Dict(Box<HashMap<&'static str, Value>>),
|
||||||
Box(Rc<RefCell<Value>>),
|
Box(Rc<RefCell<Value>>),
|
||||||
Fn(Rc<OnceCell<LFn>>),
|
Fn(Rc<OnceCell<LFn>>),
|
||||||
|
BaseFn(BaseFn),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Value {
|
||||||
|
fn eq(&self, other: &Value) -> bool {
|
||||||
|
use Value::*;
|
||||||
|
match (self, other) {
|
||||||
|
(Nothing, Nothing) | (Nil, Nil) | (True, True) | (False, False) => true,
|
||||||
|
(Keyword(str1), Keyword(str2)) | (Interned(str1), Interned(str2)) => str1 == str2,
|
||||||
|
(String(x), String(y)) => x == y,
|
||||||
|
(String(x), Interned(y)) => x.as_ref() == y,
|
||||||
|
(Interned(x), String(y)) => x == y.as_ref(),
|
||||||
|
(Number(x), Number(y)) => x == y,
|
||||||
|
(Tuple(x), Tuple(y)) => x == y,
|
||||||
|
(List(x), List(y)) => x == y,
|
||||||
|
(Dict(x), Dict(y)) => x == y,
|
||||||
|
(Box(x), Box(y)) => std::ptr::eq(x.as_ref().as_ptr(), y.as_ref().as_ptr()),
|
||||||
|
(Fn(x), Fn(y)) => x == y,
|
||||||
|
(BaseFn(x), BaseFn(y)) => std::ptr::eq(x, y),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Value {
|
impl std::fmt::Display for Value {
|
||||||
|
@ -81,6 +104,7 @@ impl std::fmt::Display for Value {
|
||||||
),
|
),
|
||||||
Box(value) => write!(f, "box {}", value.as_ref().borrow()),
|
Box(value) => write!(f, "box {}", value.as_ref().borrow()),
|
||||||
Fn(lfn) => write!(f, "fn {}", lfn.get().unwrap().name),
|
Fn(lfn) => write!(f, "fn {}", lfn.get().unwrap().name),
|
||||||
|
BaseFn(_) => write!(f, "base fn"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,7 +145,8 @@ impl Value {
|
||||||
}
|
}
|
||||||
Box(x) => format!("box {{ {} }}", x.as_ref().borrow().show()),
|
Box(x) => format!("box {{ {} }}", x.as_ref().borrow().show()),
|
||||||
Fn(lfn) => format!("fn {}", lfn.get().unwrap().name),
|
Fn(lfn) => format!("fn {}", lfn.get().unwrap().name),
|
||||||
_ => todo!(),
|
BaseFn(_) => "base fn".to_string(),
|
||||||
|
Nothing => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +210,7 @@ impl Value {
|
||||||
Dict(..) => "dict",
|
Dict(..) => "dict",
|
||||||
Box(..) => "box",
|
Box(..) => "box",
|
||||||
Fn(..) => "fn",
|
Fn(..) => "fn",
|
||||||
|
BaseFn(..) => "fn",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
47
src/vm.rs
47
src/vm.rs
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::base::BaseFn;
|
||||||
use crate::compiler::{Chunk, Op};
|
use crate::compiler::{Chunk, Op};
|
||||||
use crate::parser::Ast;
|
use crate::parser::Ast;
|
||||||
use crate::spans::Spanned;
|
use crate::spans::Spanned;
|
||||||
|
@ -83,7 +84,7 @@ pub struct Vm {
|
||||||
pub call_stack: Vec<CallFrame>,
|
pub call_stack: Vec<CallFrame>,
|
||||||
pub frame: CallFrame,
|
pub frame: CallFrame,
|
||||||
pub ip: usize,
|
pub ip: usize,
|
||||||
pub return_register: [Value; 7],
|
pub return_register: [Value; 8],
|
||||||
pub matches: bool,
|
pub matches: bool,
|
||||||
pub match_depth: u8,
|
pub match_depth: u8,
|
||||||
pub result: Option<Result<Value, Panic>>,
|
pub result: Option<Result<Value, Panic>>,
|
||||||
|
@ -111,7 +112,7 @@ impl Vm {
|
||||||
call_stack: Vec::with_capacity(64),
|
call_stack: Vec::with_capacity(64),
|
||||||
frame: base_frame,
|
frame: base_frame,
|
||||||
ip: 0,
|
ip: 0,
|
||||||
return_register: [const { Value::Nothing }; 7],
|
return_register: [const { Value::Nothing }; 8],
|
||||||
matches: false,
|
matches: false,
|
||||||
match_depth: 0,
|
match_depth: 0,
|
||||||
result: None,
|
result: None,
|
||||||
|
@ -662,25 +663,37 @@ impl Vm {
|
||||||
self.ip += 2;
|
self.ip += 2;
|
||||||
|
|
||||||
let val = self.pop();
|
let val = self.pop();
|
||||||
let Value::Fn(_) = val else {
|
|
||||||
return self.panic_with(format!("{} is not a function", val.show()));
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut frame = CallFrame {
|
match val {
|
||||||
function: val,
|
Value::Fn(_) => {
|
||||||
arity,
|
let mut frame = CallFrame {
|
||||||
stack_base: self.stack.len() - arity as usize,
|
function: val,
|
||||||
ip: 0,
|
arity,
|
||||||
};
|
stack_base: self.stack.len() - arity as usize,
|
||||||
|
ip: 0,
|
||||||
|
};
|
||||||
|
|
||||||
swap(&mut self.frame, &mut frame);
|
swap(&mut self.frame, &mut frame);
|
||||||
frame.ip = self.ip;
|
frame.ip = self.ip;
|
||||||
|
|
||||||
self.call_stack.push(frame);
|
self.call_stack.push(frame);
|
||||||
self.ip = 0;
|
self.ip = 0;
|
||||||
|
|
||||||
if crate::DEBUG_RUN {
|
if crate::DEBUG_RUN {
|
||||||
println!("== calling into {} ==", self.frame.function.show());
|
println!("== calling into {} ==", self.frame.function.show());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Value::BaseFn(base_fn) => {
|
||||||
|
let value = match (arity, base_fn) {
|
||||||
|
(0, BaseFn::Nullary(f)) => f(),
|
||||||
|
(1, BaseFn::Unary(f)) => f(&self.pop()),
|
||||||
|
(2, BaseFn::Binary(f)) => f(&self.pop(), &self.pop()),
|
||||||
|
(3, BaseFn::Ternary(f)) => f(&self.pop(), &self.pop(), &self.pop()),
|
||||||
|
_ => return self.panic("internal ludus error"),
|
||||||
|
};
|
||||||
|
self.push(value);
|
||||||
|
}
|
||||||
|
_ => return self.panic_with(format!("{} is not a function", val.show())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Return => {
|
Return => {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user