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:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user