diff options
author | Freya Murphy <freya@freyacat.org> | 2024-02-29 17:04:28 -0500 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2024-02-29 17:04:28 -0500 |
commit | 5d2747e26f51cc2344a6bd95f93457248fdfebd8 (patch) | |
tree | 8755b4068166c3854d26817683ce438a771ab319 /matrix-std/src/core.rs | |
parent | more mat, sys, and os stdlib functions, better matrix printing, other fixes (diff) | |
download | matrix-5d2747e26f51cc2344a6bd95f93457248fdfebd8.tar.gz matrix-5d2747e26f51cc2344a6bd95f93457248fdfebd8.tar.bz2 matrix-5d2747e26f51cc2344a6bd95f93457248fdfebd8.zip |
fin prob
Diffstat (limited to 'matrix-std/src/core.rs')
-rw-r--r-- | matrix-std/src/core.rs | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/matrix-std/src/core.rs b/matrix-std/src/core.rs new file mode 100644 index 0000000..69b6d97 --- /dev/null +++ b/matrix-std/src/core.rs @@ -0,0 +1,295 @@ +use std::hash::{DefaultHasher, Hasher}; +use rand::Rng; +use matrix_lang::prelude::*; +use matrix_macros::native_func; +use crate::{VmArgs, next, error, unpack_args, unpack_varargs}; + +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); + let mut hasher = DefaultHasher::new(); + value.try_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") + }; + if list.len() > 1 { + 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"); +} |