summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock54
-rw-r--r--matrix-stdlib/Cargo.toml1
-rw-r--r--matrix-stdlib/src/core.rs119
-rw-r--r--matrix-stdlib/src/iter.rs8
-rw-r--r--matrix-stdlib/src/lib.rs7
5 files changed, 181 insertions, 8 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 6414157..a59e6f1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -182,6 +182,17 @@ dependencies = [
]
[[package]]
+name = "getrandom"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -251,6 +262,7 @@ dependencies = [
"anyhow",
"matrix",
"matrix-macros",
+ "rand",
]
[[package]]
@@ -330,6 +342,12 @@ dependencies = [
]
[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
name = "proc-macro2"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -358,6 +376,36 @@ dependencies = [
]
[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
name = "regex"
version = "1.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -492,6 +540,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/matrix-stdlib/Cargo.toml b/matrix-stdlib/Cargo.toml
index 1c6b0ac..bdbd2f9 100644
--- a/matrix-stdlib/Cargo.toml
+++ b/matrix-stdlib/Cargo.toml
@@ -9,3 +9,4 @@ edition = "2021"
anyhow = "1"
matrix = { path = "../matrix" }
matrix-macros = { path = "../matrix-macros" }
+rand = "0.8"
diff --git a/matrix-stdlib/src/core.rs b/matrix-stdlib/src/core.rs
index 183c142..2c76497 100644
--- a/matrix-stdlib/src/core.rs
+++ b/matrix-stdlib/src/core.rs
@@ -2,7 +2,8 @@ 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};
+use rand::Rng;
+use crate::{VmArgs, next, error};
fn to_radix(r: i64, mut n: i64) -> String {
@@ -162,6 +163,116 @@ fn str(_: VmArgs, args: Vec<Value>) -> Result<Value> {
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");
@@ -178,4 +289,10 @@ pub fn load(vm: &mut Vm) {
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/iter.rs b/matrix-stdlib/src/iter.rs
index 74056ce..630e52c 100644
--- a/matrix-stdlib/src/iter.rs
+++ b/matrix-stdlib/src/iter.rs
@@ -1,16 +1,10 @@
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, VmArgs};
+use crate::{error, next, VmArgs};
use Value as V;
-macro_rules! next {
- ($vm:expr, $frame:expr, $iter:expr) => {
- $vm.run_fn($frame, $iter.clone(), vec![])
- };
-}
-
#[native_func(1)]
fn len(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let [value] = unpack_args!(args);
diff --git a/matrix-stdlib/src/lib.rs b/matrix-stdlib/src/lib.rs
index 334de90..b4ab658 100644
--- a/matrix-stdlib/src/lib.rs
+++ b/matrix-stdlib/src/lib.rs
@@ -14,7 +14,14 @@ macro_rules! error {
};
}
+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);