77 lines
2.2 KiB
Rust
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)),
|
|
}
|
|
}
|
|
}
|