53 lines
2.3 KiB
Rust
53 lines
2.3 KiB
Rust
|
|
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); }
|
||
|
|
}
|