77 lines
2.2 KiB
Rust

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<Value, String> {
self.operand_stack.pop().ok_or("Stack underflow".into())
}
pub fn pop_number(&mut self) -> Result<f64, String> {
let val = self.pop()?;
val.as_float().ok_or_else(|| "Expected number".into())
}
pub fn pop_integer(&mut self) -> Result<i64, String> {
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<S: Into<String>>(
&mut self,
opcode: OpCode,
pc: u32,
message: S,
) -> Result<Value, LogicalFrameEndingReason> {
self.pop().map_err(|_| self.trap(TRAP_STACK_UNDERFLOW, opcode as u16, message.into(), pc))
}
pub(super) fn peek_trap<S: Into<String>>(
&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<F>(
&mut self,
opcode: OpCode,
start_pc: u32,
f: F,
) -> Result<(), LogicalFrameEndingReason>
where
F: FnOnce(Value, Value) -> Result<Value, OpError>,
{
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)),
}
}
}