             else
               null
           if fnName is 'eval'
-            await interp ast, env, defer(e, result)
-            return cont(e, result)
-          else
-            await interp ast, env.getGlobalEnv(), defer(e, result)
-            return cont(e, result)
+            interp ast, env, cont, errCont
+          else
+            interp ast, env.getGlobalEnv(), cont, errCont
         else
           if callee instanceof InterpretedFunction
-            await callee.applyCps _this, args, defer(e, applied)
-            return cont(e) if e?
-            return cont(null, applied)
-          else
-            applied = callee.apply _this, args
-            return cont(null, applied)
+            callee.applyCps _this, args, cont, errCont
+          else
+            cont callee.apply _this, args
       when 'NewExpression'
-        await interp node.callee, env, defer(e, callee)
-        return cont(e) if e?
-        args = []
-        for arg in node.arguments
-          await interp(arg, env, defer(e, result))
-          return cont(e) if e?
-          args.push(result)
+        await interp node.callee, env, defer(callee), errCont
+        args =
+          for arg in node.arguments
+            await interp arg, env, defer(result), errCont
+            result
         if callee.__ctor__?
           obj = new callee.__ctor__
           if callee instanceof InterpretedFunction
-            await callee.applyCps obj, args, defer(e, result)
-            return cont(e) if e?
+            await callee.applyCps obj, args, defer(result), errCont
           else
             callee.apply obj, args
         else
           if callee instanceof InterpretedFunction
-            await callee.bind.applyCps callee, ([null].concat args), defer(e, result)
-            return cont(e) if e?
+            await callee.bind.applyCps callee, ([null].concat args), defer(result), errCont
           else
             obj = new (callee.bind.apply callee, [null].concat args)
-        return cont(null, obj)
+        cont(obj)
       #*** Control Flow ***#
       when 'IfStatement'
-        await interp node.test, env, defer(e, test)
-        return cont(e) if e?
+        await interp node.test, env, defer(test), errCont
         if (test)
-          await interp node.consequent, env, defer(e, result)
-          return cont(e, result)
+          interp node.consequent, env, cont, errCont
         else if node.alternate?
-          await interp node.alternate, env, defer(e, result)
-          return cont(e, result)
-        else
-          return cont()
+          interp node.alternate, env, cont, errCont
+        else
+          cont()
       when 'WhileStatement'
         while (true)
           # Test
-          await interp node.test env, defer(e, test)
-          return cont(e) if e?
+          await interp node.test env, defer(test), errCont
           return cont() if not test
           # Body
-          await interp node.body, env, defer(e)
-          return cont() if e instanceof BreakException
-          return cont(e) if e? and not (e instanceof ContinueException)
-        return cont()
+          await
+            interp node.body, env, bodyCont = defer(),
+              makeLoopCont(node.body, env, bodyCont, cont, errCont)
       when 'DoWhileStatement'
         while (true)
           # Body
-          await interp node.body, env, defer(e)
-          return cont() if e instanceof BreakException
-          return cont(e) if e? and not (e instanceof ContinueException)
+          await
+            interp node.body, env, bodyCont = defer(),
+              makeLoopCont(node.body, env, bodyCont, cont, errCont)
           # Test
-          await interp node.test, env, defer(e, test)
-          return cont(e) if e?
+          await interp node.test, env, defer(test), errCont
           return cont() if not test
-        return cont()
       when 'ForStatement'
-        await interp node.init, env, defer(e)
-        return cont(e) if e?
+        await interp node.init, env, defer(), errCont
         while (true)
           # Test
-          await interp node.test, env, defer(e, test)
-          return cont(e) if e?
+          await interp node.test, env, defer(test), errCont
           return cont() if not test
           # Body
-          await interp node.body, env, defer(e)
-          return cont() if e instanceof BreakException
-          return cont(e) if e? and not (e instanceof ContinueException)
+          await
+            interp node.body, env, bodyCont = defer(),
+              makeLoopCont(node.body, env, bodyCont, cont, errCont)
           # Update
-          await interp node.update, env, defer(e)
-          return cont() if e instanceof BreakException
-          return cont(e) if e? and not (e instanceof ContinueException)
+          await interp node.update, env, defer(), errCont
       when 'ForInStatement'
-        await interp node.left, env, defer(e)
-        return cont(e) if e?
-        await interp node.right, env, defer(e, obj)
-        return cont(e) if e?
+        await interp node.left, env, defer(), errCont
+        await interp node.right, env, defer(obj), errCont
         for k of obj
           if node.left.type is 'VariableDeclaration'
-            await assign node.left.declarations[0].id, k, env, defer(e, result)
-            return cont(e) if e?
-          else
-            await assign node.left, k, env, defer(e, result)
-            return cont(e) if e?
-          await interp node.body, env, defer(e)
-          return cont(e) if e?
-        return cont()
+            await assign node.left.declarations[0].id, k, env, defer(), errCont
+          else
+            await assign node.left, k, env, defer(), errCont
+          await
+            interp node.body, env, bodyCont = defer(),
+              makeLoopCont(node.body, env, bodyCont, cont, errCont)
+        cont()
       when 'BreakStatement'
-        return cont(new BreakException)
+        errCont(new BreakException)
       when 'ContinueStatement'
-        return cont(new ContinueException)
+        errCont(new ContinueException)
       when 'ReturnStatement'
-        return cont(new ReturnException undefined) if node.argument is null
-        await interp node.argument, env, defer(e, result)
-        return cont(e || new ReturnException result)
+        if node.argument is null
+          errCont new ReturnException undefined
+        else
+          await interp node.argument, env, defer(result), errCont
+          errCont new ReturnException result
       when 'ThrowStatement'
-        await interp node.argument, env, defer(e, result)
-        return cont(e || new JSException result)
+        await interp node.argument, env, defer(result), errCont
+        errCont new JSException result
       when 'TryStatement'
-        await interp node.block, env, defer(errorInTry, result)
-        if errorInTry instanceof JSException and node.handlers.length > 0
-          catchEnv = env.increaseScope true
-          catchEnv.set node.handlers[0].param.name, errorInTry.exception
-          await interp node.handlers[0], env, defer(errorInCatch, result)
-          env.decreaseScope() # unless errorInCatch?
-          if node.finalizer # try->catch->finally
-            await interp node.finalizer, env, defer(errorInFinalizer, result)
-            return cont(errorInFinalizer || errorInCatch)
-          else # try->catch
-            return cont(eInCatch)
-        else if node.finalizer
-          await interp node.finalizer, env, defer(errorInFinalizer, result)
-          return cont(errorInFinalizer || errorInTry) # try->finally
-        else
-          return cont(errorInTry) # try
+        interp node.block, env, cont, (e) ->
+          if e instanceof JSException and node.handlers.length > 0
+            catchEnv = env.increaseScope true
+            catchEnv.set node.handlers[0].param.name, e.exception
+            await interp node.handlers[0], env, defer(), errCont
+            env.decreaseScope()
+          if node.finalizer
+            interp node.finalizer, env, cont, errCont
+          else
+            cont()
       when 'CatchClause'
-        await interp node.body, env, defer(e, result)
-        return cont(e, result)
+        await interp node.body, env, cont, errCont
       #*** Operator Expressions ***#
       when 'BinaryExpression'
-        await interp node.left, env, defer(e, lhs)
-        return cont(e) if e?
-        await interp node.right, env, defer(e, rhs)
-        return cont(e) if e?
+        await interp node.left, env, defer(lhs), errCont
+        await interp node.right, env, defer(rhs), errCont
         switch node.operator
           when '+'
-            return cont(null, lhs + rhs)
+            cont(lhs + rhs)
           when '-'
-            return cont(null, lhs - rhs)
+            cont(lhs - rhs)
           when '*'
-            return cont(null, lhs * rhs)
+            cont(lhs * rhs)
           when '/'
-            return cont(null, lhs / rhs)
+            cont(lhs / rhs) # TODO handle divzero
           when '&'
-            return cont(null, lhs & rhs)
+            cont(lhs & rhs)
           when '|'
-            return cont(null, lhs | rhs)
+            cont(lhs | rhs)
           when '^'
-            return cont(null, lhs ^ rhs)
+            cont(lhs ^ rhs)
           when '>>'
-            return cont(null, lhs >> rhs)
+            cont(lhs >> rhs)
           when '<<'
-            return cont(null, lhs << rhs)
+            cont(lhs << rhs)
           when '>>>'
-            return cont(null, lhs >>> rhs)
+            cont(lhs >>> rhs)
           when '<'
-            return cont(null, lhs < rhs)
+            cont(lhs < rhs)
           when '>'
-            return cont(null, lhs > rhs)
+            cont(lhs > rhs)
           when '<='
-            return cont(null, lhs <= rhs)
+            cont(lhs <= rhs)
           when '>='
-            return cont(null, lhs >= rhs)
+            cont(lhs >= rhs)
           when '=='
-            return cont(null, `lhs == rhs`)
+            cont(`lhs == rhs`)
           when '==='
-            return cont(null, `lhs === rhs`)
+            cont(`lhs === rhs`)
           when '!='
-            return cont(null, `lhs != rhs`)
+            cont(`lhs != rhs`)
           when '!=='
-            return cont(null, `lhs !== rhs`)
+            cont(`lhs !== rhs`)
           when 'instanceof'
-            return cont(null, lhs instanceof rhs.__ctor__)
-          else
-            return cont("Unrecognized operator #{node.operator}")
+            cont(lhs instanceof rhs.__ctor__)
+          else
+            errCont("Unrecognized operator #{node.operator}")
       when 'AssignmentExpression'
-        await interp node.right, env, defer(e, value)
-        return cont(e) if e?
+        await interp node.right, env, defer(value), errCont
         if node.operator is '='
-          await assign node.left, value, env, defer(e, result)
-          return cont(e, result)
+          assign node.left, value, env, cont, errCont
         else
           if node.left.type is 'Identifier'
             original = env.resolve node.left.name
           else if node.left.type is 'MemberExpression'
-            evalMemberExpr node.left, env, cont(e, result)
-            return cont(e) if e?
-            [object, property] = result
+            await evalMemberExpr node.left, env, defer(object, property), errCont
             original = object[property]
           else
             throw "Invalid LHS in assignment"

    @prototype = @__ctor__.prototype

  apply: (_this, args) ->
    await this.applyCps _this, args, defer(e, result)
    throw e if e?
    return result

  applyCps: (appliedThis, args, cont) ->
    calleeNode = this.__call__
    calleeNode.env.increaseScope()
    argsObject = {}

      argsObject[i] = arg
    Util.defineNonEnumerable argsObject, 'length', args.length
    calleeNode.env.insert 'this', appliedThis
    await interp calleeNode.body, calleeNode.env, defer(result), (e) ->
      if e instanceof ReturnException
        calleeNode.env.decreaseScope()
        cont(e.value)
      else
        errCont(e)
    calleeNode.env.decreaseScope()
    cont(result)

  call: (_this) -> @apply _this, Array::slice arguments, 1

  callCps: (_this, cont, errCont) ->
    applyCps _this, (Array::slice arguments, 1), cont, errCont

interp = (node, env=new Environment, cont, errCont) ->
  try
    switch node.type
      when 'Program', 'BlockStatement'
        for stmt, i in node.body
          env.strict ||= i == 0 and stmt.expression?.value is 'use strict'
          await interp stmt, env, defer(v), errCont
          return cont(v) if node.type is 'Program' and i == node.body.length - 1 # for eval's return value
        cont()
      when 'FunctionDeclaration', 'FunctionExpression'
        node.env = env.copy()
        fn = (new Function "return function #{node.id?.name ? ''}() {}")()
        ifn = new InterpretedFunction fn, node
        if node.id?
          env.insert(node.id.name, ifn)
        cont(ifn)
      when 'VariableDeclaration'
        for dec in node.declarations
          await interp dec, env, defer(result), errCont
        cont()
      when 'VariableDeclarator'
        await interp node.init, env, defer(result), errCont
        declaratorResult = env.insert node.id.name, result, env
        cont(declaratorResult)
      when 'ExpressionStatement'
        interp node.expression, env, cont, errCont
      when 'CallExpression'
        callee = null
        if node.callee.type is 'MemberExpression'
          await evalMemberExpr node.callee, env, defer(_this, calleeName), errCont
          callee = _this[calleeName]
        else
          _this = undefined
          await interp node.callee, env, defer(callee), errCont
        args = []
        for arg in node.arguments
          await interp arg, env, defer(argResult), errCont
          args.push(argResult)
        if callee == eval
          return cont(args[0]) unless Util.isString args[0]
          ast = esprima.parse args[0]
          fnName =
            if node.callee.type is 'MemberExpression' and
