diff options
Diffstat (limited to 'matrix-stdlib/src/core.rs')
-rw-r--r-- | matrix-stdlib/src/core.rs | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/matrix-stdlib/src/core.rs b/matrix-stdlib/src/core.rs new file mode 100644 index 0000000..183c142 --- /dev/null +++ b/matrix-stdlib/src/core.rs @@ -0,0 +1,181 @@ +use std::hash::{DefaultHasher, Hash, Hasher}; + +use matrix::{vm::Vm, value::Value, unpack_args, Result, unpack_varargs}; +use matrix_macros::native_func; +use crate::{VmArgs, 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())) +} + +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"); +} |