diff --git a/lang_tests/inst_var_at_put.som b/lang_tests/inst_var_at_put.som new file mode 100644 index 00000000..347e1233 --- /dev/null +++ b/lang_tests/inst_var_at_put.som @@ -0,0 +1,19 @@ +" +VM: + status: success + stdout: + 5 + instance of inst_var_at_put + 6 +" + +inst_var_at_put = ( + | x | + + run = ( + x := 5. + (self instVarAt: 1) println. + (self instVarAt: 1 put: 6) println. + x println. + ) +) diff --git a/lang_tests/inst_var_at_put_bad_idx.som b/lang_tests/inst_var_at_put_bad_idx.som new file mode 100644 index 00000000..36fe2477 --- /dev/null +++ b/lang_tests/inst_var_at_put_bad_idx.som @@ -0,0 +1,18 @@ +" +VM: + status: error + stderr: + Traceback... + ... + Index 2 not valid for array of length 1. +" + +inst_var_at_put_bad_idx = ( + | x | + + run = ( + x := 5. + self instVarAt: 2 put: 6. + x println. + ) +) diff --git a/src/lib/vm/core.rs b/src/lib/vm/core.rs index 0bafcfd4..e21b5544 100644 --- a/src/lib/vm/core.rs +++ b/src/lib/vm/core.rs @@ -822,7 +822,14 @@ impl VM { self.stack.push(v); SendReturn::Val } - Primitive::InstVarAtPut => unimplemented!(), + Primitive::InstVarAtPut => { + let v = self.stack.pop(); + let n = stry!(self.stack.pop().as_usize(self)); + let inst = stry!(rcv.tobj(self)); + stry!(inst.inst_var_at_put(self, n, v)); + self.stack.push(rcv); + SendReturn::Val + } Primitive::InstVarNamed => unimplemented!(), Primitive::InvokeOnWith => todo!(), Primitive::IsDigits => unimplemented!(), diff --git a/src/lib/vm/objects/mod.rs b/src/lib/vm/objects/mod.rs index 66018ff0..14001e87 100644 --- a/src/lib/vm/objects/mod.rs +++ b/src/lib/vm/objects/mod.rs @@ -117,6 +117,21 @@ pub trait Obj: std::fmt::Debug { } } + /// Return the instance variable at `i` (using SOM indexing). + fn inst_var_at_put(&self, vm: &VM, i: usize, v: Val) -> Result<(), Box> { + if i > 0 && i <= self.num_inst_vars() { + Ok(unsafe { self.unchecked_inst_var_set(i - 1, v) }) + } 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 {