diff --git a/Cargo.lock b/Cargo.lock index a59e6f1..9a015a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -262,6 +262,7 @@ dependencies = [ "anyhow", "matrix", "matrix-macros", + "os_info", "rand", ] @@ -341,6 +342,17 @@ dependencies = [ "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]] name = "ppv-lite86" version = "0.2.17" @@ -481,6 +493,26 @@ dependencies = [ "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]] name = "smallvec" version = "1.13.1" diff --git a/matrix-bin/src/helper.rs b/matrix-bin/src/helper.rs index c0ac5ec..95e0848 100644 --- a/matrix-bin/src/helper.rs +++ b/matrix-bin/src/helper.rs @@ -274,10 +274,10 @@ impl Completer for MatrixHelper { let mut start = 0; for char in line.chars() { - if buf.is_empty() && char.is_alphabetic() { + if buf.is_empty() && (char.is_alphabetic() || char == '_') { start = idx; buf.push(char); - } else if !buf.is_empty() && char.is_alphanumeric() { + } else if !buf.is_empty() && (char.is_alphanumeric() || char == '_') { buf.push(char); } else { if idx >= pos { diff --git a/matrix-stdlib/Cargo.toml b/matrix-stdlib/Cargo.toml index bdbd2f9..6256cfa 100644 --- a/matrix-stdlib/Cargo.toml +++ b/matrix-stdlib/Cargo.toml @@ -9,4 +9,5 @@ edition = "2021" anyhow = "1" matrix = { path = "../matrix" } matrix-macros = { path = "../matrix-macros" } +os_info = "3" rand = "0.8" diff --git a/matrix-stdlib/src/math.rs b/matrix-stdlib/src/math.rs index 3226af5..3f33951 100644 --- a/matrix-stdlib/src/math.rs +++ b/matrix-stdlib/src/math.rs @@ -100,7 +100,7 @@ fn mat_get_non_zero_pivot_row( Ok(()) } -fn mat_rref(mat: Matrix) -> Result { +fn mat_rref(mat: Matrix, full_rref: bool) -> Result { let mut mat = mat; let Some(start) = mat_find_non_zero_col(&mat) else { return Ok(mat) @@ -112,7 +112,8 @@ fn mat_rref(mat: Matrix) -> Result { if mat.get(pivot_row, col)?.is_zero() { 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; }; let scale = mat.get(row, col)?; mat_gauss_row_operation(row, pivot_row, scale, &mut mat)?; @@ -127,9 +128,20 @@ fn rref(_: VmArgs, args: Vec) -> Result { let mat = match value { Value::Matrix(m) => m, 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) -> Result { + 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 { @@ -236,7 +248,7 @@ fn inv(_: VmArgs, args: Vec) -> Result { let mat = mat.into_inner(); let ident = mat_ident(mat.domain); 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); if new_ident == ident { @@ -393,6 +405,17 @@ fn complex(_: VmArgs, args: Vec) -> Result { } } +#[native_func(1)] +fn mat(_: VmArgs, args: Vec) -> Result { + 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)] fn numer(_: VmArgs, args: Vec) -> Result { use Value as V; @@ -437,6 +460,140 @@ fn im(_: VmArgs, args: Vec) -> Result { } } +#[native_func(1)] +fn cis(_: VmArgs, args: Vec) -> Result { + 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) -> Result { + 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) -> Result { + 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) -> Result { + 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) -> Result { + 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) -> Result { + 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) -> Result { + 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) -> Result { + 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) -> Result { + 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) -> Result { + 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) -> Result { + 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!(ceil); mathr!(round); @@ -465,10 +622,13 @@ trigf!(to_radians, rad); pub fn load(vm: &mut Vm) { vm.load_global_fn(trans(), "trans"); + vm.load_global_fn(mat_ref(), "ref"); vm.load_global_fn(rref(), "rref"); vm.load_global_fn(det(), "det"); vm.load_global_fn(ident(), "ident"); 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(TAU), "tau"); @@ -481,6 +641,7 @@ pub fn load(vm: &mut Vm) { vm.load_global_fn(ratio(), "ratio"); vm.load_global_fn(float(), "float"); vm.load_global_fn(complex(), "complex"); + vm.load_global_fn(mat(), "mat"); vm.load_global_fn(abs(), "abs"); vm.load_global_fn(sign(), "sign"); 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(deg(), "deg"); vm.load_global_fn(rad(), "rad"); + vm.load_global_fn(cis(), "cis"); vm.load_global_fn(denom(), "denom"); vm.load_global_fn(numer(), "numer"); vm.load_global_fn(re(), "re"); 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"); } diff --git a/matrix-stdlib/src/sys.rs b/matrix-stdlib/src/sys.rs index e91e635..d30226f 100644 --- a/matrix-stdlib/src/sys.rs +++ b/matrix-stdlib/src/sys.rs @@ -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_macros::native_func; +use os_info::Info; use crate::{VmArgs, error}; #[native_func(1)] @@ -35,26 +36,7 @@ fn env(_: VmArgs, args: Vec) -> Result { } } -#[native_func(2)] -fn exec(_: VmArgs, args: Vec) -> Result { - 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(); +fn exec_impl(cmd: io::Result) -> Result { let mut child = match cmd { Ok(c) => c, Err(e) => return error!("error executing command: {e}") @@ -91,9 +73,180 @@ fn exec(_: VmArgs, args: Vec) -> Result { Ok(Value::Table(res.into())) } +#[native_func(2)] +fn exec(_: VmArgs, args: Vec) -> Result { + 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) -> Result { + 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) -> Result { + 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 = OnceLock::new(); + +#[native_func(0)] +fn os_type(_: VmArgs, _: Vec) -> Result { + Ok(Value::String(OS_INFO.get_or_init(|| os_info::get()).os_type().to_string().into())) +} + +#[native_func(0)] +fn os_version(_: VmArgs, _: Vec) -> Result { + Ok(Value::String(OS_INFO.get_or_init(|| os_info::get()).version().to_string().into())) +} + +#[native_func(0)] +fn os_edition(_: VmArgs, _: Vec) -> Result { + Ok(Value::String(OS_INFO.get_or_init(|| os_info::get()).edition().unwrap_or("Unknown").into())) +} + +#[native_func(0)] +fn os_bitness(_: VmArgs, _: Vec) -> Result { + Ok(Value::String(OS_INFO.get_or_init(|| os_info::get()).bitness().to_string().into())) +} + +#[native_func(0)] +fn os_arch(_: VmArgs, _: Vec) -> Result { + Ok(Value::String(OS_INFO.get_or_init(|| os_info::get()).architecture().unwrap_or("Unknown").into())) +} + +#[native_func(0)] +fn cwd(_: VmArgs, _: Vec) -> Result { + 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) -> Result { + 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) -> Result { + 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) -> Result { + 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) { vm.load_global_fn(sys_exit(), "exit"); vm.load_global_fn(argv(), "argv"); 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(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"); } diff --git a/matrix/src/gc.rs b/matrix/src/gc.rs index 8fba633..7af020b 100644 --- a/matrix/src/gc.rs +++ b/matrix/src/gc.rs @@ -127,13 +127,21 @@ impl Drop for Gc { impl Debug for Gc { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.deref()) + if f.alternate() { + write!(f, "{:#?}", self.deref()) + } else { + write!(f, "{:?}", self.deref()) + } } } impl Display for Gc { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.deref()) + if f.alternate() { + write!(f, "{:#}", self.deref()) + } else { + write!(f, "{}", self.deref()) + } } } diff --git a/matrix/src/value.rs b/matrix/src/value.rs index 3ebc48a..f7d5170 100644 --- a/matrix/src/value.rs +++ b/matrix/src/value.rs @@ -197,20 +197,10 @@ impl Display for Value { write!(f, "]")?; }, 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() { - write!(f, "{el:#}")?; - } else { - write!(f, "{el}")?; - } - } - write!(f, "\n")?; + if f.alternate() { + write!(f, "{m:#}")?; + } else { + write!(f, "{m}")?; } }, V::Table(t) => { @@ -1025,8 +1015,8 @@ impl Matrix { } pub fn join_right(&self, other: &Matrix) -> Result { - if self.domain != other.domain || self.codomain != other.codomain { - return error!("matrix dimensions do not match"); + if self.codomain != other.codomain { + return error!("matrix codomain's do not match"); } let mut r1 = self.rows(); let mut r2 = other.rows(); @@ -1050,16 +1040,16 @@ impl Matrix { .reduce(|mut a,b| {a.extend(b); a}) .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 { - if self.domain != other.domain || self.codomain != other.codomain { - return error!("matrix dimensions do not match"); + if self.domain != other.domain { + return error!("matrix domain's do not match"); } let mut values = self.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) } } + +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 = 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(()) + } +} diff --git a/matrix/src/vm.rs b/matrix/src/vm.rs index f98dc72..e511adf 100644 --- a/matrix/src/vm.rs +++ b/matrix/src/vm.rs @@ -164,7 +164,7 @@ pub struct Vm { stack: Stack, locals: Stack, trystack: Vec, - globals: HashMap, + globals: Rc>>, names: NamesTable, global_names: NamesTable, interupt: Arc, @@ -201,7 +201,7 @@ impl Vm { stack: Stack::new(), locals: Stack::new(), trystack: Vec::new(), - globals: HashMap::new(), + globals: Rc::new(RefCell::new(HashMap::new())), names: Rc::new(RefCell::new(Vec::new())), global_names: Rc::new(RefCell::new(Vec::new())), interupt: Arc::new(AtomicUsize::new(0)), @@ -211,7 +211,7 @@ impl Vm { pub fn load_global(&mut self, value: Value, name: &str) { let idx = self.global_names.borrow().len(); 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, name: &str) { @@ -245,6 +245,7 @@ impl Vm { I::DiscardLocals(count) => {self.locals.truncate(self.locals.len() - count as usize)}, I::LoadGlobal(idx) => { let val = self.globals + .borrow_mut() .get(&idx) .unwrap() .clone(); @@ -252,7 +253,7 @@ impl Vm { }, I::StoreGlobal(idx) => { 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::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, params: Vec) -> VmResult { + if self.check_interupt() { + return Ok(Value::Nil) + } let name = fun.name.clone(); let params_len = params.len(); match &fun.fun {