summaryrefslogtreecommitdiff
path: root/matrix-stdlib/src/core.rs
diff options
context:
space:
mode:
Diffstat (limited to 'matrix-stdlib/src/core.rs')
-rw-r--r--matrix-stdlib/src/core.rs181
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");
+}