Files
not-python/src/compile/locals.rs

53 lines
2.3 KiB
Rust
Raw Normal View History

use crate::{compile::Compile, obj::prelude::*, syn::{ast::*, visit::*}};
/// Collects local names from the given tree.
///
/// This will *not* attempt to recursively collect locals, and will only stay on the base statement
/// level.
pub struct CollectLocals<'c, 't> {
compile: &'c mut Compile<'t>,
}
// - Python's LEGB methodology seems to be good. Look up variables in this order:
// - Local
// - Enclosing functions (i.e. inner functions)
// - Global
// - Builtin
// - Resolving names:
// - Scan assignments first. If anything is assigned (even before usage), it's local.
// - Everything else should just do a lookup
impl<'c, 't> CollectLocals<'c, 't> {
pub fn new(compile: &'c mut Compile<'t>) -> Self {
Self { compile }
}
pub fn collect(&mut self, body: &Body) {
self.visit_body(body)
}
}
impl Visit for CollectLocals<'_, '_> {
type Out = ();
fn visit_body(&mut self, body: &Body) -> Self::Out { DefaultAccept::default_accept(body, self); }
fn visit_stmt(&mut self, stmt: &Stmt) -> Self::Out { DefaultAccept::default_accept(stmt, self); }
fn visit_assign_stmt(&mut self, assign: &AssignStmt) -> Self::Out { DefaultAccept::default_accept(assign, self); }
fn visit_lhs_expr(&mut self, lhs_expr: &LhsExpr) -> Self::Out {
match lhs_expr {
LhsExpr::Local(name) => {
let sym = global_sym(name.to_string());
self.compile.create_local(sym);
}
_ => { /* no op */ }
}
}
fn visit_expr(&mut self, expr: &Expr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
fn visit_bin_expr(&mut self, expr: &BinExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
fn visit_un_expr(&mut self, expr: &UnExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
fn visit_call_expr(&mut self, expr: &CallExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
fn visit_index_expr(&mut self, expr: &IndexExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
fn visit_access_expr(&mut self, expr: &AccessExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
fn visit_atom(&mut self, atom: &Atom) -> Self::Out { DefaultAccept::default_accept(atom, self); }
}