From 1d6b2e35bc0b57bc3c70dd2fd2cdaa2dcd24e1e9 Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Mon, 19 Oct 2020 16:57:40 -0700 Subject: [PATCH] Fix bug where global names could only be used once in the root scope Global names previously would only load once, and then not again because of issues with how the root scope is compiled. This is fixed. Signed-off-by: Alek Ratzloff --- src/compile/mod.rs | 4 ++++ src/compile/scope.rs | 4 ++++ src/compile/thunk.rs | 13 +++++++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) 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() }