diff options
Diffstat (limited to 'matrix-stdlib')
-rw-r--r-- | matrix-stdlib/Cargo.toml | 13 | ||||
-rw-r--r-- | matrix-stdlib/src/core.rs | 298 | ||||
-rw-r--r-- | matrix-stdlib/src/io.rs | 175 | ||||
-rw-r--r-- | matrix-stdlib/src/iter.rs | 538 | ||||
-rw-r--r-- | matrix-stdlib/src/lib.rs | 32 | ||||
-rw-r--r-- | matrix-stdlib/src/math.rs | 689 | ||||
-rw-r--r-- | matrix-stdlib/src/sys.rs | 252 |
7 files changed, 0 insertions, 1997 deletions
diff --git a/matrix-stdlib/Cargo.toml b/matrix-stdlib/Cargo.toml deleted file mode 100644 index 6256cfa..0000000 --- a/matrix-stdlib/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "matrix-stdlib" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -anyhow = "1" -matrix = { path = "../matrix" } -matrix-macros = { path = "../matrix-macros" } -os_info = "3" -rand = "0.8" diff --git a/matrix-stdlib/src/core.rs b/matrix-stdlib/src/core.rs deleted file mode 100644 index 2c76497..0000000 --- a/matrix-stdlib/src/core.rs +++ /dev/null @@ -1,298 +0,0 @@ -use std::hash::{DefaultHasher, Hash, Hasher}; - -use matrix::{vm::Vm, value::Value, unpack_args, Result, unpack_varargs}; -use matrix_macros::native_func; -use rand::Rng; -use crate::{VmArgs, next, error}; - - -fn to_radix(r: i64, mut n: i64) -> String { - let mut result = String::new(); - let mut idx = 0; - if n == 0 { - result.push('0'); - return result - } else if n < 0 { - n = -n; - idx = 1; - result.push('-'); - } - while n != 0 { - let c = std::char::from_digit((n % r) as u32, r as u32).unwrap(); - result.insert(idx, c); - n /= r; - } - result -} - -#[native_func(1)] -fn bin(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - match value { - Value::Int(n) => Ok(Value::String(to_radix(2, n).into())), - _ => error!("bin requires a integer agument") - } -} - -#[native_func(1)] -fn sex(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - match value { - Value::Int(n) => Ok(Value::String(to_radix(6, n).into())), - _ => error!("sex requires a integer agument") - } -} - -#[native_func(1)] -fn oct(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - match value { - Value::Int(n) => Ok(Value::String(to_radix(8, n).into())), - _ => error!("oct requires a integer agument") - } -} - -#[native_func(1)] -fn hex(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - match value { - Value::Int(n) => Ok(Value::String(to_radix(16, n).into())), - _ => error!("hex requires a integer agument") - } -} - -#[native_func(2)] -fn radix(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [radix, value] = unpack_args!(args); - match (radix, value) { - (Value::Int(r), Value::Int(n)) => Ok(Value::String(to_radix(r, n).into())), - _ => error!("radix requires two integer aguments") - } -} - -#[native_func(1..)] -fn append(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let ([list], args) = unpack_varargs!(args); - let Value::List(mut list) = list else { - return error!("append requires a list") - }; - for arg in args { - list.push(arg); - }; - Ok(Value::List(list)) -} - -#[native_func(2)] -fn push(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [list, value] = unpack_args!(args); - let Value::List(mut list) = list else { - return error!("push requires a list") - }; - list.push(value); - Ok(Value::List(list)) -} - -#[native_func(1)] -fn pop(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [list] = unpack_args!(args); - let Value::List(mut list) = list else { - return error!("pop requires a list") - }; - match list.pop() { - Some(v) => Ok(v), - None => Ok(Value::Nil) - } -} - -#[native_func(2)] -fn remove(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [list, index] = unpack_args!(args); - let Value::List(mut list) = list else { - return error!("remove requires a list") - }; - let Value::Int(i) = index else { - return error!("remove reuqires a int index"); - }; - if i < 0 || i as usize >= list.len() { - Ok(Value::Nil) - } else { - Ok(list.remove(i as usize)) - } -} - -#[native_func(1)] -fn hash(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - if let Err(e) = value.can_hash() { - return Err(e) - }; - let mut hasher = DefaultHasher::new(); - value.hash(&mut hasher); - let fin = hasher.finish(); - Ok(Value::Int(fin as u32 as i64)) -} - -#[native_func(1)] -fn ord(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let Value::String(str) = value else { - return error!("ord requires a 1 length string") - }; - if str.len() != 1 { - return error!("ord requires a 1 length string") - } - let char = str.chars().next().unwrap(); - Ok(Value::Int(char as i64)) -} - -#[native_func(1)] -fn chr(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let Value::Int(i) = value else { - return error!("chr requires an int") - }; - match char::from_u32(i as u32) { - Some(c) => Ok(Value::String(String::from(c).into())), - None => error!("unable to get char from: {}", i as u32) - } -} - -#[native_func(1)] -fn str(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - Ok(Value::String(format!("{value}").into())) -} - -fn partition(list: &mut [Value], lo: usize, hi: usize) -> (usize, usize) { - let pivot = list[(lo + hi) / 2].clone(); - let mut lt = lo; - let mut eq = lo; - let mut gt = hi; - - while eq <= gt { - if list[eq] < pivot { - list.swap(eq, lt); - lt += 1; - eq += 1; - } else if list[eq] > pivot { - list.swap(eq, gt); - gt -= 1; - } else { - eq += 1; - } - } - - (lt, gt) -} - -fn quicksort(list: &mut [Value], lo: usize, hi: usize) { - if lo < hi { - let (lt, gt) = partition(list, lo, hi); - if lt > 0 { - quicksort(list, lo, lt - 1); - } - quicksort(list, gt + 1, hi); - } -} - -#[native_func(1)] -fn sort(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let Value::List(mut list) = value else { - return error!("sort requires a list") - }; - let hi = list.len() - 1; - quicksort(list.as_mut(), 0, hi); - Ok(Value::List(list)) -} - -#[native_func(0)] -fn rand(_: VmArgs, _: Vec<Value>) -> Result<Value> { - let mut rng = rand::thread_rng(); - Ok(Value::Float(rng.gen())) -} - -#[native_func(0..)] -fn rand_range(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let ([], varargs) = unpack_varargs!(args); - let (min, max, step) = match varargs.as_slice() { - [V::Int(max)] => { - (0, *max, 1) - }, - [V::Int(min), V::Int(max)] => { - (*min, *max, 1) - }, - [V::Int(min), V::Int(max), V::Int(step)] => { - (*min, *max, *step) - }, - _ => return error!("rand_range takes 1 to 3 [Int]'s") - }; - if max <= min { - return Ok(Value::Int(min)) - } - let count = ((max - 1 - min) / step) + 1; - let rng = (rand::thread_rng().gen::<u32>() % (count as u32)) as i64; - let i = min + (rng * step); - Ok(Value::Int(i)) -} - -#[native_func(2)] -fn rand_int(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let (min, max) = match args.as_slice() { - [V::Int(min), V::Int(max)] => { - (*min, *max + 1) - }, - _ => return error!("rand_int takes 2 [Int]'s") - }; - if max <= min { - return Ok(Value::Int(min)) - } - - let count = max - min; - let rng = (rand::thread_rng().gen::<u32>() % (count as u32)) as i64; - let i = min + rng; - Ok(Value::Int(i)) -} - -#[native_func(1)] -fn rand_in((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let mut vals = Vec::new(); - loop { - let val = next!(vm, frame, iter)?; - if val == Value::Nil { break } - vals.push(val); - } - if vals.is_empty() { - return Ok(Value::Nil) - } - let idx = rand::thread_rng().gen::<usize>() % vals.len(); - Ok(vals[idx].clone()) -} - -pub fn load(vm: &mut Vm) { - vm.load_global_fn(bin(), "bin"); - vm.load_global_fn(sex(), "sex"); - vm.load_global_fn(oct(), "oct"); - vm.load_global_fn(hex(), "hex"); - vm.load_global_fn(radix(), "radix"); - vm.load_global_fn(str(), "str"); - - vm.load_global_fn(append(), "append"); - vm.load_global_fn(push(), "push"); - vm.load_global_fn(pop(), "pop"); - vm.load_global_fn(remove(), "remove"); - - vm.load_global_fn(hash(), "hash"); - vm.load_global_fn(ord(), "ord"); - vm.load_global_fn(chr(), "chr"); - - vm.load_global_fn(sort(), "sort"); - vm.load_global_fn(rand(), "rand"); - vm.load_global_fn(rand_range(), "rand_range"); - vm.load_global_fn(rand_int(), "rand_int"); - vm.load_global_fn(rand_in(), "rand_in"); -} diff --git a/matrix-stdlib/src/io.rs b/matrix-stdlib/src/io.rs deleted file mode 100644 index d72248c..0000000 --- a/matrix-stdlib/src/io.rs +++ /dev/null @@ -1,175 +0,0 @@ -use std::{io::{self, Read, Write}, cell::RefCell, fs::OpenOptions, rc::Rc}; - -use matrix::{value::Value, self, vm::Vm, Result, unpack_varargs, iter, unpack_args}; -use matrix_macros::native_func; -use crate::{error, VmArgs}; - -#[native_func(0..)] -fn print(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let ([], varags) = unpack_varargs!(args); - for (i, value) in varags.into_iter().enumerate() { - if i != 0 { - print!(" "); - } - print!("{value}"); - } - Ok(Value::Nil) -} - -#[native_func(0..)] -fn println(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let ([], varags) = unpack_varargs!(args); - for (i, value) in varags.into_iter().enumerate() { - if i != 0 { - print!(" "); - } - print!("{value}"); - } - print!("\n"); - Ok(Value::Nil) -} - -#[native_func(0)] -fn readln(_: VmArgs, _: Vec<Value>) -> Result<Value> { - let mut input = String::new(); - match io::stdin().read_line(&mut input) { - Ok(_) => { - match input.pop() { - Some(c) if c == '\n' => {}, - Some(c) => input.push(c), - None => {} - }; - Ok(Value::String(input.into())) - }, - Err(err) => error!("cant read from stdin: {err}") - } -} - -#[native_func(1)] -fn input(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [prompt] = unpack_args!(args); - let mut input = String::new(); - print!("{prompt}"); - let _ = io::stdout().flush(); - match io::stdin().read_line(&mut input) { - Ok(_) => { - match input.pop() { - Some(c) if c == '\n' => {}, - Some(c) => input.push(c), - None => {} - }; - Ok(Value::String(input.into())) - }, - Err(err) => error!("cant read from stdin: {err}") - } -} - -#[native_func(0)] -fn readlines(_: VmArgs, _: Vec<Value>) -> Result<Value> { - let lines = RefCell::new(io::stdin().lines()); - Ok(iter!(move |_,_| { - match lines.borrow_mut().next() { - Some(Ok(line)) => Ok(Value::String(line.into())), - _ => Ok(Value::Nil) - } - })) -} - -#[native_func(2)] -fn file_open(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [path, mode] = unpack_args!(args); - let Value::String(mode) = mode else { - return error!("open mode must be a string") - }; - let Value::String(path) = path else { - return error!("open path must be a string") - }; - let file = match mode.as_ref() { - "r" => OpenOptions::new().read(true).open(path.as_ref()), - "w" => OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref()), - "a" => OpenOptions::new().write(true).create(true).append(true).open(path.as_ref()), - "r+" => OpenOptions::new().read(true).write(true).open(path.as_ref()), - "w+" => OpenOptions::new().read(true).write(true).create(true).truncate(true).open(path.as_ref()), - "a+" => OpenOptions::new().read(true).write(true).create(true).append(true).open(path.as_ref()), - _ => return error!("invalid open mode: {mode}") - }; - - match file { - Ok(file) => Ok(Value::File(Rc::new(RefCell::new(file)))), - Err(err) => return error!("cannot open '{path}': {err}") - } -} - -#[native_func(1)] -fn file_read(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [file] = unpack_args!(args); - let Value::File(file) = file else { - return error!("file read requires a file") - }; - let mut contents = String::new(); - if let Err(err) = file.try_borrow_mut().unwrap().read_to_string(&mut contents) { - return error!("cannot read file: '{err}'") - }; - Ok(Value::String(contents.into())) -} - -#[native_func(1)] -fn file_lines(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [file] = unpack_args!(args); - let Value::File(file) = file else { - return error!("file read requires a file") - }; - let mut contents = String::new(); - if let Err(err) = file.try_borrow_mut().unwrap().read_to_string(&mut contents) { - return error!("cannot read file: '{err}'") - }; - let lines: Vec<Rc<str>> = contents.split_inclusive("\n").map(|s| Rc::from(s)).collect(); - let lines = RefCell::new(lines.into_iter()); - Ok(iter!(move |_,_| { - match lines.borrow_mut().next() { - Some(line) => Ok(Value::String(line)), - None => Ok(Value::Nil) - } - })) -} - -#[native_func(2)] -fn file_write(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [file, content] = unpack_args!(args); - let Value::File(file) = file else { - return error!("file write requires a file") - }; - let content = format!("{content}"); - if let Err(err) = file.try_borrow_mut().unwrap().write_all(content.as_bytes()) { - return error!("cannot write file: '{err}'") - }; - Ok(Value::Nil) -} - -#[native_func(0..)] -fn throw(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let ([], varargs) = unpack_varargs!(args); - - let mut str = String::new(); - for (i, v) in varargs.into_iter().enumerate() { - if i != 0 { - str.push_str(" "); - } - str.push_str(&format!("{v}")); - } - - error!("{str}") -} - -pub fn load(vm: &mut Vm) { - vm.load_global_fn(print(), "print"); - vm.load_global_fn(println(), "println"); - vm.load_global_fn(readln(), "readln"); - vm.load_global_fn(input(), "input"); - vm.load_global_fn(readlines(), "readlines"); - vm.load_global_fn(file_open(), "file_open"); - vm.load_global_fn(file_read(), "file_read"); - vm.load_global_fn(file_lines(), "file_lines"); - vm.load_global_fn(file_write(), "file_write"); - vm.load_global_fn(throw(), "throw"); -} diff --git a/matrix-stdlib/src/iter.rs b/matrix-stdlib/src/iter.rs deleted file mode 100644 index 630e52c..0000000 --- a/matrix-stdlib/src/iter.rs +++ /dev/null @@ -1,538 +0,0 @@ -use std::{cell::RefCell, rc::Rc}; -use matrix::{iter, vm::Vm, value::Value, Result, unpack_varargs, unpack_args}; -use matrix_macros::native_func; -use crate::{error, next, VmArgs}; - -use Value as V; - -#[native_func(1)] -fn len(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let len = match value { - V::List(l) => l.len(), - V::Matrix(m) => m.values.len(), - V::String(s) => s.len(), - V::Table(t) => t.len(), - _ => 1 - }; - Ok(V::Int(len as i64)) -} - -#[native_func(1)] -fn sum((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let mut res = next!(vm, frame, iter)?; - if res == Value::Nil { - return Ok(res) - }; - loop { - let next = next!(vm, frame, iter)?; - if next == Value::Nil { break } - res = (res + next)?; - } - Ok(res) -} - -#[native_func(0..)] -fn range(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let ([], varargs) = unpack_varargs!(args); - let (min, max, step) = match varargs.as_slice() { - [V::Int(max)] => { - (0, *max, 1) - }, - [V::Int(min), V::Int(max)] => { - (*min, *max, 1) - }, - [V::Int(min), V::Int(max), V::Int(step)] => { - (*min, *max, *step) - }, - _ => return error!("range takes 1 to 3 [Int]'s") - }; - - let i = RefCell::new(min); - Ok(iter!(move |_,_| { - let curr = *(i.borrow()); - *(i.borrow_mut()) = curr + step; - if curr >= max { - return Ok(V::Nil) - } else { - return Ok(V::Int(curr)) - } - })) -} - -#[native_func(1)] -fn iter(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - Ok(value.into_iter()?) -} - -#[native_func(1)] -fn once(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let first = RefCell::new(false); - Ok(iter!(move |_,_| { - if *first.borrow() == false { - *first.borrow_mut() = true; - Ok(value.clone()) - } else { - Ok(Value::Nil) - } - })) -} - -#[native_func(1)] -fn list((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let mut list = Vec::new(); - loop { - let res = next!(vm, frame, iter)?; - if res == Value::Nil { break } - list.push(res); - } - Ok(Value::List(list.into())) -} - -#[native_func(2)] -fn map(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [fun, iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let Value::Function(fun) = fun else { - return error!("map 1st arg must be a function") - }; - Ok(iter!(move |(vm,frame),_| { - let input = next!(vm, frame, iter)?; - if input == Value::Nil { - return Ok(input) - } - vm.run_fn(frame, fun.clone(), vec![input]) - })) -} - -#[native_func(2)] -fn fold((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [fun, iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let Value::Function(fun) = fun else { - return error!("fold 1st arg must be a function") - }; - let mut res = next!(vm, frame, iter)?; - if res == Value::Nil { - return Ok(Value::Nil) - }; - loop { - let next = next!(vm, frame, iter)?; - if next == Value::Nil { - return Ok(res) - }; - res = vm.run_fn(frame, fun.clone(), vec![res, next])?; - } -} - -#[native_func(3)] -fn foldi((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [init, fun, iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let Value::Function(fun) = fun else { - return error!("foldi 1st arg must be a function") - }; - let mut res = init; - loop { - let next = next!(vm, frame, iter)?; - if next == Value::Nil { - return Ok(res) - }; - res = vm.run_fn(frame, fun.clone(), vec![res, next])?; - } -} - -#[native_func(1)] -fn count((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let mut len = 0; - loop { - let res = vm.run_fn(frame, iter.clone(), vec![])?; - if res == Value::Nil { break }; - len += 1; - } - Ok(Value::Int(len)) -} - -#[native_func(3)] -fn scan(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [init, fun, iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let Value::Function(fun) = fun else { - return error!("scan 2nd arg must be a function") - }; - let res = RefCell::new(init); - Ok(iter!(move |(vm,frame),_| { - let next = next!(vm, frame, iter)?; - if next == Value::Nil { - return Ok(Value::Nil) - }; - let res_next = vm.run_fn(frame, fun.clone(), vec![res.borrow().clone(), next])?; - *res.borrow_mut() = res_next; - Ok(res.borrow().clone()) - })) -} - -#[native_func(2)] -fn filter(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [fun, iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let Value::Function(fun) = fun else { - return error!("filter 1st arg must be a function") - }; - Ok(iter!(move |(vm,frame),_| { - loop { - let next = next!(vm, frame, iter)?; - if next == Value::Nil { - return Ok(Value::Nil) - } - let res = vm.run_fn(frame, fun.clone(), vec![next.clone()])?; - if !!res { - return Ok(next) - } - } - })) -} - -#[native_func(0..)] -fn chain(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let ([], iters) = unpack_varargs!(args); - - let mut chaind = Vec::new(); - for iter in iters { - chaind.push(iter.into_iter_fn()?); - } - - chaind.reverse(); - let chaind = RefCell::new(chaind); - Ok(iter!(move |(vm,frame), _| { - loop { - let curr = match chaind.borrow_mut().last() { - Some(iter) => iter.clone(), - None => return Ok(Value::Nil) - }; - match vm.run_fn(frame, curr.clone(), vec![]) { - Ok(Value::Nil) => { - chaind.borrow_mut().pop(); - continue; - }, - v => return v - }; - } - })) -} - -#[native_func(1)] -fn lines(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [str] = unpack_args!(args); - let Value::String(str) = str else { - return error!("lines arg must be a string") - }; - let lines: Vec<Rc<str>> = str.split_inclusive("\n").map(|s| Rc::from(s)).collect(); - let res = RefCell::new(lines.into_iter()); - Ok(iter!(move |_,_| { - match res.borrow_mut().next() { - Some(line) => Ok(Value::String(line)), - None => Ok(Value::Nil) - } - })) -} - -#[native_func(1)] -fn skip((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [count, iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let Value::Int(i) = count else { - return error!("skip count requires a int") - }; - for _ in 0..i { - next!(vm, frame, iter)?; - } - Ok(Value::Iter(iter)) -} - -#[native_func(2)] -fn alternate(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [il, ir] = unpack_args!(args); - let il = il.into_iter_fn()?; - let ir = ir.into_iter_fn()?; - let flag = RefCell::new(Some(0)); - Ok(iter!(move |(vm, frame),_| { - let f = *flag.borrow(); - match f { - Some(0) => { - let val = next!(vm, frame, il)?; - if val == Value::Nil { - *flag.borrow_mut() = None; - } else { - *flag.borrow_mut() = Some(1); - } - Ok(val) - }, - Some(1) => { - let val = next!(vm, frame, ir)?; - if val == Value::Nil { - *flag.borrow_mut() = None; - } else { - *flag.borrow_mut() = Some(0); - } - Ok(val) - }, - _ => Ok(Value::Nil) - } - })) -} - -#[native_func(2)] -fn intersperse(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value, iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let flag = RefCell::new(Some(0)); - Ok(iter!(move |(vm, frame),_| { - let f = *flag.borrow(); - match f { - Some(0) => { - let val = next!(vm, frame, iter)?; - if val == Value::Nil { - *flag.borrow_mut() = None; - } else { - *flag.borrow_mut() = Some(1); - } - Ok(val) - }, - Some(1) => { - let val = value.clone(); - *flag.borrow_mut() = Some(0); - Ok(val) - }, - _ => Ok(Value::Nil) - } - })) -} - -#[native_func(2)] -fn zip(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [il, ir] = unpack_args!(args); - let il = il.into_iter_fn()?; - let ir = ir.into_iter_fn()?; - let flag = RefCell::new(true); - Ok(iter!(move |(vm, frame),_| { - let f = *flag.borrow(); - match f { - true => { - let vl = next!(vm, frame, il)?; - let vr = next!(vm, frame, ir)?; - if vl == Value::Nil || vr == Value::Nil { - *flag.borrow_mut() = false; - } - Ok(Value::List(vec![vl, vr].into())) - }, - _ => Ok(Value::Nil) - } - })) -} - -#[native_func(1)] -fn unzip((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let mut ll = Vec::new(); - let mut lr = Vec::new(); - loop { - let val = next!(vm, frame, iter)?; - if val == Value::Nil { - break; - } - let Value::List(vals) = val else { - return error!("unzip only works over a iterator of pairs"); - }; - let vals = vals.into_inner(); - if vals.len() != 2 { - return error!("unzip only works over a iterator of pairs"); - } - let [l, r] = vals.try_into().unwrap(); - ll.push(l); - lr.push(r); - } - let ll = Value::List(ll.into()); - let lr = Value::List(lr.into()); - Ok(Value::List(vec![ll, lr].into())) -} - -#[native_func(1)] -fn cycle((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let mut values = Vec::new(); - loop { - let val = next!(vm, frame, iter)?; - if val == Value::Nil { break }; - values.push(val); - } - let idx = RefCell::new(0_usize); - Ok(iter!(move |_,_| { - let i = *idx.borrow(); - *idx.borrow_mut() += 1; - *idx.borrow_mut() %= values.len(); - Ok(values[i].clone()) - })) -} - -#[native_func(2)] -fn take((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [count, iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let Value::Int(count) = count else { - return error!("take requires an int amount to collect") - }; - let mut values = Vec::new(); - for _ in 0..count { - let val = next!(vm, frame, iter)?; - if val == Value::Nil { break }; - values.push(val); - } - Ok(Value::List(values.into())) -} - -#[native_func(2)] -fn last((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let mut last = Value::Nil; - loop { - let val = next!(vm, frame, iter)?; - if val == Value::Nil { break }; - last = val; - } - Ok(last) -} - -#[native_func(2)] -fn next((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let val = next!(vm, frame, iter)?; - Ok(val) -} - -#[native_func(1)] -fn min((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let mut min = Value::Nil; - loop { - let val = next!(vm, frame, iter)?; - if val == Value::Nil { break }; - if min == Value::Nil || val < min { - min = val; - } - } - Ok(min) -} - -#[native_func(1)] -fn max((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let mut max = Value::Nil; - loop { - let val = next!(vm, frame, iter)?; - if val == Value::Nil { break }; - if max == Value::Nil || val > max { - max = val; - } - } - Ok(max) -} - -#[native_func(1)] -fn rev((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> { - let [iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - let mut values = Vec::new(); - loop { - let val = next!(vm, frame, iter)?; - if val == Value::Nil { break }; - values.push(val); - } - let values = RefCell::new(values); - Ok(iter!(move |_,_| { - match values.borrow_mut().pop() { - Some(v) => Ok(v), - None => Ok(Value::Nil) - } - })) -} - -#[native_func(1)] -fn enumerate(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [iter] = unpack_args!(args); - let iter = iter.into_iter_fn()?; - - let idx = RefCell::new(0_i64); - Ok(iter!(move |(vm, frame),_| { - let val = next!(vm, frame, iter)?; - if val == Value::Nil { - return Ok(Value::Nil) - }; - let curr = *idx.borrow(); - *idx.borrow_mut() += 1; - Ok(Value::List(vec![Value::Int(curr), val].into())) - })) -} - -#[native_func(1)] -fn iterable(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - use Value as V; - match value { - V::Function(_) | - V::List(_) | - V::Range(_) | - V::Iter(_) - => Ok(V::Bool(true)), - _ => Ok(V::Bool(false)) - } -} - -pub fn load(vm: &mut Vm) { - vm.load_global_fn(take(), "take"); - vm.load_global_fn(unzip(), "unzip"); - vm.load_global_fn(count(), "count"); - vm.load_global_fn(len(), "len"); - vm.load_global_fn(sum(), "sum"); - vm.load_global_fn(min(), "min"); - vm.load_global_fn(max(), "max"); - vm.load_global_fn(next(), "next"); - vm.load_global_fn(last(), "last"); - - vm.load_global_fn(list(), "list"); - vm.load_global_fn(fold(), "fold"); - vm.load_global_fn(foldi(), "foldi"); - vm.load_global_fn(scan(), "scan"); - vm.load_global_fn(chain(), "chain"); - vm.load_global_fn(lines(), "lines"); - vm.load_global_fn(skip(), "skip"); - - vm.load_global_fn(once(), "once"); - vm.load_global_fn(iter(), "iter"); - vm.load_global_fn(range(), "range"); - vm.load_global_fn(map(), "map"); - vm.load_global_fn(filter(), "filter"); - vm.load_global_fn(skip(), "skip"); - vm.load_global_fn(zip(), "zip"); - vm.load_global_fn(cycle(), "cycle"); - vm.load_global_fn(alternate(), "alternate"); - vm.load_global_fn(intersperse(), "intersperse"); - vm.load_global_fn(rev(), "rev"); - vm.load_global_fn(enumerate(), "enumerate"); - - vm.load_global_fn(iterable(), "iterable"); -} diff --git a/matrix-stdlib/src/lib.rs b/matrix-stdlib/src/lib.rs deleted file mode 100644 index b4ab658..0000000 --- a/matrix-stdlib/src/lib.rs +++ /dev/null @@ -1,32 +0,0 @@ -use matrix::vm::{Vm, StackFrame}; - -mod core; -mod sys; -mod math; -mod io; -mod iter; - -pub(crate) type VmArgs<'a, 'b> = (&'a mut Vm, &'b mut StackFrame); - -macro_rules! error { - ($($arg:tt)*) => { - Err(format!($($arg)*).into()) - }; -} - -macro_rules! next { - ($vm:expr, $frame:expr, $iter:expr) => { - $vm.run_fn($frame, $iter.clone(), vec![]) - }; -} - -pub(crate) use error; -pub(crate) use next; - -pub fn load(vm: &mut Vm) { - core::load(vm); - sys::load(vm); - io::load(vm); - iter::load(vm); - math::load(vm); -} diff --git a/matrix-stdlib/src/math.rs b/matrix-stdlib/src/math.rs deleted file mode 100644 index 3f33951..0000000 --- a/matrix-stdlib/src/math.rs +++ /dev/null @@ -1,689 +0,0 @@ -use core::f64; -use std::f64::{consts::{PI, E, TAU}, NAN, INFINITY}; - -use matrix::{vm::Vm, value::{Value, Matrix}, Result, unpack_args, Rational64, Complex64}; -use matrix_macros::native_func; -use crate::{error, VmArgs}; - -#[native_func(1)] -fn trans(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let mat = match value { - Value::Matrix(m) => m, - Value::List(l) => Matrix::from_list(l.to_vec()).into(), - _ => return error!("trans must be given a matrix") - }; - let values = mat - .cols() - .reduce(|mut a, b| {a.extend(b); a}) - .unwrap() - .into_iter() - .map(|e| e.clone()) - .collect(); - Ok(Value::Matrix(Matrix::new(mat.codomain, mat.domain, values).into())) -} - -fn mat_gauss_row_operation( - r1: usize, - r2: usize, - scale: Value, - mat: &mut Matrix -) -> Result<()> { - for col in 0..mat.domain { - let r1v = mat.get(r1, col)?; - let r2v = mat.get(r2, col)?; - let res = (r1v - (r2v * scale.clone())?)?; - mat.set(r1, col, res)?; - } - Ok(()) -} - -fn mat_swap_rows( - r1: usize, - r2: usize, - mat: &mut Matrix -) -> Result<()> { - let cols = mat.domain; - for col in 0..cols { - let a = mat.get(r1, col)?; - let b = mat.get(r2, col)?; - mat.set(r2, col, a)?; - mat.set(r1, col, b)?; - } - Ok(()) -} - -fn mat_find_non_zero_col( - mat: &Matrix -) -> Option<usize> { - for (i,col) in mat.cols().enumerate() { - for val in col.iter() { - if **val != Value::Int(0) { - return Some(i) - } - } - } - return None -} - -fn mat_scale_pivot_row( - row: usize, - mat: &mut Matrix -) -> Result<()> { - let scale = mat.get(row, row)?; - if scale.is_zero() { - return Ok(()) - } - for col in 0..mat.domain { - let res = (mat.get(row, col)?.clone() / scale.clone())?; - mat.set(row, col, res)?; - } - Ok(()) -} - -fn mat_get_non_zero_pivot_row( - row: usize, - mat: &mut Matrix, -) -> Result<()> { - let col = row; - let test = mat.get(row, col)?; - if test.is_zero() { - for r in row..mat.codomain { - let cur = mat.get(r, col)?; - if !cur.is_zero() { - mat_swap_rows(row, r, mat)?; - break; - } - } - } - mat_scale_pivot_row(row, mat)?; - Ok(()) -} - -fn mat_rref(mat: Matrix, full_rref: bool) -> Result<Matrix> { - let mut mat = mat; - let Some(start) = mat_find_non_zero_col(&mat) else { - return Ok(mat) - }; - let end = mat.domain.min(mat.codomain); - for col in start..end { - let pivot_row = col; - mat_get_non_zero_pivot_row(pivot_row, &mut mat)?; - if mat.get(pivot_row, col)?.is_zero() { - break - } - let min = if full_rref { 0 } else { col }; - for row in min..mat.codomain { - if row == pivot_row { continue; }; - let scale = mat.get(row, col)?; - mat_gauss_row_operation(row, pivot_row, scale, &mut mat)?; - } - } - Ok(mat) -} - -#[native_func(1)] -fn rref(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let mat = match value { - Value::Matrix(m) => m, - Value::List(l) => Matrix::from_list(l.to_vec()).into(), - _ => return error!("rref must be given a matrix") - }; - Ok(Value::Matrix(mat_rref(mat.into_inner(), true)?.into())) -} - -#[native_func(1)] -fn mat_ref(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let mat = match value { - Value::Matrix(m) => m, - Value::List(l) => Matrix::from_list(l.to_vec()).into(), - _ => return error!("ref must be given a matrix") - }; - Ok(Value::Matrix(mat_rref(mat.into_inner(), false)?.into())) -} - -fn mat_det(mat: Matrix) -> Result<Value> { - if mat.domain == 1 { - return Ok(mat.get(0,0)?) - } - if mat.domain == 2 { - let a = mat.get(0,0)? * mat.get(1,1)?; - let b = mat.get(0,1)? * mat.get(1,0)?; - return Ok((a? - b?)?) - } - let mut res = Value::Int(0); - for col in 0..mat.domain { - let sub_values = mat.rows() - .skip(1) - .map(|r| - r.into_iter() - .enumerate() - .filter(|(idx,_)| *idx != col) - .map(|(_, v)| v.clone()) - .collect::<Vec<Value>>() - ) - .reduce(|mut a, b| {a.extend(b); a}) - .unwrap(); - let sub = Matrix::new(mat.domain - 1, mat.domain - 1, sub_values); - let val = mat.get(0, col)?; - let part = (val * mat_det(sub)?)?; - if col % 2 == 0 { - res = (res + part)?; - } else { - res = (res - part)?; - } - } - Ok(res) -} - -#[native_func(1)] -fn det(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let mat = match value { - Value::Matrix(m) if m.domain == m.codomain => m, - Value::List(l) if l.len() == 1 => Matrix::from_list(l.to_vec()).into(), - _ => return error!("det requires a square matrix") - }; - let mat = mat.into_inner(); - Ok(mat_det(mat)?) -} - -fn mat_ident(dim: usize) -> Matrix { - let len = dim * dim; - let mut values = vec![Value::Int(0); len]; - let mut idx = 0; - loop { - if idx >= len { break }; - values[idx] = Value::Int(1); - idx += dim + 1; - } - Matrix::new(dim, dim, values) -} - -#[native_func(1)] -fn ident(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let dim = match value { - Value::Int(i) if i > 0 => i, - Value::Ratio(r) - if *r.denom() == 1 && - *r.numer() > 0 - => *r.numer(), - _ => return error!("ident requries a positive [Int] dimension") - }; - Ok(Value::Matrix(mat_ident(dim as usize).into())) -} - -fn mat_splith(mat: Matrix) -> (Matrix, Matrix) { - let mut m1 = Vec::new(); - let mut m2 = Vec::new(); - - mat.rows() - .for_each(|r| { - let split = r.len() / 2; - r.into_iter().enumerate().for_each(|(i, v)| { - if i < split { - m1.push(v.clone()); - } else { - m2.push(v.clone()); - } - }) - }); - - let m1 = Matrix::new(mat.domain/2, mat.codomain, m1); - let m2 = Matrix::new(mat.domain/2, mat.codomain, m2); - (m1, m2) -} - -#[native_func(1)] -fn inv(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let mat = match value { - Value::Matrix(m) if m.domain == m.codomain => m, - Value::List(l) if l.len() == 1 => Matrix::from_list(l.to_vec()).into(), - _ => return error!("det requires a square matrix") - }; - let mat = mat.into_inner(); - let ident = mat_ident(mat.domain); - let joined = mat.join_right(&ident)?; - let refed = mat_rref(joined, true)?; - let (new_ident, new_inv) = mat_splith(refed); - - if new_ident == ident { - Ok(Value::Matrix(new_inv.into())) - } else { - error!("matrix does not have an inverse") - } -} - -macro_rules! mathr { - ($type:ident) => { - #[native_func(1)] - fn $type(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(i) => Ok(V::Int(i)), - V::Ratio(r) => Ok(V::Ratio(r.$type())), - V::Float(f) => Ok(V::Float(f.$type())), - v => error!("cannot compute {} on {v}", stringify!($type)) - } - } - }; -} - -macro_rules! trig { - ($type:ident) => { - #[native_func(1)] - fn $type(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value.promote_trig() { - V::Float(f) => Ok(V::Float(f.$type())), - V::Complex(c) => Ok(V::Complex(c.$type())), - v => error!("cannot compute {} on {v}", stringify!($type)) - } - } - }; -} - -macro_rules! trigf { - ($type:ident, $str:ident) => { - #[native_func(1)] - fn $str(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value.promote_trig() { - V::Float(f) => Ok(V::Float(f.$type())), - v => error!("cannot compute {} on {v}", stringify!($str)) - } - } - }; -} - -#[native_func(2)] -fn log(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [base, value] = unpack_args!(args); - match (base.promote_trig(), value.promote_trig()) { - (V::Float(base), V::Float(arg)) => Ok(V::Float(arg.log(base))), - (V::Float(base), V::Complex(arg)) => Ok(V::Complex(arg.log(base))), - (V::Complex(base), V::Float(arg)) => Ok(V::Complex(arg.ln() / base.ln())), - (V::Complex(base), V::Complex(arg)) => Ok(V::Complex(arg.ln() / base.ln())), - (base, arg) => error!("cannot compute log base {base} argument {arg}") - } -} - -#[native_func(1)] -fn abs(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(i) => Ok(V::Int(i.abs())), - V::Float(f) => Ok(V::Float(f.abs())), - V::Ratio(r) => Ok(V::Ratio(Rational64::new(r.numer().abs(), r.denom().abs()))), - V::Complex(c) => Ok(V::Float(c.norm())), - arg => error!("cannot compute abs for {arg}") - } -} - -#[native_func(1)] -fn fract(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(_) => Ok(V::Int(0)), - V::Float(f) => Ok(V::Float(f.fract())), - V::Ratio(r) => Ok(V::Ratio(r.fract())), - arg => error!("cannot compute fract for {arg}") - } -} - -#[native_func(1)] -fn sign(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(i) => Ok(V::Int(i.signum())), - V::Ratio(r) => Ok(V::Int(r.numer().signum())), - V::Float(f) => Ok(V::Float(f.signum())), - arg => error!("cannot compute sign for {arg}") - } -} - -#[native_func(1)] -fn int(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(i) => Ok(V::Int(i)), - V::Ratio(r) => Ok(V::Int(r.numer() / r.denom())), - V::Float(f) => Ok(V::Int(f as i64)), - V::Complex(c) => Ok(V::Int(c.re as i64)), - arg => error!("cannot cast {arg} to int") - } -} - -#[native_func(1)] -fn ratio(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(i) => Ok(V::Ratio(Rational64::new(i, 1))), - V::Ratio(r) => Ok(V::Ratio(r)), - V::Float(f) => Ok(V::Ratio(Rational64::approximate_float(f).unwrap_or(Rational64::new(0, 1)))), - V::Complex(c) => Ok(V::Ratio(Rational64::approximate_float(c.re).unwrap_or(Rational64::new(0, 1)))), - arg => error!("cannot cast {arg} to ratio") - } -} - -#[native_func(1)] -fn float(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(i) => Ok(V::Float(i as f64)), - V::Ratio(r) => Ok(V::Float((*r.numer() as f64) / (*r.denom() as f64))), - V::Float(f) => Ok(V::Float(f)), - V::Complex(c) => Ok(V::Float(c.re)), - arg => error!("cannot cast {arg} to float") - } -} - -#[native_func(1)] -fn complex(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(i) => Ok(V::Complex(Complex64::new(i as f64, 0.0))), - V::Ratio(r) => Ok(V::Complex(Complex64::new((*r.numer() as f64) / (*r.denom() as f64), 0.0))), - V::Float(f) => Ok(V::Complex(Complex64::new(f, 0.0))), - V::Complex(c) => Ok(V::Complex(c)), - arg => error!("cannot cast {arg} to float") - } -} - -#[native_func(1)] -fn mat(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::List(l) => Ok(V::Matrix(Matrix::from_list(l.to_vec()).into())), - V::Matrix(m) => Ok(V::Matrix(m)), - arg => error!("cannot cast {arg} to mat") - } -} - -#[native_func(1)] -fn numer(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(i) => Ok(V::Int(i)), - V::Ratio(r) => Ok(V::Int(*r.numer())), - _ => error!("numer can only take a integer or ratio") - } -} - -#[native_func(1)] -fn denom(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(_) => Ok(V::Int(1)), - V::Ratio(r) => Ok(V::Int(*r.denom())), - _ => error!("denom can only take a integer or ratio") - } -} - -#[native_func(1)] -fn re(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(_) | V::Ratio(_) | V::Float(_) => Ok(value), - V::Complex(c) => Ok(V::Float(c.re)), - _ => error!("re can only take a valid number") - } -} - -#[native_func(1)] -fn im(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(_) | V::Ratio(_) | V::Float(_ )=> Ok(V::Int(0)), - V::Complex(c) => Ok(V::Float(c.im)), - _ => error!("re can only take a valid number") - } -} - -#[native_func(1)] -fn cis(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - match value.promote_trig() { - Value::Float(f) => Ok(Value::Complex(Complex64::cis(f))), - Value::Complex(c) => Ok((Value::Complex(Complex64::cis(c.re)) * Value::Float((-c.im).exp()))?), - _ => error!("cis can only take floats") - } -} - -#[native_func(1)] -fn is_finite(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(_) | V::Ratio(_) => Ok(V::Bool(true)), - V::Float(f) => Ok(V::Bool(f.is_finite())), - V::Complex(c) => Ok(V::Bool(c.is_finite())), - _ => error!("is_finite can only take a valid number") - } -} - -#[native_func(1)] -fn is_infinite(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(_) | V::Ratio(_) => Ok(V::Bool(false)), - V::Float(f) => Ok(V::Bool(f.is_infinite())), - V::Complex(c) => Ok(V::Bool(c.is_infinite())), - _ => error!("is_infinite can only take a valid number") - } -} - -#[native_func(1)] -fn is_nan(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(_) | V::Ratio(_) => Ok(V::Bool(false)), - V::Float(f) => Ok(V::Bool(f.is_nan())), - V::Complex(c) => Ok(V::Bool(c.is_nan())), - _ => error!("is_nan can only take a valid number") - } -} - -#[native_func(1)] -fn is_normal(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(_) | V::Ratio(_) => Ok(V::Bool(true)), - V::Float(f) => Ok(V::Bool(f.is_normal())), - V::Complex(c) => Ok(V::Bool(c.is_normal())), - _ => error!("is_normal can only take a valid number") - } -} - -#[native_func(1)] -fn is_subnormal(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(_) | V::Ratio(_) => Ok(V::Bool(false)), - V::Float(f) => Ok(V::Bool(f.is_subnormal())), - _ => error!("is_subnormal can only take subnormal") - } -} - -#[native_func(1)] -fn is_sign_positive(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(i) => Ok(V::Bool(i > 0)), - V::Ratio(r) => Ok(V::Bool(*r.numer() > 0)), - V::Float(f) => Ok(V::Bool(f.is_sign_positive())), - _ => error!("is_sign_positive can only take a real number") - } -} - -#[native_func(1)] -fn is_sign_negative(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(i) => Ok(V::Bool(i < 0)), - V::Ratio(r) => Ok(V::Bool(*r.numer() < 0)), - V::Float(f) => Ok(V::Bool(f.is_sign_negative())), - _ => error!("is_sign_negative can only take a real number") - } -} - -#[native_func(1)] -fn is_zero(_: VmArgs, args: Vec<Value>) -> Result<Value> { - use Value as V; - let [value] = unpack_args!(args); - match value { - V::Int(i) => Ok(V::Bool(i == 0)), - V::Ratio(r) => Ok(V::Bool(*r.numer() == 0 && *r.denom() != 0)), - V::Float(f) => Ok(V::Bool(f == 0.0)), - V::Complex(c) => Ok(V::Bool(c.re == 0.0 && c.im == 0.0)), - _ => error!("is_zero can only take a valid number") - } -} - -#[native_func(2)] -fn mat_joinh(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [l, r] = unpack_args!(args); - let (l, r) = match (l, r) { - (Value::List(l), Value::List(r)) => (Matrix::from_list(l.to_vec()), Matrix::from_list(r.to_vec())), - (Value::List(l), Value::Matrix(r)) => (Matrix::from_list(l.to_vec()), r.into_inner()), - (Value::Matrix(l), Value::List(r)) => (l.into_inner(), Matrix::from_list(r.to_vec())), - (Value::Matrix(l), Value::Matrix(r)) => (l.into_inner(), r.into_inner()), - _ => return error!("mat_joinh takes two matrices") - }; - let mat = l.join_right(&r)?; - Ok(Value::Matrix(mat.into())) -} - -#[native_func(2)] -fn mat_joinv(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [l, r] = unpack_args!(args); - let (l, r) = match (l, r) { - (Value::List(l), Value::List(r)) => (Matrix::from_list(l.to_vec()), Matrix::from_list(r.to_vec())), - (Value::List(l), Value::Matrix(r)) => (Matrix::from_list(l.to_vec()), r.into_inner()), - (Value::Matrix(l), Value::List(r)) => (l.into_inner(), Matrix::from_list(r.to_vec())), - (Value::Matrix(l), Value::Matrix(r)) => (l.into_inner(), r.into_inner()), - _ => return error!("mat_joinv takes two matrices") - }; - let mat = l.join_bottom(&r)?; - Ok(Value::Matrix(mat.into())) -} - -mathr!(floor); -mathr!(ceil); -mathr!(round); -mathr!(trunc); -trig!(sqrt); -trig!(cbrt); -trig!(ln); -trig!(log2); -trig!(log10); -trig!(exp); -trig!(exp2); -trig!(sin); -trig!(cos); -trig!(tan); -trig!(sinh); -trig!(cosh); -trig!(tanh); -trig!(asin); -trig!(acos); -trig!(atan); -trig!(asinh); -trig!(acosh); -trig!(atanh); -trigf!(to_degrees, deg); -trigf!(to_radians, rad); - -pub fn load(vm: &mut Vm) { - vm.load_global_fn(trans(), "trans"); - vm.load_global_fn(mat_ref(), "ref"); - vm.load_global_fn(rref(), "rref"); - vm.load_global_fn(det(), "det"); - vm.load_global_fn(ident(), "ident"); - vm.load_global_fn(inv(), "inv"); - vm.load_global_fn(mat_joinh(), "mat_joinh"); - vm.load_global_fn(mat_joinv(), "mat_joinv"); - - vm.load_global(Value::Float(PI), "pi"); - vm.load_global(Value::Float(TAU), "tau"); - vm.load_global(Value::Float(E), "e"); - vm.load_global(Value::Float(NAN), "nan"); - vm.load_global(Value::Float(NAN), "NaN"); - vm.load_global(Value::Float(INFINITY), "inf"); - - vm.load_global_fn(int(), "int"); - vm.load_global_fn(ratio(), "ratio"); - vm.load_global_fn(float(), "float"); - vm.load_global_fn(complex(), "complex"); - vm.load_global_fn(mat(), "mat"); - vm.load_global_fn(abs(), "abs"); - vm.load_global_fn(sign(), "sign"); - vm.load_global_fn(floor(), "floor"); - vm.load_global_fn(ceil(), "ceil"); - vm.load_global_fn(round(), "round"); - vm.load_global_fn(trunc(), "trunc"); - vm.load_global_fn(fract(), "fract"); - vm.load_global_fn(sqrt(), "sqrt"); - vm.load_global_fn(cbrt(), "cbrt"); - vm.load_global_fn(ln(), "ln"); - vm.load_global_fn(log(), "log"); - vm.load_global_fn(log2(), "log2"); - vm.load_global_fn(log10(), "log10"); - vm.load_global_fn(exp(), "exp"); - vm.load_global_fn(exp2(), "exp2"); - vm.load_global_fn(sin(), "sin"); - vm.load_global_fn(cos(), "cos"); - vm.load_global_fn(tan(), "tan"); - vm.load_global_fn(sinh(), "sinh"); - vm.load_global_fn(cosh(), "cosh"); - vm.load_global_fn(tanh(), "tanh"); - vm.load_global_fn(asin(), "asin"); - vm.load_global_fn(acos(), "acos"); - vm.load_global_fn(atan(), "atan"); - vm.load_global_fn(asinh(), "asinh"); - vm.load_global_fn(acosh(), "acosh"); - vm.load_global_fn(atanh(), "atanh"); - vm.load_global_fn(deg(), "deg"); - vm.load_global_fn(rad(), "rad"); - vm.load_global_fn(cis(), "cis"); - - vm.load_global_fn(denom(), "denom"); - vm.load_global_fn(numer(), "numer"); - vm.load_global_fn(re(), "re"); - vm.load_global_fn(im(), "im"); - - vm.load_global_fn(is_finite(), "is_finite"); - vm.load_global_fn(is_infinite(), "is_infinite"); - vm.load_global_fn(is_nan(), "is_nan"); - vm.load_global_fn(is_zero(), "is_zero"); - vm.load_global_fn(is_normal(), "is_normal"); - vm.load_global_fn(is_subnormal(), "is_subnormal"); - vm.load_global_fn(is_sign_negative(), "is_sign_negative"); - vm.load_global_fn(is_sign_positive(), "is_sign_positive"); -} diff --git a/matrix-stdlib/src/sys.rs b/matrix-stdlib/src/sys.rs deleted file mode 100644 index d30226f..0000000 --- a/matrix-stdlib/src/sys.rs +++ /dev/null @@ -1,252 +0,0 @@ -use std::{process::{exit, Command, Stdio, Child}, env, rc::Rc, io::{Read, self}, cell::RefCell, fs::{File, self}, os::fd::FromRawFd, sync::OnceLock, path::PathBuf}; - -use matrix::{vm::Vm, value::{Value, ValueMap}, unpack_args, Result, gc::Gc}; -use matrix_macros::native_func; -use os_info::Info; -use crate::{VmArgs, error}; - -#[native_func(1)] -fn sys_exit(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let Value::Int(i) = value else { - return error!("exit requires a int exit code") - }; - exit(i as i32); -} - -#[native_func(0)] -fn argv(_: VmArgs, _: Vec<Value>) -> Result<Value> { - Ok(Value::List( - Gc::new( - env::args() - .map(|a| Value::String(Rc::from(a.as_str()))) - .collect() - ))) -} - -#[native_func(1)] -fn env(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let Value::String(value) = value else { - return error!("env requires a string name") - }; - match std::env::var(value.as_ref()) { - Ok(v) => Ok(Value::String(v.into())), - Err(e) => error!("couldn't read env var: {e}") - } -} - -fn exec_impl(cmd: io::Result<Child>) -> Result<Value> { - let mut child = match cmd { - Ok(c) => c, - Err(e) => return error!("error executing command: {e}") - }; - let status = match child.wait() { - Ok(s) => s, - Err(e) => return error!("error executing command: {e}") - }; - - let stdout = match child.stdout { - Some(ref mut out) => { - let mut buf = String::new(); - let _ = out.read_to_string(&mut buf); - buf - }, - None => String::new() - }; - - let stderr = match child.stderr { - Some(ref mut err) => { - let mut buf = String::new(); - let _ = err.read_to_string(&mut buf); - buf - }, - None => String::new() - }; - - let mut res = ValueMap::new(); - res.insert(Value::from("success"), Value::Bool(status.success()))?; - res.insert(Value::from("code"), Value::Int(status.code().unwrap_or(0) as i64))?; - res.insert(Value::from("out"), Value::String(stdout.into()))?; - res.insert(Value::from("err"), Value::String(stderr.into()))?; - - Ok(Value::Table(res.into())) -} - -#[native_func(2)] -fn exec(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [cmd, args] = unpack_args!(args); - let (cmd, args) = match (cmd, args) { - (Value::String(s), Value::List(l)) => (s, l.into_inner()), - _ => return error!("exec requires a string cmd and string argument list") - }; - let mut sargs = Vec::new(); - for arg in args { - let Value::String(arg) = arg else { - return error!("exec requires a string cmd and string argument list") - }; - sargs.push(arg.to_string()); - }; - let cmd = Command::new(cmd.to_string()) - .args(sargs) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn(); - - exec_impl(cmd) -} - -#[native_func(1)] -fn system(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [cmd] = unpack_args!(args); - let Value::String(cmd) = cmd else { - return error!("system requires a full command argument string") - }; - let sh = String::from("/bin/sh"); - let args = vec!["-c".to_string(), cmd.to_string()]; - - let cmd = Command::new(sh) - .args(args) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn(); - - exec_impl(cmd) -} - -#[native_func(1)] -fn systemi(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [cmd] = unpack_args!(args); - let Value::String(cmd) = cmd else { - return error!("systemi requires a full command argument string") - }; - let sh = String::from("/bin/sh"); - let args = vec!["-c".to_string(), cmd.to_string()]; - - let cmd = Command::new(sh) - .args(args) - .stdin(Stdio::inherit()) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()) - .spawn(); - - exec_impl(cmd) -} - -fn stdin() -> Value { - let f = unsafe { File::from_raw_fd(0) }; - Value::File(Rc::new(RefCell::new(f))) -} - -fn stdout() -> Value { - let f = unsafe { File::from_raw_fd(1) }; - Value::File(Rc::new(RefCell::new(f))) -} - -fn stderr() -> Value { - let f = unsafe { File::from_raw_fd(2) }; - Value::File(Rc::new(RefCell::new(f))) -} - -const OS_INFO: OnceLock<Info> = OnceLock::new(); - -#[native_func(0)] -fn os_type(_: VmArgs, _: Vec<Value>) -> Result<Value> { - Ok(Value::String(OS_INFO.get_or_init(|| os_info::get()).os_type().to_string().into())) -} - -#[native_func(0)] -fn os_version(_: VmArgs, _: Vec<Value>) -> Result<Value> { - Ok(Value::String(OS_INFO.get_or_init(|| os_info::get()).version().to_string().into())) -} - -#[native_func(0)] -fn os_edition(_: VmArgs, _: Vec<Value>) -> Result<Value> { - Ok(Value::String(OS_INFO.get_or_init(|| os_info::get()).edition().unwrap_or("Unknown").into())) -} - -#[native_func(0)] -fn os_bitness(_: VmArgs, _: Vec<Value>) -> Result<Value> { - Ok(Value::String(OS_INFO.get_or_init(|| os_info::get()).bitness().to_string().into())) -} - -#[native_func(0)] -fn os_arch(_: VmArgs, _: Vec<Value>) -> Result<Value> { - Ok(Value::String(OS_INFO.get_or_init(|| os_info::get()).architecture().unwrap_or("Unknown").into())) -} - -#[native_func(0)] -fn cwd(_: VmArgs, _: Vec<Value>) -> Result<Value> { - match env::current_dir() { - Ok(v) => Ok(Value::String(v.into_os_string().into_string().unwrap_or(String::new()).into())), - Err(e) => error!("cant get cwd: {e}") - } -} - -#[native_func(1)] -fn basename(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let Value::String(value) = value else { - return error!("basename requires a string path") - }; - let path = PathBuf::from(value.to_string()); - match path.file_name() { - Some(p) => Ok(Value::String(p.to_str().unwrap().into())), - None => Ok(Value::String(value.into())) - } -} - -#[native_func(1)] -fn dirname(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let Value::String(value) = value else { - return error!("basename requires a string path") - }; - let path = PathBuf::from(value.to_string()); - let parent = match path.parent() { - Some(p) => p, - None => path.as_path() - }; - let str = parent.as_os_str().to_str().unwrap(); - match str { - "" => Ok(Value::String(".".into())), - s => Ok(Value::String(s.into())) - } -} - -#[native_func(1)] -fn realpath(_: VmArgs, args: Vec<Value>) -> Result<Value> { - let [value] = unpack_args!(args); - let Value::String(value) = value else { - return error!("basename requires a string path") - }; - let path = match fs::canonicalize(value.as_ref()) { - Ok(p) => p, - Err(e) => return error!("could not get realpath: {e}") - }; - Ok(Value::String(path.to_str().unwrap().into())) -} - - -pub fn load(vm: &mut Vm) { - vm.load_global_fn(sys_exit(), "exit"); - vm.load_global_fn(argv(), "argv"); - vm.load_global_fn(exec(), "exec"); - vm.load_global_fn(system(), "system"); - vm.load_global_fn(systemi(), "systemi"); - vm.load_global_fn(env(), "env"); - vm.load_global(stdin(), "stdin"); - vm.load_global(stdout(), "stdout"); - vm.load_global(stderr(), "stderr"); - vm.load_global_fn(os_type(), "os_type"); - vm.load_global_fn(os_version(), "os_version"); - vm.load_global_fn(os_edition(), "os_edition"); - vm.load_global_fn(os_bitness(), "os_bitness"); - vm.load_global_fn(os_arch(), "os_arch"); - vm.load_global_fn(cwd(), "cwd"); - vm.load_global_fn(basename(), "basename"); - vm.load_global_fn(dirname(), "dirname"); - vm.load_global_fn(realpath(), "realpath"); -} |