2020-09-17 13:09:37 -07:00
|
|
|
use crate::{obj::prelude::*, vm::consts::*};
|
|
|
|
|
use std::fmt::{self, Display, Formatter};
|
2020-09-01 17:32:48 -07:00
|
|
|
|
2020-09-14 16:32:00 -07:00
|
|
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
2020-09-01 17:32:48 -07:00
|
|
|
pub enum Inst {
|
|
|
|
|
/// Push a literal symbol object to the stack.
|
|
|
|
|
PushSym(Sym),
|
|
|
|
|
|
2020-09-14 14:09:29 -07:00
|
|
|
/// Push a const value reference to the stack.
|
|
|
|
|
PushConst(ConstHandle),
|
|
|
|
|
|
|
|
|
|
/// Looks up and pushes a local value.
|
2020-09-16 17:27:33 -07:00
|
|
|
PushLocal(Local),
|
2020-09-14 14:09:29 -07:00
|
|
|
|
2020-09-01 17:32:48 -07:00
|
|
|
/// Pop a value from the stack, possibly into a local symbol.
|
2020-09-17 13:09:37 -07:00
|
|
|
Pop(Option<Local>),
|
2020-09-01 17:32:48 -07:00
|
|
|
|
|
|
|
|
/// Pops a symbol value and an object reference.
|
|
|
|
|
///
|
|
|
|
|
/// This will get an attr from the object reference pointed to by the symbol.
|
2020-09-14 14:09:29 -07:00
|
|
|
GetAttr(Sym),
|
2020-09-01 17:32:48 -07:00
|
|
|
|
2020-09-14 14:09:29 -07:00
|
|
|
/// A target reference and a source reference from the stack.
|
2020-09-01 17:32:48 -07:00
|
|
|
///
|
2020-09-14 14:09:29 -07:00
|
|
|
/// The target reference will have the given symbol attribute assigned to the source.
|
2020-09-01 17:32:48 -07:00
|
|
|
///
|
2020-09-14 14:09:29 -07:00
|
|
|
/// In code, it would look like this:
|
|
|
|
|
///
|
2020-09-16 17:18:31 -07:00
|
|
|
/// `target.symbol = source`
|
2020-09-14 14:09:29 -07:00
|
|
|
///
|
|
|
|
|
SetAttr(Sym),
|
2020-09-01 17:32:48 -07:00
|
|
|
|
|
|
|
|
/// 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),
|
|
|
|
|
|
2020-09-14 14:09:29 -07:00
|
|
|
/// 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.
|
2020-09-01 17:32:48 -07:00
|
|
|
Call(usize),
|
|
|
|
|
|
2020-09-14 14:09:29 -07:00
|
|
|
/// 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,
|
|
|
|
|
|
2020-09-01 17:32:48 -07:00
|
|
|
/// Pops the top value from the stack, and returns from the function, using the popped value as
|
|
|
|
|
/// a return value.
|
|
|
|
|
Return,
|
2020-09-14 14:09:29 -07:00
|
|
|
|
|
|
|
|
/// 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,
|
2020-09-01 17:32:48 -07:00
|
|
|
}
|
2020-09-17 13:09:37 -07:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// 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
|
|
|
|
|
}
|