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); } }