diff --git a/src/compile/locals.rs b/src/compile/locals.rs index 7a2b0d7..f04bd5b 100644 --- a/src/compile/locals.rs +++ b/src/compile/locals.rs @@ -50,7 +50,3 @@ impl Visit for CollectLocals<'_, '_> { fn visit_access_expr(&mut self, expr: &AccessExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); } fn visit_atom(&mut self, atom: &Atom) -> Self::Out { DefaultAccept::default_accept(atom, self); } } - -pub fn collect_locals(compile: &mut Compile, body: &Body) { - CollectLocals::new(compile).collect(body); -} diff --git a/src/compile/mod.rs b/src/compile/mod.rs index a309db7..9a51cdb 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -3,7 +3,7 @@ pub mod error; mod locals; pub mod thunk; -use crate::{obj::prelude::*, vm::consts::*}; +use crate::{syn::ast::Body, obj::prelude::*, vm::consts::*}; use std::collections::{BTreeMap, HashMap}; pub struct Compile<'t> { @@ -96,6 +96,11 @@ impl<'t> Compile<'t> { pub fn pop_scope_layer(&mut self) -> Option> { self.locals.pop() } + + /// Collects local variables for the given AST body non-recursively. + pub fn collect_locals(&mut self, body: &Body) { + locals::CollectLocals::new(self).collect(body); + } } #[derive(Debug, Default)] diff --git a/src/compile/thunk.rs b/src/compile/thunk.rs index 958ae78..f8fae74 100644 --- a/src/compile/thunk.rs +++ b/src/compile/thunk.rs @@ -213,7 +213,10 @@ impl<'c, 't> CompileBody<'c, 't> { } pub fn compile(&mut self, body: &'c Body) -> Result { - self.visit_body(body) + self.compile.push_scope_layer(); + let thunk = self.visit_body(body)?; + self.compile.pop_scope_layer(); + Ok(thunk) } } @@ -228,6 +231,7 @@ impl Visit for CompileBody<'_, '_> { type Out = Result; fn visit_body(&mut self, body: &Body) -> Self::Out { + self.compile.collect_locals(body); let mut thunk = Thunk::Nop; for stmt in body.body.iter() { @@ -342,14 +346,10 @@ impl Visit for CompileBody<'_, '_> { fn visit_atom(&mut self, atom: &Atom) -> Self::Out { let thunk = match atom { Atom::Ident(ident) => { - // TODO : set up lexical name stack - // - think about how lexical names in function defs need to be captured, so no - // references get prematurely GC'd - // - Python uses LOAD_CLOSURE and CREATE_FUNCTION ops, but is this necessary if we - // know the names being closed over at runtime? Hm. - + let sym = global_sym(ident.to_string()); + let local = self.compile.lookup_scope(sym).unwrap(); // get local - Inst::PushLocal(global_sym(ident.to_string())).into() + Inst::PushLocal(local).into() } Atom::Sym(sym) => { // push symbol diff --git a/src/vm/inst.rs b/src/vm/inst.rs index 52dae3b..15b9aa2 100644 --- a/src/vm/inst.rs +++ b/src/vm/inst.rs @@ -9,7 +9,7 @@ pub enum Inst { PushConst(ConstHandle), /// Looks up and pushes a local value. - PushLocal(Sym), + PushLocal(Local), /// Pop a value from the stack, possibly into a local symbol. Pop(Option),