Add instruction dumper

A vector of instructions and constants can now be decompiled as text on
the terminal to give an idea of what the VM is doing.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-09-17 13:09:37 -07:00
parent be6266832e
commit 534812f54d
5 changed files with 155 additions and 15 deletions

View File

@@ -11,6 +11,7 @@ pub struct Compile {
const_data: ConstData,
globals: BTreeMap<Sym, Local>,
locals: Vec<BTreeMap<Sym, Local>>,
names: Vec<Sym>,
next_local: Local,
}
@@ -63,6 +64,15 @@ impl Compile {
.copied()
}
/// Looks up a variable name, or creates a global name if it doesn't exist.
pub fn lookup_scope_or_create_global(&mut self, sym: Sym) -> Local {
if let Some(local) = self.lookup_scope(sym) {
local
} else {
self.create_global(sym)
}
}
/// Creates a new local variable if it does not exist in the current local scope.
pub(crate) fn create_local(&mut self, sym: Sym) -> Local {
let locals = self.locals.last_mut().expect("scope");
@@ -73,6 +83,8 @@ impl Compile {
let local = self.next_local;
self.next_local = self.next_local.next();
locals.insert(sym, local);
self.names.push(sym);
assert_eq!(self.names.len(), self.next_local.index());
local
}
}
@@ -85,6 +97,8 @@ impl Compile {
let global = self.next_local;
self.next_local = self.next_local.next();
self.globals.insert(sym, global);
self.names.push(sym);
assert_eq!(self.names.len(), self.next_local.index());
global
}
}

View File

@@ -264,8 +264,9 @@ impl Visit for CompileBody<'_> {
let attr = global_sym(expr.access.to_string());
thunk.push(Inst::SetAttr(attr));
}
LhsExpr::Local(local) => {
let local = global_sym(local.to_string());
LhsExpr::Local(local_name) => {
let sym = global_sym(local_name.to_string());
let local = self.compile.lookup_scope_or_create_global(sym);
thunk = Inst::Pop(Some(local)).into();
}
}
@@ -320,6 +321,7 @@ impl Visit for CompileBody<'_> {
for arg in expr.args.iter() {
thunk.push_thunk(self.visit_expr(&arg)?);
}
thunk.push(Inst::Call(expr.args.len()));
Ok(thunk)
}
@@ -347,13 +349,7 @@ impl Visit for CompileBody<'_> {
let thunk = match atom {
Atom::Ident(ident) => {
let sym = global_sym(ident.to_string());
let local = if let Some(local) = self.compile.lookup_scope(sym) {
local
} else {
// create a global that gets looked up instead, since nothing with this name
// has been declared/assigned in this scope
self.compile.create_global(sym)
};
let local = self.compile.lookup_scope_or_create_global(sym);
// get local
Inst::PushLocal(local).into()
}