Files
not-python/src/vm/inst.rs

235 lines
7.6 KiB
Rust
Raw Normal View History

use crate::{obj::prelude::*, vm::consts::*};
use std::fmt::{self, Display, Formatter};
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Inst {
/// Push a literal symbol object to the stack.
PushSym(Sym),
/// Push a const value reference to the stack.
PushConst(ConstHandle),
/// Looks up and pushes a local value.
PushLocal(Local),
/// Pop a value from the stack, possibly into a local symbol.
Pop(Option<Local>),
/// Pops a symbol value and an object reference.
///
/// This will get an attr from the object reference pointed to by the symbol.
GetAttr(Sym),
/// A target reference and a source reference from the stack.
///
/// The target reference will have the given symbol attribute assigned to the source.
///
/// In code, it would look like this:
///
/// `target.symbol = source`
///
SetAttr(Sym),
/// Jump to a given address in the current function unconditionally.
Jump(usize),
/// Jump to a given address in the current function if the condition flag is true.
///
/// The condition flag may be set by an internal function.
JumpTrue(usize),
/// Calls a function with the supplied number of arguments.
///
/// The stack, from bottom to top, should contain the function followed by the arguments.
///
/// After the function has returned, the VM will have popped the arguments and function
/// pointer, and the return value will be on top of the stack.
Call(usize),
/// Indexes a value, e.g. a list or a dict.
///
/// The stack, from bottom to top, should have the expression being indexed, and then the
/// indexed value.
Index,
/// Pops the top value from the stack, and returns from the function, using the popped value as
/// a return value.
Return,
/// Replaces the top stack value with its negation applied.
UnNeg,
/// Replaces the top stack value with its absolute value applied.
UnPos,
/// Pops the top two items off of the stack, and applies the binary addition operator to them,
/// pushing the result to the stack.
BinPlus,
/// Pops the top two items off of the stack, and applies the binary subtraction operator to
/// them, pushing the result to the stack.
BinMinus,
/// Pops the top two items off of the stack, and applies the binary multiplication operator to
/// them, pushing the result to the stack.
BinMul,
/// Pops the top two items off of the stack, and applies the binary division operator to them,
/// pushing the result to the stack.
BinDiv,
/// Pops the top two items off of the stack, and applies the boolean equality operator to them,
/// pushing the result to the stack.
BinEq,
/// Pops the top two items off of the stack, and applies the boolean inequality operator to
/// them, pushing the result to the stack.
BinNeq,
/// Pops the top two items off of the stack, and applies the boolean less-than operator to
/// them, pushing the result to the stack.
BinLt,
/// Pops the top two items off of the stack, and applies the binary less-than or equals
/// operator to them, pushing the result to the stack.
BinLe,
/// Pops the top two items off of the stack, and applies the boolean greater-than operator to
/// them, pushing the result to the stack.
BinGt,
/// Pops the top two items off of the stack, and applies the binary greater-than or equals
/// operator to them, pushing the result to the stack.
BinGe,
/// Pops the top two items off of the stack, and applies the boolean and operator to them,
/// pushing the result to the stack.
BinAnd,
/// Pops the top two items off of the stack, and applies the boolean or operator to them,
/// pushing the result to the stack.
BinOr,
}
//
// impl Inst
//
impl Inst {
pub fn name(&self) -> &'static str {
match self {
Inst::PushSym(_) => "PUSH_SYM",
Inst::PushConst(_) => "PUSH_CONST",
Inst::PushLocal(_) => "PUSH_LOCAL",
Inst::Pop(_) => "POP",
Inst::GetAttr(_) => "GET_ATTR",
Inst::SetAttr(_) => "SET_ATTR",
Inst::Jump(_) => "JUMP",
Inst::JumpTrue(_) => "JUMP_TRUE",
Inst::Call(_) => "CALL",
Inst::Index => "INDEX",
Inst::Return => "RETURN",
Inst::UnNeg => "UN_NEG",
Inst::UnPos => "UN_POS",
Inst::BinPlus => "BIN_PLUS",
Inst::BinMinus => "BIN_MINUS",
Inst::BinMul => "BIN_MUL",
Inst::BinDiv => "BIN_DIV",
Inst::BinEq => "BIN_EQ",
Inst::BinNeq => "BIN_NEQ",
Inst::BinLt => "BIN_LT",
Inst::BinLe => "BIN_LE",
Inst::BinGt => "BIN_GT",
Inst::BinGe => "BIN_GE",
Inst::BinAnd => "BIN_AND",
Inst::BinOr => "BIN_OR",
}
}
}
pub fn dump_inst_body(insts: &Vec<Inst>, const_pool: &ConstPool) {
println!("{}", InstFormatter::new(insts, const_pool))
}
//
// struct InstFormatter
//
pub struct InstFormatter<'i, 'c> {
insts: &'i Vec<Inst>,
const_pool: &'c ConstPool,
}
impl<'i, 'c> InstFormatter<'i, 'c> {
pub fn new(insts: &'i Vec<Inst>, const_pool: &'c ConstPool) -> Self {
Self { insts, const_pool, }
}
}
impl Display for InstFormatter<'_, '_> {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
// column widths
let addr_w = num_digits(self.insts.len(), 16).max(4);
let inst_col = 16 - addr_w;
let inst_w = 16;
for (addr, inst) in self.insts.iter().enumerate() {
let (param_val, mut param_name) = match inst {
Inst::PushSym(sym) | Inst::GetAttr(sym) | Inst::SetAttr(sym) => (
sym.index().to_string(),
global_sym_lookup(*sym).unwrap().to_string(),
),
Inst::PushConst(hdl) => (
hdl.index().to_string(),
{
let obj_ref = self.const_pool.get(*hdl);
read_obj!(let obj = obj_ref);
// XXX weirdness with coercion, can't deref as a &dyn Obj because
// RwReadLockGuard is not Obj - but using Deref::deref works
let obj: &dyn Obj = std::ops::Deref::deref(obj);
format!("{:?}", obj)
},
),
Inst::PushLocal(local) => (
local.index().to_string(),
"TODO: local name".to_string(),
),
Inst::Pop(local) => (
format!("{:?}", local),
"TODO: local name".to_string(),
),
Inst::Jump(addr) | Inst::JumpTrue(addr) => (
addr.to_string(),
String::new(),
),
Inst::Call(argc) => (
argc.to_string(),
String::new(),
),
_ => (String::new(), String::new()),
};
if !param_name.is_empty() {
param_name = format!("({})", param_name);
}
writeln!(
fmt,
"{:0addr_w$x}{space: >inst_col$}{: <inst_w$}{} {}",
addr,
inst.name(),
param_val,
param_name,
space = "",
addr_w = addr_w,
inst_w = inst_w,
inst_col = inst_col,
)?;
}
Ok(())
}
}
fn num_digits(n: usize, radix: usize) -> usize {
((n as f64) + 1.0).log(radix as f64).ceil() as usize
}