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 <alekratz@gmail.com>
This commit is contained in:
2020-10-19 16:57:40 -07:00
parent f35d44cf65
commit 1d6b2e35bc
3 changed files with 19 additions and 2 deletions

View File

@@ -104,6 +104,10 @@ impl Compile {
pub(crate) fn collect_locals(&mut self, body: &Body) { pub(crate) fn collect_locals(&mut self, body: &Body) {
locals::CollectLocals::new(self).collect(body); locals::CollectLocals::new(self).collect(body);
} }
pub(crate) fn scope(&self) -> &Scope {
&self.scope
}
} }
/// Constant data pool used for building the const pool. /// Constant data pool used for building the const pool.

View File

@@ -69,4 +69,8 @@ impl Scope {
pub fn globals_mut(&mut self) -> Option<&mut ScopeLocalSyms> { pub fn globals_mut(&mut self) -> Option<&mut ScopeLocalSyms> {
self.scope.first_mut() self.scope.first_mut()
} }
pub fn layers_len(&self) -> usize {
self.scope.len()
}
} }

View File

@@ -419,12 +419,21 @@ impl Visit for CompileBody<'_> {
let thunk = match atom { let thunk = match atom {
Atom::Ident(ident) => { Atom::Ident(ident) => {
let sym = global_sym(ident.to_string()); let sym = global_sym(ident.to_string());
// TODO : use "LOAD_GLOBAL" instead of "LOAD_LOCAL" when inside a user function // Small gotcha:
if let Some(local) = self.compile.lookup_local(sym) { // 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 // get local
Inst::LoadLocal(local).into() Inst::LoadLocal(local).into()
} else { } else {
// get or create global // 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); let global = self.compile.create_global(sym);
Inst::LoadGlobal(global).into() Inst::LoadGlobal(global).into()
} }