summaryrefslogtreecommitdiff
path: root/matrix-stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'matrix-stdlib')
-rw-r--r--matrix-stdlib/Cargo.toml13
-rw-r--r--matrix-stdlib/src/core.rs298
-rw-r--r--matrix-stdlib/src/io.rs175
-rw-r--r--matrix-stdlib/src/iter.rs538
-rw-r--r--matrix-stdlib/src/lib.rs32
-rw-r--r--matrix-stdlib/src/math.rs689
-rw-r--r--matrix-stdlib/src/sys.rs252
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");
-}