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) {
locals::CollectLocals::new(self).collect(body);
}
pub(crate) fn scope(&self) -> &Scope {
&self.scope
}
}
/// 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> {
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 {
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()
}