diff --git a/src/compile/mod.rs b/src/compile/mod.rs index 84b4a19..b189cc9 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -104,6 +104,10 @@ impl Compile { pub(crate) fn collect_locals(&mut self, body: &Body) { locals::CollectLocals::new(self).collect(body); } + + pub(crate) fn scope(&self) -> &Scope { + &self.scope + } } /// Constant data pool used for building the const pool. diff --git a/src/compile/scope.rs b/src/compile/scope.rs index bc57a50..2a348f1 100644 --- a/src/compile/scope.rs +++ b/src/compile/scope.rs @@ -69,4 +69,8 @@ impl Scope { pub fn globals_mut(&mut self) -> Option<&mut ScopeLocalSyms> { self.scope.first_mut() } + + pub fn layers_len(&self) -> usize { + self.scope.len() + } } diff --git a/src/compile/thunk.rs b/src/compile/thunk.rs index 47b571b..9143ce6 100644 --- a/src/compile/thunk.rs +++ b/src/compile/thunk.rs @@ -419,12 +419,21 @@ impl Visit for CompileBody<'_> { let thunk = match atom { Atom::Ident(ident) => { let sym = global_sym(ident.to_string()); - // TODO : use "LOAD_GLOBAL" instead of "LOAD_LOCAL" when inside a user function - if let Some(local) = self.compile.lookup_local(sym) { + // Small gotcha: + // Looking up a name will either result in a local or a global lookup. If it's + // a local variable first, then it's determined as a local and that's the end + // of the story... except when we're at the top scope level, we're both "local" + // *and* global. + // + // This checks to make sure that it's both a local variable and that there's more + // than one scope layer. + if let (true, Some(local)) = (self.compile.scope().layers_len() > 1, self.compile.lookup_local(sym)) { // get local Inst::LoadLocal(local).into() } else { // get or create global + // create_global only makes a new global with this symbol name if one has not + // been created yet let global = self.compile.create_global(sym); Inst::LoadGlobal(global).into() }