get base functions working
This commit is contained in:
parent
26ff15cae8
commit
10bc2e9b0c
95
src/base.rs
95
src/base.rs
|
@ -1,28 +1,18 @@
|
||||||
|
// Solution to the #[derive(Clone)] problem: https://stackoverflow.com/questions/27883509/can-you-clone-a-closure
|
||||||
use crate::value::*;
|
use crate::value::*;
|
||||||
use crate::vm::*;
|
use crate::vm::*;
|
||||||
use imbl::*;
|
use imbl::*;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
|
type LResult<'src> = Result<Value<'src>, LudusError>;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub enum Base<'src> {
|
pub enum Base<'src> {
|
||||||
Unary(
|
Unary(&'src str, fn(&Value<'src>) -> LResult<'src>),
|
||||||
&'src str,
|
Binary(&'src str, fn(&Value<'src>, &Value<'src>) -> LResult<'src>),
|
||||||
Box<dyn std::ops::Fn(Value<'src>) -> Result<Value<'src>, LudusError>>,
|
|
||||||
),
|
|
||||||
Binary(
|
|
||||||
&'src str,
|
|
||||||
Box<dyn std::ops::Fn(Value<'src>, Value<'src>) -> Result<Value<'src>, LudusError>>,
|
|
||||||
),
|
|
||||||
Ternary(
|
Ternary(
|
||||||
&'src str,
|
&'src str,
|
||||||
Box<
|
fn(&Value<'src>, &Value<'src>, &Value<'src>) -> LResult<'src>,
|
||||||
dyn std::ops::Fn(
|
|
||||||
Value<'src>,
|
|
||||||
Value<'src>,
|
|
||||||
Value<'src>,
|
|
||||||
) -> Result<Value<'src>, LudusError>,
|
|
||||||
>,
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,33 +26,67 @@ impl<'src> Base<'src> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> fmt::Debug for Base<'src> {
|
pub fn eq<'src>(x: &Value<'src>, y: &Value<'src>) -> LResult<'src> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
Ok(Value::Boolean(x == y))
|
||||||
f.debug_tuple("Base").field(&self.name()).finish()
|
}
|
||||||
|
|
||||||
|
pub fn add<'src>(x: &Value<'src>, y: &Value<'src>) -> LResult<'src> {
|
||||||
|
match (x, y) {
|
||||||
|
(Value::Number(x), Value::Number(y)) => Ok(Value::Number(x + y)),
|
||||||
|
_ => Err(LudusError {
|
||||||
|
msg: "add takes two numbers".to_string(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sub<'src>(x: &Value<'src>, y: &Value<'src>) -> LResult<'src> {
|
||||||
|
match (x, y) {
|
||||||
|
(Value::Number(x), Value::Number(y)) => Ok(Value::Number(x - y)),
|
||||||
|
_ => Err(LudusError {
|
||||||
|
msg: "sub takes two numbers".to_string(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unbox<'src>(x: &Value<'src>) -> LResult<'src> {
|
||||||
|
match x {
|
||||||
|
Value::Box(_, cell) => Ok(cell.borrow().clone()),
|
||||||
|
_ => Err(LudusError {
|
||||||
|
msg: "only boxes may be unboxed".to_string(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn store<'src>(b: &Value<'src>, val: &Value<'src>) -> LResult<'src> {
|
||||||
|
if let Value::Box(_, cell) = b {
|
||||||
|
cell.replace(val.clone());
|
||||||
|
Ok(val.clone())
|
||||||
|
} else {
|
||||||
|
Err(LudusError {
|
||||||
|
msg: "only boxes may store values".to_string(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> {
|
pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> {
|
||||||
let mut base = vec![];
|
let mut base = vec![];
|
||||||
|
|
||||||
let eq = Base::Binary("eq", Box::new(|x, y| Ok(Value::Boolean(x == y))));
|
let eq = Base::Binary("eq", eq);
|
||||||
base.push(("eq", Value::Base(&eq)));
|
base.push(("eq", Value::Base(eq)));
|
||||||
|
|
||||||
let add = Base::Binary(
|
let add = Base::Binary("add", add);
|
||||||
"add",
|
base.push(("add", Value::Base(add)));
|
||||||
Box::new(|x, y| match (x, y) {
|
|
||||||
(Value::Number(x), Value::Number(y)) => Ok(Value::Number(x + y)),
|
base.push(("sub", Value::Base(Base::Binary("sub", sub))));
|
||||||
_ => Err(LudusError {
|
|
||||||
msg: "I can only add numbers".to_string(),
|
base.push(("unbox", Value::Base(Base::Unary("unbox", unbox))));
|
||||||
}),
|
|
||||||
}),
|
base.push(("store", Value::Base(Base::Binary("store", store))));
|
||||||
);
|
|
||||||
base.push(("add", Value::Base(&add)));
|
|
||||||
|
|
||||||
base
|
base
|
||||||
}
|
}
|
||||||
|
|
||||||
// add (x, y) -> number
|
// DONE add (x, y) -> number
|
||||||
// and (x, y) -> value
|
// and (x, y) -> value
|
||||||
// assoc (x, y) -> dict
|
// assoc (x, y) -> dict
|
||||||
// atan_2 (x) -> number
|
// atan_2 (x) -> number
|
||||||
|
@ -78,6 +102,7 @@ pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> {
|
||||||
// div (x, y) -> number
|
// div (x, y) -> number
|
||||||
// doc (x) -> string
|
// doc (x) -> string
|
||||||
// downcase (x) -> string
|
// downcase (x) -> string
|
||||||
|
// DONE eq (x, y) -> bool
|
||||||
// first (x) -> value
|
// first (x) -> value
|
||||||
// floor (x) -> number
|
// floor (x) -> number
|
||||||
// get (x, y) -> value
|
// get (x, y) -> value
|
||||||
|
@ -102,7 +127,7 @@ pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> {
|
||||||
// slice (x, y, z) -> list
|
// slice (x, y, z) -> list
|
||||||
// split (x, y) -> list(string)
|
// split (x, y) -> list(string)
|
||||||
// sqrt (x) -> number
|
// sqrt (x) -> number
|
||||||
// store! (x, y) -> value
|
// DONE store! (x, y) -> value
|
||||||
// str_slice (x, y, z) -> string
|
// str_slice (x, y, z) -> string
|
||||||
// stringify (x) -> string
|
// stringify (x) -> string
|
||||||
// sub (x, y) -> number
|
// sub (x, y) -> number
|
||||||
|
@ -113,5 +138,5 @@ pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> {
|
||||||
// triml (x) -> string
|
// triml (x) -> string
|
||||||
// trimr (x) -> string
|
// trimr (x) -> string
|
||||||
// type (x) -> keyword
|
// type (x) -> keyword
|
||||||
// unbox (x) -> value
|
// DONE unbox (x) -> value
|
||||||
// upcase (x) -> string
|
// upcase (x) -> string
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
// * [ ] splat patterns in tuples, lists, dicts
|
// * [ ] splat patterns in tuples, lists, dicts
|
||||||
// * [ ] splats in list and dict literals
|
// * [ ] splats in list and dict literals
|
||||||
// * [ ] `loop` and `recur`
|
// * [ ] `loop` and `recur`
|
||||||
// * [ ] write `base` in Rust
|
// * [~] write `base` in Rust
|
||||||
// * [ ] turn this into a library function
|
// * [ ] turn this into a library function
|
||||||
// * [ ] compile this into WASM
|
// * [ ] compile this into WASM
|
||||||
// * [ ] perf testing
|
// * [ ] perf testing
|
||||||
|
@ -53,7 +53,7 @@ use crate::base::*;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let src = "
|
let src = "
|
||||||
eq
|
|
||||||
";
|
";
|
||||||
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
|
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
|
||||||
if lex_errs.len() > 0 {
|
if lex_errs.len() > 0 {
|
||||||
|
|
|
@ -28,7 +28,7 @@ pub enum Value<'src> {
|
||||||
Dict(HashMap<&'src str, Self>),
|
Dict(HashMap<&'src str, Self>),
|
||||||
Box(&'src str, Rc<RefCell<Self>>),
|
Box(&'src str, Rc<RefCell<Self>>),
|
||||||
Fn(Rc<Fn<'src>>),
|
Fn(Rc<Fn<'src>>),
|
||||||
Base(&Base<'src>),
|
Base(Base<'src>),
|
||||||
// Set(HashSet<Self>),
|
// Set(HashSet<Self>),
|
||||||
// Sets are hard
|
// Sets are hard
|
||||||
// Sets require Eq
|
// Sets require Eq
|
||||||
|
|
29
src/vm.rs
29
src/vm.rs
|
@ -174,6 +174,35 @@ pub fn apply<'src, 'a>(
|
||||||
(_, Value::Args(_)) => Err(LudusError {
|
(_, Value::Args(_)) => Err(LudusError {
|
||||||
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 {
|
||||||
|
Base::Unary(_name, f) => {
|
||||||
|
if args.len() != 1 {
|
||||||
|
Err(LudusError {
|
||||||
|
msg: "wrong arity: expected 1 argument".to_string(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
f(&args[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Base::Binary(_name, r#fn) => {
|
||||||
|
if args.len() != 2 {
|
||||||
|
Err(LudusError {
|
||||||
|
msg: "wrong arity: expected 2 arguments".to_string(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
r#fn(&args[0], &args[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Base::Ternary(_name, f) => {
|
||||||
|
if args.len() != 3 {
|
||||||
|
Err(LudusError {
|
||||||
|
msg: "wrong arity: expected 3 arguments".to_string(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
f(&args[0], &args[1], &args[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user