diff --git a/lang_tests/inst_var_at.som b/lang_tests/inst_var_at.som new file mode 100644 index 00000000..4c59d1da --- /dev/null +++ b/lang_tests/inst_var_at.som @@ -0,0 +1,14 @@ +" +VM: + status: success + stdout: 5 +" + +inst_var_at = ( + | x | + + run = ( + x := 5. + (self instVarAt: 1) println. + ) +) diff --git a/lang_tests/inst_var_at_bad_idx.som b/lang_tests/inst_var_at_bad_idx.som new file mode 100644 index 00000000..a4f6abcb --- /dev/null +++ b/lang_tests/inst_var_at_bad_idx.som @@ -0,0 +1,17 @@ +" +VM: + status: error + stderr: + Traceback... + ... + Index 2 not valid for array of length 1. +" + +inst_var_at_bad_idx = ( + | x | + + run = ( + x := 5. + (self instVarAt: 2) println. + ) +) diff --git a/src/lib/vm/core.rs b/src/lib/vm/core.rs index c8b6c2d7..0bafcfd4 100644 --- a/src/lib/vm/core.rs +++ b/src/lib/vm/core.rs @@ -815,7 +815,13 @@ impl VM { SendReturn::Val } Primitive::Inspect => unimplemented!(), - Primitive::InstVarAt => unimplemented!(), + Primitive::InstVarAt => { + let n = stry!(self.stack.pop().as_usize(self)); + let inst = stry!(rcv.tobj(self)); + let v = stry!(inst.inst_var_at(self, n)); + self.stack.push(v); + SendReturn::Val + } Primitive::InstVarAtPut => unimplemented!(), Primitive::InstVarNamed => unimplemented!(), Primitive::InvokeOnWith => todo!(), diff --git a/src/lib/vm/objects/instance.rs b/src/lib/vm/objects/instance.rs index 02c29b5b..d9732051 100644 --- a/src/lib/vm/objects/instance.rs +++ b/src/lib/vm/objects/instance.rs @@ -26,6 +26,10 @@ impl Obj for Inst { self.class } + fn num_inst_vars(&self) -> usize { + unsafe { &*self.inst_vars.get() }.len() + } + unsafe fn unchecked_inst_var_get(&self, n: usize) -> Val { let inst_vars = &mut *self.inst_vars.get(); inst_vars[n] diff --git a/src/lib/vm/objects/mod.rs b/src/lib/vm/objects/mod.rs index 62277353..66018ff0 100644 --- a/src/lib/vm/objects/mod.rs +++ b/src/lib/vm/objects/mod.rs @@ -41,7 +41,11 @@ pub use string_::String_; use natrob::narrowable_rboehm; use rboehm::Gc; -use crate::vm::{core::VM, error::VMError, val::Val}; +use crate::vm::{ + core::VM, + error::{VMError, VMErrorKind}, + val::Val, +}; /// The SOM type of objects. #[derive(Debug, PartialEq)] @@ -93,6 +97,26 @@ pub trait Obj: std::fmt::Debug { unreachable!(); } + /// How many instance variables does this object contain? + fn num_inst_vars(&self) -> usize { + unreachable!(); + } + + /// Return the instance variable at `i` (using SOM indexing). + fn inst_var_at(&self, vm: &VM, i: usize) -> Result> { + if i > 0 && i <= self.num_inst_vars() { + Ok(unsafe { self.unchecked_inst_var_get(i - 1) }) + } else { + Err(VMError::new( + vm, + VMErrorKind::IndexError { + tried: i, + max: self.num_inst_vars(), + }, + )) + } + } + /// Lookup an instance variable in this object. If `usize` exceeds the number of instance /// variables this will lead to undefined behaviour. unsafe fn unchecked_inst_var_get(&self, _: usize) -> Val {