fn test_with_module()

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