   ###
 
   pushStack: (node) ->
-    @parent = @scope
+    [ oldScope, oldCtx ] = [ @scope, @ctx ]
+    # TODO remove @parent = @scope
     @scopes.push [ node, @ctx ]
     @ctx = clone(@ctx)
     @scope = node
-    @onScopeEnter?(node, @ctx)
+    @onScopeEnter?(@scope, @ctx, oldScope, oldCtx)
 
   popStack: (node) ->
-    @onScopeExit?(node, @ctx)
+    [ oldScope, oldCtx ] = [ @scope, @ctx ]
     [ @scope, @ctx ] = @scopes.pop()
-    @parent = if @scopes.length > 1 then @scopes[@scopes.length-2]
+    # TODO remove @parent = if @scopes.length > 1 then @scopes[@scopes.length-2]
+    @onScopeExit?(@scope, @ctx, oldScope, oldCtx)
     node
 
   ###*

    @estraverse().replace root,
      enter: (node, parent) ->
        self.controller = this
        depth += 1
        fn = self["#{node.type}"]
        res = (fn.apply(self, [ node, parent, (=> @skip()), (=> @break()) ]) if fn)
        self.onEnter?(node, depth, fn, res)
        res
      leave: (node, parent) ->
        self.controller = this
        fn = self["#{node.type}Exit"]
        res = (fn.apply(self, [ node, parent, (=> @skip()), (=> @break()) ]) if fn)
        self.onExit?(node, depth, fn, res)
        depth -= 1
        res
    root


class OtherTransformer extends TransformerBase
  Program: (node) ->
    @pushStack node

  ProgramExit: (node) ->
    @popStack node

  BlockStatementExit: (node) ->
    @removeEmptyStatementsFromBody node

  FunctionDeclaration: (node, parent) ->
    throw new Error("FnDecl: Not supposed to happen") # it's supposed to be eaten by fixScope

  FunctionExpression: (node, parent) ->
    throw new Error("NamedFnExpr: Not supposed to happen") if node.id # fixScope should've gotten this case
    @pushStack node.body
    @removeUndefinedParameter node

  FunctionExpressionExit: (node) ->
    @popStack()

  SwitchStatement: (node) ->
    @consolidateCases node

  SwitchCase: (node) ->
    @removeBreaksFromConsequents(node)

  CallExpression: (node) ->
    @parenthesizeCallee(node)

  MemberExpression: (node) ->
    @transformThisToAtSign(node)
    @replaceWithPrototype(node) or
    @parenthesizeObjectIfFunction(node)

  CoffeePrototypeExpression: (node) ->
    @transformThisToAtSign(node)

  Identifier: (node) ->
    @escapeUndefined(node)

  BinaryExpression: (node) ->
    @updateBinaryExpression node

  UnaryExpression: (node) ->
    @updateVoidToUndefined node

  LabeledStatement: (node, parent) ->
    @warnAboutLabeledStatements node, parent

  WithStatement: (node) ->
    @syntaxError node, "'with' is not supported in CoffeeScript"

  VariableDeclarator: (node) ->
    @addShadowingIfNeeded(node)
    @addExplicitUndefinedInitializer(node)

  ###
  # Remove `{type: 'EmptyStatement'}` from the body.
