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), /// 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, const_pool: &ConstPool) { println!("{}", InstFormatter::new(insts, const_pool)) } // // struct InstFormatter // pub struct InstFormatter<'i, 'c> { insts: &'i Vec, const_pool: &'c ConstPool, } impl<'i, 'c> InstFormatter<'i, 'c> { pub fn new(insts: &'i Vec, 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$}{: usize { ((n as f64) + 1.0).log(radix as f64).ceil() as usize }