in starlark/src/eval/compiler/scope.rs [808:912]
fn test_with_module(program: &str, expected: &str, module: &MutableNames) {
let ast = AstModule::parse("t.star", program.to_owned(), &Dialect::Extended).unwrap();
let mut scope_data = ScopeData::new();
let root_scope_id = scope_data.new_scope().0;
let mut cst = ast
.statement
.into_map_payload(&mut CompilerAstMap(&mut scope_data));
let frozen_heap = FrozenHeap::new();
let codemap = frozen_heap.alloc_any_display_from_debug(ast.codemap.dupe());
let scope = Scope::enter_module(
module,
root_scope_id,
scope_data,
&mut cst,
FrozenRef::new(Globals::empty()),
codemap,
);
assert!(scope.errors.is_empty());
let (.., scope_data) = scope.exit_module();
let mut r = String::new();
for (i, binding) in scope_data.bindings.iter().enumerate() {
if i != 0 {
r.push(' ');
}
let slot = match binding.slot.unwrap() {
Slot::Module(slot) => format!("m={}", slot.0),
Slot::Local(slot) => format!("l={}", slot.0),
};
let assign_count = match binding.assign_count {
AssignCount::AtMostOnce => "",
AssignCount::Any => "+",
};
let captured = match binding.captured {
Captured::Yes => "&",
Captured::No => "",
};
write!(r, "{}:{}{}{}", i, slot, assign_count, captured).unwrap();
}
write!(r, " |").unwrap();
struct Visitor<'a> {
r: &'a mut String,
}
impl Visitor<'_> {
fn visit_expr(&mut self, expr: &CstExpr) {
if let ExprP::Identifier(ident, resolved) = &expr.node {
let resolved = match resolved.as_ref().unwrap() {
ResolvedIdent::Slot((_slot, binding_id)) => binding_id.0.to_string(),
ResolvedIdent::Global(_) => "G".to_owned(),
};
write!(&mut self.r, " {}:{}", ident.node, resolved).unwrap();
}
expr.visit_expr(|expr| self.visit_expr(expr));
}
fn visit_exprs<'a>(&mut self, exprs: impl IntoIterator<Item = &'a CstExpr>) {
for expr in exprs {
self.visit_expr(expr);
}
}
fn visit_lvalue(&mut self, ident: &CstAssignIdent) {
write!(&mut self.r, " {}:{}", ident.0, ident.1.unwrap().0).unwrap();
}
fn visit_stmt_children(&mut self, stmt: &CstStmt) {
stmt.visit_children(|visit| match visit {
Visit::Stmt(stmt) => self.visit_stmt(stmt),
Visit::Expr(expr) => self.visit_expr(expr),
});
}
fn visit_assign(&mut self, assign: &CstAssign) {
assign.visit_lvalue(|ident| self.visit_lvalue(ident));
}
fn visit_stmt(&mut self, stmt: &CstStmt) {
match &stmt.node {
StmtP::Assign(lhs, _rhs) => self.visit_assign(lhs),
StmtP::Def(name, params, ..) => {
self.visit_lvalue(name);
for param in params {
let (name, def, typ) = param.split();
if let Some(name) = name {
self.visit_lvalue(name);
}
self.visit_exprs(def);
self.visit_exprs(typ);
}
}
StmtP::For(assign, ..) => self.visit_assign(assign),
_ => {}
}
self.visit_stmt_children(stmt);
}
}
Visitor { r: &mut r }.visit_stmt(&cst);
assert_eq!(expected, &r);
}