more mat, sys, and os stdlib functions, better matrix printing, other fixes
This commit is contained in:
parent
4438116264
commit
508c4fa1b8
8 changed files with 445 additions and 54 deletions
32
Cargo.lock
generated
32
Cargo.lock
generated
|
@ -262,6 +262,7 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"matrix",
|
"matrix",
|
||||||
"matrix-macros",
|
"matrix-macros",
|
||||||
|
"os_info",
|
||||||
"rand",
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -341,6 +342,17 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_info"
|
||||||
|
version = "3.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"serde",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
|
@ -481,6 +493,26 @@ dependencies = [
|
||||||
"syn 2.0.48",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.197"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.197"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.48",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.13.1"
|
version = "1.13.1"
|
||||||
|
|
|
@ -274,10 +274,10 @@ impl Completer for MatrixHelper {
|
||||||
let mut start = 0;
|
let mut start = 0;
|
||||||
|
|
||||||
for char in line.chars() {
|
for char in line.chars() {
|
||||||
if buf.is_empty() && char.is_alphabetic() {
|
if buf.is_empty() && (char.is_alphabetic() || char == '_') {
|
||||||
start = idx;
|
start = idx;
|
||||||
buf.push(char);
|
buf.push(char);
|
||||||
} else if !buf.is_empty() && char.is_alphanumeric() {
|
} else if !buf.is_empty() && (char.is_alphanumeric() || char == '_') {
|
||||||
buf.push(char);
|
buf.push(char);
|
||||||
} else {
|
} else {
|
||||||
if idx >= pos {
|
if idx >= pos {
|
||||||
|
|
|
@ -9,4 +9,5 @@ edition = "2021"
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
matrix = { path = "../matrix" }
|
matrix = { path = "../matrix" }
|
||||||
matrix-macros = { path = "../matrix-macros" }
|
matrix-macros = { path = "../matrix-macros" }
|
||||||
|
os_info = "3"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
|
|
|
@ -100,7 +100,7 @@ fn mat_get_non_zero_pivot_row(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mat_rref(mat: Matrix) -> Result<Matrix> {
|
fn mat_rref(mat: Matrix, full_rref: bool) -> Result<Matrix> {
|
||||||
let mut mat = mat;
|
let mut mat = mat;
|
||||||
let Some(start) = mat_find_non_zero_col(&mat) else {
|
let Some(start) = mat_find_non_zero_col(&mat) else {
|
||||||
return Ok(mat)
|
return Ok(mat)
|
||||||
|
@ -112,7 +112,8 @@ fn mat_rref(mat: Matrix) -> Result<Matrix> {
|
||||||
if mat.get(pivot_row, col)?.is_zero() {
|
if mat.get(pivot_row, col)?.is_zero() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
for row in 0..mat.codomain {
|
let min = if full_rref { 0 } else { col };
|
||||||
|
for row in min..mat.codomain {
|
||||||
if row == pivot_row { continue; };
|
if row == pivot_row { continue; };
|
||||||
let scale = mat.get(row, col)?;
|
let scale = mat.get(row, col)?;
|
||||||
mat_gauss_row_operation(row, pivot_row, scale, &mut mat)?;
|
mat_gauss_row_operation(row, pivot_row, scale, &mut mat)?;
|
||||||
|
@ -127,9 +128,20 @@ fn rref(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
let mat = match value {
|
let mat = match value {
|
||||||
Value::Matrix(m) => m,
|
Value::Matrix(m) => m,
|
||||||
Value::List(l) => Matrix::from_list(l.to_vec()).into(),
|
Value::List(l) => Matrix::from_list(l.to_vec()).into(),
|
||||||
_ => return error!("trans must be given a matrix")
|
_ => return error!("rref must be given a matrix")
|
||||||
};
|
};
|
||||||
Ok(Value::Matrix(mat_rref(mat.into_inner())?.into()))
|
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> {
|
fn mat_det(mat: Matrix) -> Result<Value> {
|
||||||
|
@ -236,7 +248,7 @@ fn inv(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
let mat = mat.into_inner();
|
let mat = mat.into_inner();
|
||||||
let ident = mat_ident(mat.domain);
|
let ident = mat_ident(mat.domain);
|
||||||
let joined = mat.join_right(&ident)?;
|
let joined = mat.join_right(&ident)?;
|
||||||
let refed = mat_rref(joined)?;
|
let refed = mat_rref(joined, true)?;
|
||||||
let (new_ident, new_inv) = mat_splith(refed);
|
let (new_ident, new_inv) = mat_splith(refed);
|
||||||
|
|
||||||
if new_ident == ident {
|
if new_ident == ident {
|
||||||
|
@ -393,6 +405,17 @@ fn complex(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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)]
|
#[native_func(1)]
|
||||||
fn numer(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
fn numer(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
use Value as V;
|
use Value as V;
|
||||||
|
@ -437,6 +460,140 @@ fn im(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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!(floor);
|
||||||
mathr!(ceil);
|
mathr!(ceil);
|
||||||
mathr!(round);
|
mathr!(round);
|
||||||
|
@ -465,10 +622,13 @@ trigf!(to_radians, rad);
|
||||||
|
|
||||||
pub fn load(vm: &mut Vm) {
|
pub fn load(vm: &mut Vm) {
|
||||||
vm.load_global_fn(trans(), "trans");
|
vm.load_global_fn(trans(), "trans");
|
||||||
|
vm.load_global_fn(mat_ref(), "ref");
|
||||||
vm.load_global_fn(rref(), "rref");
|
vm.load_global_fn(rref(), "rref");
|
||||||
vm.load_global_fn(det(), "det");
|
vm.load_global_fn(det(), "det");
|
||||||
vm.load_global_fn(ident(), "ident");
|
vm.load_global_fn(ident(), "ident");
|
||||||
vm.load_global_fn(inv(), "inv");
|
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(PI), "pi");
|
||||||
vm.load_global(Value::Float(TAU), "tau");
|
vm.load_global(Value::Float(TAU), "tau");
|
||||||
|
@ -481,6 +641,7 @@ pub fn load(vm: &mut Vm) {
|
||||||
vm.load_global_fn(ratio(), "ratio");
|
vm.load_global_fn(ratio(), "ratio");
|
||||||
vm.load_global_fn(float(), "float");
|
vm.load_global_fn(float(), "float");
|
||||||
vm.load_global_fn(complex(), "complex");
|
vm.load_global_fn(complex(), "complex");
|
||||||
|
vm.load_global_fn(mat(), "mat");
|
||||||
vm.load_global_fn(abs(), "abs");
|
vm.load_global_fn(abs(), "abs");
|
||||||
vm.load_global_fn(sign(), "sign");
|
vm.load_global_fn(sign(), "sign");
|
||||||
vm.load_global_fn(floor(), "floor");
|
vm.load_global_fn(floor(), "floor");
|
||||||
|
@ -510,9 +671,19 @@ pub fn load(vm: &mut Vm) {
|
||||||
vm.load_global_fn(atanh(), "atanh");
|
vm.load_global_fn(atanh(), "atanh");
|
||||||
vm.load_global_fn(deg(), "deg");
|
vm.load_global_fn(deg(), "deg");
|
||||||
vm.load_global_fn(rad(), "rad");
|
vm.load_global_fn(rad(), "rad");
|
||||||
|
vm.load_global_fn(cis(), "cis");
|
||||||
|
|
||||||
vm.load_global_fn(denom(), "denom");
|
vm.load_global_fn(denom(), "denom");
|
||||||
vm.load_global_fn(numer(), "numer");
|
vm.load_global_fn(numer(), "numer");
|
||||||
vm.load_global_fn(re(), "re");
|
vm.load_global_fn(re(), "re");
|
||||||
vm.load_global_fn(im(), "im");
|
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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use std::{process::{exit, Command, Stdio}, env, rc::Rc, io::Read};
|
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::{vm::Vm, value::{Value, ValueMap}, unpack_args, Result, gc::Gc};
|
||||||
use matrix_macros::native_func;
|
use matrix_macros::native_func;
|
||||||
|
use os_info::Info;
|
||||||
use crate::{VmArgs, error};
|
use crate::{VmArgs, error};
|
||||||
|
|
||||||
#[native_func(1)]
|
#[native_func(1)]
|
||||||
|
@ -35,26 +36,7 @@ fn env(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[native_func(2)]
|
fn exec_impl(cmd: io::Result<Child>) -> Result<Value> {
|
||||||
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();
|
|
||||||
let mut child = match cmd {
|
let mut child = match cmd {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => return error!("error executing command: {e}")
|
Err(e) => return error!("error executing command: {e}")
|
||||||
|
@ -91,9 +73,180 @@ fn exec(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
Ok(Value::Table(res.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) {
|
pub fn load(vm: &mut Vm) {
|
||||||
vm.load_global_fn(sys_exit(), "exit");
|
vm.load_global_fn(sys_exit(), "exit");
|
||||||
vm.load_global_fn(argv(), "argv");
|
vm.load_global_fn(argv(), "argv");
|
||||||
vm.load_global_fn(exec(), "exec");
|
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_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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,14 +127,22 @@ impl<T> Drop for Gc<T> {
|
||||||
|
|
||||||
impl<T: Debug> Debug for Gc<T> {
|
impl<T: Debug> Debug for Gc<T> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if f.alternate() {
|
||||||
|
write!(f, "{:#?}", self.deref())
|
||||||
|
} else {
|
||||||
write!(f, "{:?}", self.deref())
|
write!(f, "{:?}", self.deref())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Display> Display for Gc<T> {
|
impl<T: Display> Display for Gc<T> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if f.alternate() {
|
||||||
|
write!(f, "{:#}", self.deref())
|
||||||
|
} else {
|
||||||
write!(f, "{}", self.deref())
|
write!(f, "{}", self.deref())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T: Add + Clone> Add for Gc<T> {
|
impl <T: Add + Clone> Add for Gc<T> {
|
||||||
|
|
|
@ -197,20 +197,10 @@ impl Display for Value {
|
||||||
write!(f, "]")?;
|
write!(f, "]")?;
|
||||||
},
|
},
|
||||||
V::Matrix(m) => {
|
V::Matrix(m) => {
|
||||||
write!(f, "\n")?;
|
|
||||||
for row in m.rows() {
|
|
||||||
write!(f, " ")?;
|
|
||||||
for (i, el) in row.into_iter().enumerate() {
|
|
||||||
if i != 0 {
|
|
||||||
write!(f, " ")?;
|
|
||||||
}
|
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
write!(f, "{el:#}")?;
|
write!(f, "{m:#}")?;
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{el}")?;
|
write!(f, "{m}")?;
|
||||||
}
|
|
||||||
}
|
|
||||||
write!(f, "\n")?;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
V::Table(t) => {
|
V::Table(t) => {
|
||||||
|
@ -1025,8 +1015,8 @@ impl Matrix {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn join_right(&self, other: &Matrix) -> Result<Self> {
|
pub fn join_right(&self, other: &Matrix) -> Result<Self> {
|
||||||
if self.domain != other.domain || self.codomain != other.codomain {
|
if self.codomain != other.codomain {
|
||||||
return error!("matrix dimensions do not match");
|
return error!("matrix codomain's do not match");
|
||||||
}
|
}
|
||||||
let mut r1 = self.rows();
|
let mut r1 = self.rows();
|
||||||
let mut r2 = other.rows();
|
let mut r2 = other.rows();
|
||||||
|
@ -1050,16 +1040,16 @@ impl Matrix {
|
||||||
.reduce(|mut a,b| {a.extend(b); a})
|
.reduce(|mut a,b| {a.extend(b); a})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Ok(Matrix::new(self.domain * 2, self.codomain, values))
|
Ok(Matrix::new(self.domain + other.domain, self.codomain, values))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn join_bottom(&self, other: &Matrix) -> Result<Self> {
|
pub fn join_bottom(&self, other: &Matrix) -> Result<Self> {
|
||||||
if self.domain != other.domain || self.codomain != other.codomain {
|
if self.domain != other.domain {
|
||||||
return error!("matrix dimensions do not match");
|
return error!("matrix domain's do not match");
|
||||||
}
|
}
|
||||||
let mut values = self.values.clone();
|
let mut values = self.values.clone();
|
||||||
values.extend(other.values.clone());
|
values.extend(other.values.clone());
|
||||||
Ok(Matrix::new(self.domain, self.codomain * 2, values))
|
Ok(Matrix::new(self.domain, self.codomain + other.codomain, values))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1199,3 +1189,35 @@ impl<'a> Iterator for MatrixCols<'a> {
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Matrix {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let mut max_cols = vec![0; self.domain];
|
||||||
|
let mut vals: Vec<String> = Vec::with_capacity(self.domain * self.codomain);
|
||||||
|
for row in 0..self.codomain {
|
||||||
|
for col in 0..self.domain {
|
||||||
|
let idx = col + row * self.domain;
|
||||||
|
let el = &self.values[idx];
|
||||||
|
let s = match f.alternate() {
|
||||||
|
true => format!("{:#}", el),
|
||||||
|
false => format!("{}", el)
|
||||||
|
};
|
||||||
|
max_cols[col] = max_cols[col].max(s.len());
|
||||||
|
vals.push(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, "\n")?;
|
||||||
|
for row in 0..self.codomain {
|
||||||
|
for col in 0..self.domain {
|
||||||
|
let idx = col + row * self.domain;
|
||||||
|
let s = vals[idx].as_str();
|
||||||
|
let width = max_cols[col];
|
||||||
|
write!(f, " {s:>width$}")?;
|
||||||
|
}
|
||||||
|
write!(f, "\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -164,7 +164,7 @@ pub struct Vm {
|
||||||
stack: Stack<Value>,
|
stack: Stack<Value>,
|
||||||
locals: Stack<Value>,
|
locals: Stack<Value>,
|
||||||
trystack: Vec<TryScope>,
|
trystack: Vec<TryScope>,
|
||||||
globals: HashMap<u16, Value>,
|
globals: Rc<RefCell<HashMap<u16, Value>>>,
|
||||||
names: NamesTable,
|
names: NamesTable,
|
||||||
global_names: NamesTable,
|
global_names: NamesTable,
|
||||||
interupt: Arc<AtomicUsize>,
|
interupt: Arc<AtomicUsize>,
|
||||||
|
@ -201,7 +201,7 @@ impl Vm {
|
||||||
stack: Stack::new(),
|
stack: Stack::new(),
|
||||||
locals: Stack::new(),
|
locals: Stack::new(),
|
||||||
trystack: Vec::new(),
|
trystack: Vec::new(),
|
||||||
globals: HashMap::new(),
|
globals: Rc::new(RefCell::new(HashMap::new())),
|
||||||
names: Rc::new(RefCell::new(Vec::new())),
|
names: Rc::new(RefCell::new(Vec::new())),
|
||||||
global_names: Rc::new(RefCell::new(Vec::new())),
|
global_names: Rc::new(RefCell::new(Vec::new())),
|
||||||
interupt: Arc::new(AtomicUsize::new(0)),
|
interupt: Arc::new(AtomicUsize::new(0)),
|
||||||
|
@ -211,7 +211,7 @@ impl Vm {
|
||||||
pub fn load_global(&mut self, value: Value, name: &str) {
|
pub fn load_global(&mut self, value: Value, name: &str) {
|
||||||
let idx = self.global_names.borrow().len();
|
let idx = self.global_names.borrow().len();
|
||||||
self.global_names.borrow_mut().push(name.into());
|
self.global_names.borrow_mut().push(name.into());
|
||||||
self.globals.insert(idx as u16, value);
|
self.globals.borrow_mut().insert(idx as u16, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_global_fn(&mut self, value: Rc<Function>, name: &str) {
|
pub fn load_global_fn(&mut self, value: Rc<Function>, name: &str) {
|
||||||
|
@ -245,6 +245,7 @@ impl Vm {
|
||||||
I::DiscardLocals(count) => {self.locals.truncate(self.locals.len() - count as usize)},
|
I::DiscardLocals(count) => {self.locals.truncate(self.locals.len() - count as usize)},
|
||||||
I::LoadGlobal(idx) => {
|
I::LoadGlobal(idx) => {
|
||||||
let val = self.globals
|
let val = self.globals
|
||||||
|
.borrow_mut()
|
||||||
.get(&idx)
|
.get(&idx)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone();
|
.clone();
|
||||||
|
@ -252,7 +253,7 @@ impl Vm {
|
||||||
},
|
},
|
||||||
I::StoreGlobal(idx) => {
|
I::StoreGlobal(idx) => {
|
||||||
let val = self.pop();
|
let val = self.pop();
|
||||||
self.globals.insert(idx, val);
|
self.globals.borrow_mut().insert(idx, val);
|
||||||
},
|
},
|
||||||
I::Const(idx) => self.push(frame.body.constants[idx as usize].clone()),
|
I::Const(idx) => self.push(frame.body.constants[idx as usize].clone()),
|
||||||
I::Int(i) => self.push(Value::Int(i as i64)),
|
I::Int(i) => self.push(Value::Int(i as i64)),
|
||||||
|
@ -426,6 +427,9 @@ impl Vm {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_fn(&mut self, frame: &mut StackFrame, fun: Rc<Function>, params: Vec<Value>) -> VmResult<Value> {
|
fn exec_fn(&mut self, frame: &mut StackFrame, fun: Rc<Function>, params: Vec<Value>) -> VmResult<Value> {
|
||||||
|
if self.check_interupt() {
|
||||||
|
return Ok(Value::Nil)
|
||||||
|
}
|
||||||
let name = fun.name.clone();
|
let name = fun.name.clone();
|
||||||
let params_len = params.len();
|
let params_len = params.len();
|
||||||
match &fun.fun {
|
match &fun.fun {
|
||||||
|
|
Loading…
Reference in a new issue