more functions
This commit is contained in:
parent
749a404a90
commit
14b749d2ed
5 changed files with 216 additions and 4 deletions
|
@ -7,6 +7,6 @@ edition = "2021"
|
|||
num-complex = "0.4.2"
|
||||
num-rational = "0.4.1"
|
||||
num-traits = "0.2.15"
|
||||
strum_macros = "0.24"
|
||||
strum = { version = "0.24", features = ["derive"] }
|
||||
strum_macros = "0.24.3"
|
||||
strum = { version = "0.24.1", features = ["derive"] }
|
||||
paste = "1.0.9"
|
||||
|
|
|
@ -7,6 +7,9 @@ pub fn load(env: &mut Environment) {
|
|||
declare_fn!(env, skip, 2);
|
||||
declare_fn!(env, forall, 2);
|
||||
declare_fn!(env, exists, 2);
|
||||
declare_fn!(env, nth, 2);
|
||||
declare_fn!(env, last, 1);
|
||||
declare_fn!(env, void, 1);
|
||||
}
|
||||
|
||||
fn fn_take(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
|
@ -76,3 +79,20 @@ fn fn_exists(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||
}
|
||||
Ok(Value::Bool(false))
|
||||
}
|
||||
|
||||
fn fn_nth(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
match &args[0] {
|
||||
Value::Int(n) if *n < 0 => Err("First argument to nth must be positive".into()),
|
||||
Value::Int(n) => args[1].iter()?.nth(*n as usize).unwrap_or(Ok(Value::Nil)),
|
||||
_ => Err("First argument to nth must be an integer".into())
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_last(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
args[0].iter()?.last().unwrap_or(Ok(Value::Nil))
|
||||
}
|
||||
|
||||
fn fn_void(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
for _ in args[0].iter()? {}
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::cmp::Ordering;
|
||||
|
||||
use num_traits::{ToPrimitive, Pow};
|
||||
use num_traits::{ToPrimitive, Pow, Signed};
|
||||
|
||||
use crate::{value::{Value, Complex, Rational}, RuntimeError, env::Environment, declare_fn};
|
||||
|
||||
|
@ -25,6 +25,7 @@ pub fn load(env: &mut Environment) {
|
|||
declare_fn!(env, im, 1);
|
||||
declare_fn!(env, min, 2);
|
||||
declare_fn!(env, max, 2);
|
||||
declare_fn!(env, abs, 1);
|
||||
declare_fn!(env, floor, 1);
|
||||
declare_fn!(env, ceil, 1);
|
||||
declare_fn!(env, round, 1);
|
||||
|
@ -43,6 +44,8 @@ pub fn load(env: &mut Environment) {
|
|||
declare_fn!(env, atanh, 1);
|
||||
declare_fn!(env, exp, 1);
|
||||
declare_fn!(env, "log", fn_ln, 1);
|
||||
declare_fn!(env, is_prime, 1);
|
||||
declare_fn!(env, factors, 1);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -98,6 +101,19 @@ fn fn_max(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||
}
|
||||
}
|
||||
|
||||
fn fn_abs(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
match args[0] {
|
||||
Value::Int(n) => Ok(Value::Int(n.abs())),
|
||||
Value::Float(f) => Ok(Value::Float(f.abs())),
|
||||
Value::Rational(r) => Ok(Value::Rational(r.abs())),
|
||||
_ => Err("Argument to floor must be real".into()),
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Rounding
|
||||
//
|
||||
|
||||
fn fn_floor(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
match args[0] {
|
||||
Value::Int(n) => Ok(Value::Int(n)),
|
||||
|
@ -195,3 +211,67 @@ transcendental!{ acosh }
|
|||
transcendental!{ atanh }
|
||||
transcendental!{ exp }
|
||||
transcendental!{ ln }
|
||||
|
||||
//
|
||||
// Factorization
|
||||
//
|
||||
|
||||
fn fn_is_prime(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
let n = match &args[0] {
|
||||
Value::Int(n) => *n,
|
||||
_ => return Err("Argument to is_prime must be an integer".into())
|
||||
};
|
||||
match n {
|
||||
_ if n <= 1 => Ok(Value::Bool(false)),
|
||||
2 | 3 => Ok(Value::Bool(true)),
|
||||
_ if (n % 2 == 0) || (n % 3 == 0) => Ok(Value::Bool(false)),
|
||||
_ => {
|
||||
let mut i = 5;
|
||||
while i*i <= n {
|
||||
if n % i == 0 {
|
||||
return Ok(Value::Bool(false));
|
||||
}
|
||||
i += 2;
|
||||
if n % i == 0 {
|
||||
return Ok(Value::Bool(false));
|
||||
}
|
||||
i += 4;
|
||||
}
|
||||
Ok(Value::Bool(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_factors(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
let mut n = match &args[0] {
|
||||
Value::Int(n) => n.abs(),
|
||||
_ => return Err("Argument to is_prime must be an integer".into())
|
||||
};
|
||||
if n <= 1 {
|
||||
return Ok(Value::from(vec![]));
|
||||
}
|
||||
let mut factors = vec![];
|
||||
while n % 2 == 0 {
|
||||
factors.push(Value::Int(2));
|
||||
n >>= 1;
|
||||
}
|
||||
while n % 3 == 0 {
|
||||
factors.push(Value::Int(3));
|
||||
n /= 3;
|
||||
}
|
||||
let mut i = 5;
|
||||
while n != 1 {
|
||||
while n % i == 0 {
|
||||
factors.push(Value::Int(i));
|
||||
n /= i;
|
||||
}
|
||||
i += 2;
|
||||
while n % i == 0 {
|
||||
factors.push(Value::Int(i));
|
||||
n /= i;
|
||||
}
|
||||
i += 4;
|
||||
}
|
||||
|
||||
Ok(Value::from(factors))
|
||||
}
|
||||
|
|
|
@ -21,15 +21,23 @@ macro_rules! declare_fn {
|
|||
pub fn load(env: &mut Environment) {
|
||||
declare_fn!(env, "type", fn_type, 1);
|
||||
declare_fn!(env, type_eq, 1);
|
||||
declare_fn!(env, copy, 1);
|
||||
declare_fn!(env, str, 1);
|
||||
declare_fn!(env, repr, 1);
|
||||
declare_fn!(env, ord, 1);
|
||||
declare_fn!(env, chr, 1);
|
||||
declare_fn!(env, range, 2);
|
||||
declare_fn!(env, count_by, 2);
|
||||
declare_fn!(env, has, 2);
|
||||
declare_fn!(env, len, 1);
|
||||
declare_fn!(env, time, 0);
|
||||
declare_fn!(env, list, 1);
|
||||
declare_fn!(env, push, 2);
|
||||
declare_fn!(env, pop, 1);
|
||||
declare_fn!(env, append, 2);
|
||||
declare_fn!(env, insert, 3);
|
||||
declare_fn!(env, remove, 2);
|
||||
|
||||
}
|
||||
|
||||
fn fn_type(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
|
@ -44,6 +52,16 @@ fn fn_type_eq(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||
}))
|
||||
}
|
||||
|
||||
fn fn_copy(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
Ok(match &args[0] {
|
||||
Value::List(l) => Value::from(l.borrow().clone()),
|
||||
Value::Map(m) => Value::from(m.borrow().clone()),
|
||||
// Value::Func(f) => Value::Func(f.make_copy()) // TODO copy functions
|
||||
Value::Data(_) => todo!(),
|
||||
a => a.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn fn_str(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
Ok(Value::String(args[0].to_string()))
|
||||
}
|
||||
|
@ -105,6 +123,26 @@ fn fn_range(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||
Ok(Value::Func(mk_range_inner(*start, *end, delta)))
|
||||
}
|
||||
|
||||
fn mk_countby_inner(start: i64, delta: i64) -> Func {
|
||||
let counter = RefCell::new(start);
|
||||
Func::BuiltinClosure {
|
||||
arg_count: 0,
|
||||
func: Rc::new(move |_| {
|
||||
let res = *counter.borrow();
|
||||
*counter.borrow_mut() += delta;
|
||||
Ok(Value::Int(res))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_count_by(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
let (start, delta) = match (&args[0], &args[1]) {
|
||||
(Value::Int(a), Value::Int(b)) => (a, b),
|
||||
_ => return Err("Both arguments to count_by must be integers".into())
|
||||
};
|
||||
Ok(Value::Func(mk_countby_inner(*start, *delta)))
|
||||
}
|
||||
|
||||
fn fn_len(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
Ok(Value::Int(args[0].len().map_err(RuntimeError::new_no_pos)? as i64))
|
||||
}
|
||||
|
@ -127,3 +165,70 @@ fn fn_list(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
|||
for v in a { res.push(v?); }
|
||||
Ok(Value::from(res))
|
||||
}
|
||||
|
||||
fn fn_push(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
if let Value::List(l) = &args[0] {
|
||||
l.as_ref().borrow_mut().push(args[1].clone());
|
||||
Ok(Value::Nil)
|
||||
} else{
|
||||
Err("First argument to push must be a list".into())
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_pop(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
if let Value::List(l) = &args[0] {
|
||||
l.as_ref().borrow_mut().pop().ok_or("Pop on empty list".into())
|
||||
} else{
|
||||
Err("First argument to pop must be a list".into())
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_append(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::List(a), Value::List(b)) => {
|
||||
let mut newvals = b.borrow().clone();
|
||||
a.borrow_mut().append(&mut newvals);
|
||||
Ok(Value::Nil)
|
||||
},
|
||||
_ => Err("Both arguments to append must be lists".into())
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_insert(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::List(a), Value::Int(i)) => {
|
||||
if *i < 0 {
|
||||
return Err(format!("List index {} cannot be negative", i).into())
|
||||
}
|
||||
if *i > a.borrow().len() as i64 {
|
||||
return Err(format!("List index {} not valid for list of length {}", i, a.borrow().len()).into())
|
||||
}
|
||||
a.borrow_mut().insert(*i as usize, args[2].clone());
|
||||
Ok(Value::Nil)
|
||||
},
|
||||
(Value::Map(a), b) => {
|
||||
Ok(a.borrow_mut().insert(b.clone(), args[3].clone()).unwrap_or(Value::Nil))
|
||||
},
|
||||
(Value::List(_), _) => Err("Second argument to insert must be an integer when the first is a list".into()),
|
||||
_ => Err("First argument to insert must be a list or map".into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_remove(args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||
match (&args[0], &args[1]) {
|
||||
(Value::List(a), Value::Int(i)) => {
|
||||
if *i < 0 {
|
||||
return Err(format!("List index {} cannot be negative", i).into())
|
||||
}
|
||||
if *i >= a.borrow().len() as i64 {
|
||||
return Err(format!("List index {} not valid for list of length {}", i, a.borrow().len()).into())
|
||||
}
|
||||
Ok(a.borrow_mut().remove(*i as usize))
|
||||
},
|
||||
(Value::Map(a), b) => {
|
||||
Ok(a.borrow_mut().remove(b).unwrap_or(Value::Nil))
|
||||
},
|
||||
(Value::List(_), _) => Err("Second argument to remove must be an integer when the first is a list".into()),
|
||||
_ => Err("First argument to remove must be a list or map".into()),
|
||||
}
|
||||
}
|
||||
|
|
7
examples/prime.cxpr
Normal file
7
examples/prime.cxpr
Normal file
|
@ -0,0 +1,7 @@
|
|||
# compute the primorial of n - the product of all primes <= n
|
||||
fn primorial(n) {
|
||||
return range(2,n+1) |? is_prime |// fn(x,y) { return x*y; };
|
||||
}
|
||||
|
||||
println(primorial(10)); # 2*3*5*7 = 210
|
||||
println(primorial(20)); # 2*3*5*7*11*13*17*19 = 9699690
|
Loading…
Reference in a new issue