use super::*; impl VirtualMachine { pub fn trap( &self, code: u32, opcode: u16, message: String, pc: u32, ) -> LogicalFrameEndingReason { LogicalFrameEndingReason::Trap(self.program.create_trap(code, opcode, message, pc)) } pub fn push(&mut self, val: Value) { self.operand_stack.push(val); } pub fn pop(&mut self) -> Result { self.operand_stack.pop().ok_or("Stack underflow".into()) } pub fn pop_number(&mut self) -> Result { let val = self.pop()?; val.as_float().ok_or_else(|| "Expected number".into()) } pub fn pop_integer(&mut self) -> Result { let val = self.pop()?; if let Value::Boolean(b) = val { return Ok(if b { 1 } else { 0 }); } val.as_integer().ok_or_else(|| "Expected integer".into()) } pub fn peek(&self) -> Result<&Value, String> { self.operand_stack.last().ok_or("Stack underflow".into()) } pub(super) fn pop_trap>( &mut self, opcode: OpCode, pc: u32, message: S, ) -> Result { self.pop().map_err(|_| self.trap(TRAP_STACK_UNDERFLOW, opcode as u16, message.into(), pc)) } pub(super) fn peek_trap>( &self, opcode: OpCode, pc: u32, message: S, ) -> Result<&Value, LogicalFrameEndingReason> { self.peek().map_err(|_| self.trap(TRAP_STACK_UNDERFLOW, opcode as u16, message.into(), pc)) } pub(super) fn binary_op( &mut self, opcode: OpCode, start_pc: u32, f: F, ) -> Result<(), LogicalFrameEndingReason> where F: FnOnce(Value, Value) -> Result, { let b = self.pop_trap(opcode, start_pc, format!("{:?} requires two operands", opcode))?; let a = self.pop_trap(opcode, start_pc, format!("{:?} requires two operands", opcode))?; match f(a, b) { Ok(res) => { self.push(res); Ok(()) } Err(OpError::Trap(code, msg)) => Err(self.trap(code, opcode as u16, msg, start_pc)), } } }