                 n.value = @visit n.value
                 n
 
+        visitBlock: (n) ->
+                return super(n) if not n.ejs_env
+                
+                this_env_id = b.identifier("%env_#{n.ejs_env.id}")
+                if n.ejs_env.parent?
+                        parent_env_name = "%env_#{n.ejs_env.parent.id}"
+                        
+                env_prepends = []
+                new_mapping = shallow_copy_object @currentMapping()
+                
+                if n.ejs_env.closed.empty() and not n.ejs_env.nested_requires_env
+                        env_prepends.push b.letDeclaration(this_env_id, b.null())
+                else
+                        # insert environment creation (at the start of the block)
+                        env_prepends.push b.letDeclaration(this_env_id, intrinsic makeClosureEnv_id, [b.literal n.ejs_env.closed.size() + if n.ejs_env.parent? then 1 else 0])
+                
+                        n.ejs_env.slot_mapping = Object.create null
+                        i = 0
+                        if n.ejs_env.parent?
+                                n.ejs_env.slot_mapping[parent_env_name] = i
+                                i += 1
+                        n.ejs_env.closed.map (el) ->
+                                n.ejs_env.slot_mapping[el] = i
+                                i += 1
+                                
+                        
+                        if n.ejs_env.parent?
+                                parent_env_slot = n.ejs_env.slot_mapping[parent_env_name]
+                                env_prepends.push b.expressionStatement(intrinsic setSlot_id, [this_env_id, b.literal(parent_env_slot), b.literal(parent_env_name), b.identifier(parent_env_name) ]);
+
+                        # XXX here's where function handling pushes closed over parameters.  i'm guessing we need special logic for incoming environment slots for loop variables?
+
+                        new_mapping["%slot_mapping"] = n.ejs_env.slot_mapping
+
+                        flatten_memberexp = (exp, mapping) ->
+                                if exp.type isnt CallExpression
+                                        [b.literal(mapping[exp.name])]
+                                else
+                                        flatten_memberexp(exp.arguments[0], mapping).concat [exp.arguments[1]]
+
+                        prepend_environment = (exps) ->
+                                obj = this_env_id
+                                for prop in exps
+                                        obj = intrinsic(slot_id, [obj, prop])
+                                obj
+
+                        # if there are existing mappings prepend "%env." (a MemberExpression) to them
+                        for mapped of new_mapping
+                                val = new_mapping[mapped]
+                                if mapped isnt "%slot_mapping"
+                                        new_mapping[mapped] = prepend_environment(flatten_memberexp(val, n.ejs_env.slot_mapping))
+                        
+                        # and add mappings for all variables in .closed from "x" to "%env.x"
+
+                        new_mapping["%env"] = this_env_id
+                        n.ejs_env.closed.map (sym) ->
+                                new_mapping[sym] = intrinsic slot_id, [this_env_id, b.literal(n.ejs_env.slot_mapping[sym]), b.literal(sym)]
+
+                # remove all mappings for variables declared in this block
+                if n.ejs_decls?
+                        new_mapping = reject new_mapping, (sym) -> (n.ejs_decls.has sym) and not (n.ejs_env.closed.has sym)
+
+                @mappings.push new_mapping
+                super(n)
+                if env_prepends.length > 0
+                        n.body = env_prepends.concat n.body
+                @mappings.pop()
+                n
+
         visitFunctionBody: (n) ->
                 n.scratch_size = 0
                 

                @envs.pop()
                n

        visitVariableDeclarator: (n) ->
                # don't visit the id, as that will cause us to mark it ejs_substitute = true, and we'll end up with things like:
                #   var %env_1.x = blah

                exp.ejs_free_vars = uses.subtract decls
                exp.ejs_free_vars

        get_decls = (exp) -> if not exp? then null else exp.ejs_decls
        
        # TODO: move this into the @visit method
        free: (exp) ->
                return new Set if not exp?
