diff --git a/crates/compiler/src/compiler.rs b/crates/compiler/src/compiler.rs old mode 100755 new mode 100644 index 514a93d..f69beca --- a/crates/compiler/src/compiler.rs +++ b/crates/compiler/src/compiler.rs @@ -102,7 +102,31 @@ impl Compiler { self.emit(Opcode::Pop, vec![]); } Statement::Let(s) => { - let symbol = self.symbol_table.define(s.name.value); + // This step is extremely important. If it is not done then when shadowing variables + // and using the previous value we get an error. Because we would have assigned + // a new index to the symbol and the GetGlobal instruction would get a NULL + // value instead of the previous value. (corresponds to issue #11) + let symbol = match self.symbol_table.resolve(&s.name.value) { + Some(symbol) => match symbol.scope { + SymbolScope::Global => { + // A Local variable should never replace a global one + if self.symbol_table.has_outer() { + // This means that the symbol will + // be local and not global + self.symbol_table.define(s.name.value) + } else { + symbol + } + } + SymbolScope::Local => symbol, + + // We only want to do in in the case of "normal" variable assignation. + // The special cases should not be touched, since the program should not + // have access to them, only the compiler/vm + _ => self.symbol_table.define(s.name.value), + }, + None => self.symbol_table.define(s.name.value), + }; self.compile_expression(s.value)?; diff --git a/crates/compiler/src/symbol_table.rs b/crates/compiler/src/symbol_table.rs index 53791af..cf12455 100644 --- a/crates/compiler/src/symbol_table.rs +++ b/crates/compiler/src/symbol_table.rs @@ -115,6 +115,10 @@ impl SymbolTable { self.store.insert(symbol.name.clone(), symbol.clone()); symbol } + + pub fn has_outer(&self) -> bool{ + self.outer.is_some() + } } #[cfg(test)]