Add name-scanning pass to compiler

Compile::discover_locals now takes a Vec<SpExpr> instead of a single
SpExpr. It is also called before the compiler starts building the list
of instructions so that all names in the scope are available at
compile-time.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2022-02-16 15:19:14 -08:00
parent f70c27a423
commit d77bf48fe9
2 changed files with 7 additions and 8 deletions

View File

@@ -1,8 +1,5 @@
[ :x x x ] :dup [ :x x x ] :dup
# This a dumb little workaround to allow for recursion so factorial inside of
# the function definition will look in the correct scope
0 :factorial
[ [
dup! dup!
[dup! 1 -! factorial! *!] [dup! 1 -! factorial! *!]

View File

@@ -48,8 +48,8 @@ impl<'s> Compile<'s> {
// Local scopes are implicit. If a variable is assigned to at // Local scopes are implicit. If a variable is assigned to at
// all in the current scope, it's considered to be a local. // all in the current scope, it's considered to be a local.
let mut code = Vec::new(); let mut code = Vec::new();
self.discover_locals(&expr_list);
for expr in expr_list { for expr in expr_list {
self.discover_locals(&expr);
code.extend(self.compile_expr(&expr)); code.extend(self.compile_expr(&expr));
} }
code code
@@ -102,7 +102,8 @@ impl<'s> Compile<'s> {
/// ///
/// If any assignment for a local variable appears in the scope, it will be /// If any assignment for a local variable appears in the scope, it will be
/// inserted. /// inserted.
fn discover_locals(&mut self, expr: &SpExpr) { fn discover_locals(&mut self, exprs: &Vec<SpExpr>) {
for expr in exprs.iter() {
if let Expr::Atom(atom) = expr.inner() { if let Expr::Atom(atom) = expr.inner() {
if let Atom::Assign(text) = atom.inner() { if let Atom::Assign(text) = atom.inner() {
self.scope_stack.insert_local(text); self.scope_stack.insert_local(text);
@@ -110,3 +111,4 @@ impl<'s> Compile<'s> {
} }
} }
} }
}