  private CAstNode walkNodesInternal(final Node n, WalkContext context) {
    final int NT = n.getType();
    switch (NT) {
    case Token.FUNCTION: {
      int fnIndex = n.getExistingIntProp(Node.FUNCTION_PROP);
      FunctionNode fn = context.top().getFunctionNode(fnIndex);
      CAstEntity fne = walkEntity(fn, context);
      if (context.expressionContext()) {
        CAstNode fun = Ast.makeNode(CAstNode.FUNCTION_EXPR, Ast.makeConstant(fne));
        context.addScopedEntity(fun, fne);
        return fun;
      } else {
        context.addNameDecl(Ast.makeNode(CAstNode.FUNCTION_STMT, Ast.makeConstant(fne)));
        context.addScopedEntity(null, fne);
        return Ast.makeNode(CAstNode.EMPTY);
      }
    }
    case Token.CATCH_SCOPE: {
      Node catchVarNode = n.getFirstChild();
      String catchVarName = catchVarNode.getString();
      assert catchVarName != null;
      context.setCatchVar(catchVarName);
      return Ast.makeNode(CAstNode.EMPTY);
    }
    case Token.LOCAL_BLOCK: {
      return Ast.makeNode(CAstNode.BLOCK_EXPR, gatherChildren(n, context));
    }
    case Token.TRY: {
      Node catchNode = ((Node.Jump) n).target;
      Node finallyNode = ((Node.Jump) n).getFinally();
      ArrayList<Node> tryList = new ArrayList<Node>();
      ArrayList<Node> catchList = new ArrayList<Node>();
      ArrayList<Node> finallyList = new ArrayList<Node>();
      ArrayList<Node> current = tryList;
      Node c;
      for (c = n.getFirstChild(); c.getNext() != null; c = c.getNext()) {
        if (c == catchNode) {
          current = catchList;
        } else if (c == finallyNode) {
          current = finallyList;
        }
        if (c.getType() == Token.GOTO &&
            (c.getNext() == catchNode || c.getNext() == finallyNode)) {
          continue;
        }
        current.add(c);
      }
      CAstNode finallyBlock = null;
      if (finallyNode != null) {
        int i = 0;
        CAstNode[] finallyAsts = new CAstNode[finallyList.size()];
        for (Iterator<Node> fns = finallyList.iterator(); fns.hasNext();) {
          finallyAsts[i++] = walkNodes(fns.next(), context);
        }
        finallyBlock = Ast.makeNode(CAstNode.BLOCK_STMT, finallyAsts);
      }
      if (catchNode != null) {
        int i = 0;
        WalkContext catchChild = new CatchBlockContext(context);
        CAstNode[] catchAsts = new CAstNode[catchList.size()];
        for (Iterator<Node> cns = catchList.iterator(); cns.hasNext();) {
          catchAsts[i++] = walkNodes(cns.next(), catchChild);
        }
        CAstNode catchBlock = Ast.makeNode(CAstNode.CATCH, Ast.makeConstant(catchChild.getCatchVar()),
            Ast.makeNode(CAstNode.BLOCK_STMT, catchAsts));
        context.cfg().map(catchBlock, catchBlock);
        i = 0;
        WalkContext tryChild = new TryBlockContext(context, catchBlock);
        CAstNode[] tryAsts = new CAstNode[tryList.size()];
        for (Iterator<Node> tns = tryList.iterator(); tns.hasNext();) {
          tryAsts[i++] = walkNodes(tns.next(), tryChild);
        }
        CAstNode tryBlock = Ast.makeNode(CAstNode.BLOCK_STMT, tryAsts);
        if (finallyBlock != null) {
          return Ast.makeNode(CAstNode.BLOCK_STMT,
              Ast.makeNode(CAstNode.UNWIND, Ast.makeNode(CAstNode.TRY, tryBlock, catchBlock), finallyBlock), walkNodes(c, context));
        } else {
          return Ast.makeNode(CAstNode.BLOCK_STMT, Ast.makeNode(CAstNode.TRY, tryBlock, catchBlock), walkNodes(c, context));
        }
      } else {
        int i = 0;
        CAstNode[] tryAsts = new CAstNode[tryList.size()];
        for (Iterator<Node> tns = tryList.iterator(); tns.hasNext();) {
          tryAsts[i++] = walkNodes(tns.next(), context);
        }
        CAstNode tryBlock = Ast.makeNode(CAstNode.BLOCK_STMT, tryAsts);
        return Ast.makeNode(
            CAstNode.BLOCK_STMT,
            Ast.makeNode(CAstNode.UNWIND, Ast.makeNode(CAstNode.BLOCK_STMT, tryBlock),
                Ast.makeNode(CAstNode.BLOCK_STMT, finallyBlock)), walkNodes(c, context));
      }
    }
    case Token.JSR: {
      return Ast.makeNode(CAstNode.EMPTY);
    }
    case Token.COMMA: {
      int count = countSiblingsStartingFrom(n.getFirstChild());
      CAstNode[] cs = new CAstNode[count];
      int i = 0;
      for (Node c = n.getFirstChild(); c != null; i++, c = c.getNext()) {
        if (c.getNext() == null) {
          context.updateBase(n, c);
        }
        cs[i] = walkNodes(c, context);
      }
      return Ast.makeNode(CAstNode.BLOCK_EXPR, cs);
    }
    case Token.ENTERWITH:
    case Token.LEAVEWITH: {
      return Ast.makeNode(CAstNode.EMPTY);
    }
    case Token.LOOP: {
      LoopContext child = new LoopContext(context);
      CAstNode[] nodes = gatherChildren(n, child);
      if (child.forInInitExpr != null) {
        String nm = child.forInVar;
        return Ast.makeNode(CAstNode.BLOCK_STMT, Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(nm, true)),
            walkNodes(child.forInInitExpr, context)), nodes);
      } else {
        return Ast.makeNode(CAstNode.BLOCK_STMT, nodes);
      }
    }
    case Token.WITH:
    case Token.FINALLY:
    case Token.BLOCK:
    case Token.LABEL: {
      Node c1 = n.getFirstChild();
      if (c1 != null && c1.getType() == Token.SWITCH) {
        Node switchValue = c1.getFirstChild();
        CAstNode defaultLabel = Ast.makeNode(CAstNode.LABEL_STMT, Ast.makeNode(CAstNode.EMPTY));
        context.cfg().map(defaultLabel, defaultLabel);
        List<CAstNode> labelCasts = new ArrayList<CAstNode>();
        for (Node kase = switchValue.getNext(); kase != null; kase = kase.getNext()) {
          assert kase.getType() == Token.CASE;
          Node caseLbl = kase.getFirstChild();
          Node target = ((Node.Jump) kase).target;
          CAstNode labelCast = walkNodes(caseLbl, context);
          labelCasts.add(labelCast);
          context.cfg().add(c1, target, labelCast);
        }
        CAstNode[] children = new CAstNode[labelCasts.size() + 1];
        int i = 0;
        children[i++] = Ast.makeNode(CAstNode.BLOCK_STMT, defaultLabel, gatherChildren(n, context, 1));
        for (CAstNode labelCast : labelCasts) {
          children[i++] = labelCast;
        }
        context.cfg().add(c1, defaultLabel, CAstControlFlowMap.SWITCH_DEFAULT);
        CAstNode switchAst = Ast.makeNode(CAstNode.SWITCH, walkNodes(switchValue, context), children);
        noteSourcePosition(context, switchAst, c1);
        context.cfg().map(c1, switchAst);
        return switchAst;
      }
      else {
        return Ast.makeNode(CAstNode.BLOCK_STMT, gatherChildren(n, context));
      }
    }
    case Token.EXPR_VOID:
    case Token.EXPR_RESULT: {
      WalkContext child = new ExpressionContext(context);
      Node expr = n.getFirstChild();
      if (NT == Token.EXPR_RESULT) {
        child.updateBase(n, expr);
      }
      return walkNodes(expr, child);
    }
    case Token.POS: {
      return Ast.makeNode(CAstNode.UNARY_EXPR, translateOpcode(Token.ADD), walkNodes(n.getFirstChild(), context));
    }
    case Token.CALL: {
      if (!isPrimitiveCall(context, n)) {
        CAstNode base = makeVarRef("$$ base");
        Node callee = n.getFirstChild();
        WalkContext child = new BaseCollectingContext(context, callee, "$$ base");
        CAstNode fun = walkNodes(callee, child);
        Node firstParamInParens = callee.getNext();
        if (child.foundBase(callee))
          return Ast.makeNode(
              CAstNode.LOCAL_SCOPE,
              Ast.makeNode(CAstNode.BLOCK_EXPR,
                  Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl("$$ base")), Ast.makeConstant(null)),
                  makeCall(fun, base, firstParamInParens, context)));
        else {
          return makeCall(fun, makeVarRef(JSSSAPropagationCallGraphBuilder.GLOBAL_OBJ_VAR_NAME), firstParamInParens, context);
        }
      } else {
        return Ast.makeNode(CAstNode.PRIMITIVE, gatherChildren(n, context, 1));
      }
    }
    case Token.BINDNAME:
    case Token.NAME: {
      return readName(context, n.getString());
    }
    case Token.THIS: {
      return makeVarRef("this");
    }
    case Token.THISFN: {
      return makeVarRef(((FunctionNode) context.top()).getFunctionName());
    }
    case Token.STRING: {
      return Ast.makeConstant(n.getString());
    }
    case Token.NUMBER: {
      return Ast.makeConstant(n.getDouble());
    }
    case Token.FALSE: {
      return Ast.makeConstant(false);
    }
    case Token.TRUE: {
      return Ast.makeConstant(true);
    }
    case Token.NULL:
    case Token.VOID: {
      return Ast.makeConstant(null);
    }
    case Token.ADD:
    case Token.DIV:
    case Token.LSH:
    case Token.MOD:
    case Token.MUL:
    case Token.RSH:
    case Token.SUB:
    case Token.URSH:
    case Token.BITAND:
    case Token.BITOR:
    case Token.BITXOR:
    case Token.EQ:
    case Token.SHEQ:
    case Token.GE:
    case Token.GT:
    case Token.LE:
    case Token.LT:
    case Token.SHNE:
    case Token.NE: {
      Node l = n.getFirstChild();
      Node r = l.getNext();
      return Ast.makeNode(CAstNode.BINARY_EXPR, translateOpcode(NT), walkNodes(l, context), walkNodes(r, context));
    }
    case Token.NEG: {
      return Ast.makeNode(CAstNode.UNARY_EXPR, translateOpcode(Token.SUB), walkNodes(n.getFirstChild(), context));
    }
    case Token.BITNOT:
    case Token.NOT: {
      return Ast.makeNode(CAstNode.UNARY_EXPR, translateOpcode(NT), walkNodes(n.getFirstChild(), context));
    }
    case Token.VAR:
    case Token.CONST: {
      List<CAstNode> result = new ArrayList<CAstNode>();
      Node nm = n.getFirstChild();
      while (nm != null) {
        context.addNameDecl(Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(nm.getString())),
            readName(context, "$$undefined")));
        if (nm.getFirstChild() != null) {
          WalkContext child = new ExpressionContext(context);
          result.add(Ast.makeNode(CAstNode.ASSIGN, makeVarRef(nm.getString()),
              walkNodes(nm.getFirstChild(), child)));
        }
        nm = nm.getNext();
      }
      if (result.size() > 0) {
        return Ast.makeNode(CAstNode.BLOCK_EXPR, result.toArray(new CAstNode[result.size()]));
      } else {
        return Ast.makeNode(CAstNode.EMPTY);
      }
    }
    case Token.REGEXP: {
      int regexIdx = n.getIntProp(Node.REGEXP_PROP, -1);
      assert regexIdx != -1 : "while converting: " + context.top().toStringTree(context.top()) + "\nlooking at bad regex:\n "
          + n.toStringTree(context.top());
      String flags = context.top().getRegexpFlags(regexIdx);
      Node flagsNode = Node.newString(flags);
      String str = context.top().getRegexpString(regexIdx);
      Node strNode = Node.newString(str);
      strNode.addChildToFront(flagsNode);
      return handleNew(context, "RegExp", strNode);
    }
    case Token.ENUM_INIT_KEYS: {
      context.createForInVar(n.getFirstChild());
      return Ast.makeNode(CAstNode.EMPTY);
    }
    case Token.ENUM_ID: {
      return Ast.makeNode(CAstNode.EACH_ELEMENT_GET, makeVarRef(context.getForInInitVar()));
    }
    case Token.ENUM_NEXT: {
      return Ast.makeNode(CAstNode.EACH_ELEMENT_HAS_NEXT, makeVarRef(context.getForInInitVar()));
    }
    case Token.RETURN: {
      Node val = n.getFirstChild();
      if (val != null) {
        WalkContext child = new ExpressionContext(context);
        return Ast.makeNode(CAstNode.RETURN, walkNodes(val, child));
      } else {
        return Ast.makeNode(CAstNode.RETURN);
      }
    }
    case Token.SETNAME: {
      Node nm = n.getFirstChild();
      return Ast.makeNode(CAstNode.ASSIGN, walkNodes(nm, context), walkNodes(nm.getNext(), context));
    }
    case Token.IFNE:
    case Token.IFEQ: {
      context.cfg().add(n, ((Node.Jump) n).target, Boolean.TRUE);
      WalkContext child = new ExpressionContext(context);
      CAstNode gotoAst = Ast.makeNode(CAstNode.IFGOTO, translateOpcode(NT), walkNodes(n.getFirstChild(), child),
          Ast.makeConstant(1));
      context.cfg().map(n, gotoAst);
      return gotoAst;
    }
    case Token.GOTO: {
      context.cfg().add(n, ((Node.Jump) n).target, null);
      CAstNode gotoAst = Ast.makeNode(CAstNode.GOTO, Ast.makeConstant(((Node.Jump) n).target.labelId()));
      context.cfg().map(n, gotoAst);
      return gotoAst;
    }
    case Token.BREAK: {
      context.cfg().add(n, ((Node.Jump) n).getJumpStatement().target, null);
      CAstNode gotoAst = Ast.makeNode(CAstNode.GOTO, Ast.makeConstant(((Node.Jump) n).getJumpStatement().target.labelId()));
      context.cfg().map(n, gotoAst);
      return gotoAst;
    }
    case Token.CONTINUE: {
      context.cfg().add(n, ((Node.Jump) n).getJumpStatement().getContinue(), null);
      CAstNode gotoAst = Ast.makeNode(CAstNode.GOTO, Ast.makeConstant(((Node.Jump) n).getJumpStatement().getContinue().labelId()));
      context.cfg().map(n, gotoAst);
      return gotoAst;
    }
    case Token.TARGET: {
      CAstNode result = Ast.makeNode(CAstNode.LABEL_STMT, Ast.makeConstant(n.labelId()), Ast.makeNode(CAstNode.EMPTY));
      context.cfg().map(n, result);
      return result;
    }
    case Token.OR: {
    	Node l = n.getFirstChild();
    	Node r = l.getNext();
    	CAstNode lhs = walkNodes(l, context);
    	String lhsTempName = "or___lhs";
    	return Ast.makeNode(
    			CAstNode.LOCAL_SCOPE,
    			Ast.makeNode(CAstNode.BLOCK_EXPR,
    					Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(lhsTempName)), lhs),
    					Ast.makeNode(CAstNode.IF_EXPR, makeVarRef(lhsTempName), makeVarRef(lhsTempName), walkNodes(r, context))));
    }
    case Token.AND: {
      Node l = n.getFirstChild();
      Node r = l.getNext();
      CAstNode lhs = walkNodes(l, context);
      String lhsTempName = "and___lhs";
      return Ast.makeNode(
    		  CAstNode.LOCAL_SCOPE,
    		  Ast.makeNode(CAstNode.BLOCK_EXPR,
    				  Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(lhsTempName)), lhs),
    				  Ast.makeNode(CAstNode.IF_EXPR, makeVarRef(lhsTempName), walkNodes(r, context), makeVarRef(lhsTempName))));
    }
    case Token.HOOK: {
      Node cond = n.getFirstChild();
      Node thenBranch = cond.getNext();
      Node elseBranch = thenBranch.getNext();
      return Ast.makeNode(CAstNode.IF_EXPR, walkNodes(cond, context), walkNodes(thenBranch, context),
          walkNodes(elseBranch, context));
    }
    case Token.INC:
    case Token.DEC: {
      int flags = n.getIntProp(Node.INCRDECR_PROP, -1);
      CAstNode op = ((flags & Node.DECR_FLAG) != 0) ? CAstOperator.OP_SUB : CAstOperator.OP_ADD;
      Node l = n.getFirstChild();
      CAstNode last = walkNodes(l, context);
      return Ast.makeNode((((flags & Node.POST_FLAG) != 0) ? CAstNode.ASSIGN_POST_OP : CAstNode.ASSIGN_PRE_OP), last,
          Ast.makeConstant(1), op);
    }
    case Token.NEW: {
      if (isPrimitiveCreation(context, n)) {
        return makeBuiltinNew(n.getFirstChild().getString());
      } else {
        Node receiver = n.getFirstChild();
        return handleNew(context, walkNodes(receiver, context), receiver.getNext());
      }
    }
    case Token.ARRAYLIT: {
      int count = 0;
      for (Node x = n.getFirstChild(); x != null; count++, x = x.getNext())
        ;
      int i = 0;
      CAstNode[] args = new CAstNode[2 * count + 1];
      args[i++] = (isPrologueScript(context)) ? makeBuiltinNew("Array") : handleNew(context, "Array", null);
      int[] skips = (int[]) n.getProp(Node.SKIP_INDEXES_PROP);
      int skip = 0;
      int idx = 0;
      Node elt = n.getFirstChild();
      while (elt != null) {
        if (skips != null && skip < skips.length && skips[skip] == idx) {
          skip++;
          idx++;
          continue;
        }
        args[i++] = Ast.makeConstant(idx++);
        args[i++] = walkNodes(elt, context);
        elt = elt.getNext();
      }
      return Ast.makeNode(CAstNode.OBJECT_LITERAL, args);
    }
    case Token.OBJECTLIT: {
      Object[] propertyList = (Object[]) n.getProp(Node.OBJECT_IDS_PROP);
      CAstNode[] args = new CAstNode[propertyList.length * 2 + 1];
      int i = 0;
      args[i++] = ((isPrologueScript(context)) ? makeBuiltinNew("Object") : handleNew(context, "Object", null));
      Node val = n.getFirstChild();
      int nameIdx = 0;
      for (; nameIdx < propertyList.length; nameIdx++, val = val.getNext()) {
        args[i++] = Ast.makeConstant(propertyList[nameIdx]);
        args[i++] = walkNodes(val, context);
      }
      return Ast.makeNode(CAstNode.OBJECT_LITERAL, args);
    }
    case Token.GETPROP:
    case Token.GETELEM: {
      Node receiver = n.getFirstChild();
      Node element = receiver.getNext();
      CAstNode rcvr = walkNodes(receiver, context);
      String baseVarName = context.getBaseVarNameIfRelevant(n);
      CAstNode elt = walkNodes(element, context);
      CAstNode get, result;
      if (baseVarName != null) {
        result = Ast.makeNode(CAstNode.BLOCK_EXPR, Ast.makeNode(CAstNode.ASSIGN, makeVarRef(baseVarName), rcvr),
            get = Ast.makeNode(CAstNode.OBJECT_REF, makeVarRef(baseVarName), elt));
      } else {
        result = get = Ast.makeNode(CAstNode.OBJECT_REF, rcvr, elt);
      }
      if (context.getCatchTarget() != null) {
        context.cfg().map(get, get);
        context.cfg().add(get, context.getCatchTarget(), JavaScriptTypes.TypeError);
      }
      return result;
    }
    case Token.GET_REF: {
      Node child1 = n.getFirstChild();
      assert child1.getType() == Token.REF_SPECIAL;
      assert child1.getProp(Node.NAME_PROP).equals("__proto__");
      Node receiver = child1.getFirstChild();     
      assert child1.getNext() == null;
      CAstNode rcvr = walkNodes(receiver, context);
      final CAstNode result = Ast.makeNode(CAstNode.OBJECT_REF, rcvr, Ast.makeConstant("__proto__"));
      if (context.getCatchTarget() != null) {
        context.cfg().map(result, result);
        context.cfg().add(result, context.getCatchTarget(), JavaScriptTypes.TypeError);
      }
      return result;
    }
    case Token.SETPROP:
    case Token.SETELEM: {
      Node receiver = n.getFirstChild();
      Node elt = receiver.getNext();
      Node val = elt.getNext();
      CAstNode rcvr = walkNodes(receiver, context);
      return Ast.makeNode(CAstNode.ASSIGN, Ast.makeNode(CAstNode.OBJECT_REF, rcvr, walkNodes(elt, context)),
          walkNodes(val, context));
    }
    case Token.SET_REF: {
      Node child1 = n.getFirstChild();
      assert child1.getType() == Token.REF_SPECIAL;
      assert child1.getProp(Node.NAME_PROP).equals("__proto__");
      Node receiver = child1.getFirstChild();
      Node val = child1.getNext();
      CAstNode rcvr = walkNodes(receiver, context);
      return Ast.makeNode(CAstNode.ASSIGN, Ast.makeNode(CAstNode.OBJECT_REF, rcvr, Ast.makeConstant("__proto__")),
          walkNodes(val, context));
    }
    case Token.DELPROP: {
      Node receiver = n.getFirstChild();
      Node element = receiver.getNext();
      CAstNode rcvr = walkNodes(receiver, context);
      String baseVarName = context.getBaseVarNameIfRelevant(n);
      CAstNode elt = walkNodes(element, context);
      if (baseVarName != null) {
        return Ast.makeNode(CAstNode.BLOCK_EXPR, Ast.makeNode(CAstNode.ASSIGN, makeVarRef(baseVarName), rcvr),
            Ast.makeNode(CAstNode.ASSIGN, Ast.makeNode(CAstNode.OBJECT_REF, makeVarRef(baseVarName), elt), Ast.makeConstant(null)));
      } else {
        return Ast.makeNode(CAstNode.ASSIGN, Ast.makeNode(CAstNode.OBJECT_REF, rcvr, elt), Ast.makeConstant(null));
      }
    }
    case Token.TYPEOFNAME: {
      return Ast.makeNode(CAstNode.TYPE_OF, makeVarRef(n.getString()));
    }
    case Token.TYPEOF: {
      return Ast.makeNode(CAstNode.TYPE_OF, walkNodes(n.getFirstChild(), context));
    }
    case Token.SETPROP_OP:
    case Token.SETELEM_OP: {
      Node receiver = n.getFirstChild();
      Node elt = receiver.getNext();
      Node op = elt.getNext();
      CAstNode rcvr = walkNodes(receiver, context);
      return Ast.makeNode(CAstNode.ASSIGN_POST_OP, Ast.makeNode(CAstNode.OBJECT_REF, rcvr, walkNodes(elt, context)),
          walkNodes(op.getFirstChild().getNext(), context), translateOpcode(op.getType()));
    }
    case Token.THROW: {
      CAstNode catchNode = context.getCatchTarget();
      if (catchNode != null)
        context.cfg().add(n, context.getCatchTarget(), null);
      else
        context.cfg().add(n, CAstControlFlowMap.EXCEPTION_TO_EXIT, null);
      CAstNode throwAst = Ast.makeNode(CAstNode.THROW, walkNodes(n.getFirstChild(), context));
      context.cfg().map(n, throwAst);
      return throwAst;
    }
    case Token.EMPTY: {
      return Ast.makeConstant(null);
    }
    case Token.INSTANCEOF: {
      Node value = n.getFirstChild();
      Node type = value.getNext();
      return Ast.makeNode(CAstNode.INSTANCEOF, walkNodes(value, context), walkNodes(type, context));
    }
    case Token.IN: {
      Node value = n.getFirstChild();
      Node property = value.getNext();
      return Ast.makeNode(CAstNode.IS_DEFINED_EXPR, walkNodes(value, context), walkNodes(property, context));
    }
    default: {
      System.err.println("while converting: " + context.top().toStringTree(context.top()) + "\nlooking at unhandled:\n "
          + n.toStringTree(context.top()) + "\n(of type " + NT + ") (of class " + n.getClass() + ")" + " at " + n.getLineno());
      Assertions.UNREACHABLE();
      return null;
    }
    }
  }

  private CAstNode walkNodesInternal(final Node n, WalkContext context) {
    final int NT = n.getType();
    switch (NT) {
    case Token.FUNCTION: {
      int fnIndex = n.getExistingIntProp(Node.FUNCTION_PROP);
      FunctionNode fn = context.top().getFunctionNode(fnIndex);
      CAstEntity fne = walkEntity(fn, context);
      if (context.expressionContext()) {
        CAstNode fun = Ast.makeNode(CAstNode.FUNCTION_EXPR, Ast.makeConstant(fne));
        context.addScopedEntity(fun, fne);
        return fun;
      } else {
        context.addNameDecl(Ast.makeNode(CAstNode.FUNCTION_STMT, Ast.makeConstant(fne)));
        context.addScopedEntity(null, fne);
        return Ast.makeNode(CAstNode.EMPTY);
      }
    }
    case Token.CATCH_SCOPE: {
      Node catchVarNode = n.getFirstChild();
      String catchVarName = catchVarNode.getString();
      assert catchVarName != null;
      context.setCatchVar(catchVarName);
      return Ast.makeNode(CAstNode.EMPTY);
    }
    case Token.LOCAL_BLOCK: {
      return Ast.makeNode(CAstNode.BLOCK_EXPR, gatherChildren(n, context));
    }
    case Token.TRY: {
      Node catchNode = ((Node.Jump) n).target;
      Node finallyNode = ((Node.Jump) n).getFinally();
      ArrayList<Node> tryList = new ArrayList<Node>();
      ArrayList<Node> catchList = new ArrayList<Node>();
      ArrayList<Node> finallyList = new ArrayList<Node>();
      ArrayList<Node> current = tryList;
      Node c;
      for (c = n.getFirstChild(); c.getNext() != null; c = c.getNext()) {
        if (c == catchNode) {
          current = catchList;
        } else if (c == finallyNode) {
          current = finallyList;
        }
        if (c.getType() == Token.GOTO &&
            (c.getNext() == catchNode || c.getNext() == finallyNode)) {
          continue;
        }
        current.add(c);
      }
      CAstNode finallyBlock = null;
      if (finallyNode != null) {
        int i = 0;
        CAstNode[] finallyAsts = new CAstNode[finallyList.size()];
        for (Iterator<Node> fns = finallyList.iterator(); fns.hasNext();) {
          finallyAsts[i++] = walkNodes(fns.next(), context);
        }
        finallyBlock = Ast.makeNode(CAstNode.BLOCK_STMT, finallyAsts);
      }
      if (catchNode != null) {
        int i = 0;
        WalkContext catchChild = new CatchBlockContext(context);
        CAstNode[] catchAsts = new CAstNode[catchList.size()];
        for (Iterator<Node> cns = catchList.iterator(); cns.hasNext();) {
          catchAsts[i++] = walkNodes(cns.next(), catchChild);
        }
        CAstNode catchBlock = Ast.makeNode(CAstNode.CATCH, Ast.makeConstant(catchChild.getCatchVar()),
            Ast.makeNode(CAstNode.BLOCK_STMT, catchAsts));
        context.cfg().map(catchBlock, catchBlock);
        i = 0;
        WalkContext tryChild = new TryBlockContext(context, catchBlock);
        CAstNode[] tryAsts = new CAstNode[tryList.size()];
        for (Iterator<Node> tns = tryList.iterator(); tns.hasNext();) {
          tryAsts[i++] = walkNodes(tns.next(), tryChild);
        }
        CAstNode tryBlock = Ast.makeNode(CAstNode.BLOCK_STMT, tryAsts);
        if (finallyBlock != null) {
          return Ast.makeNode(CAstNode.BLOCK_STMT,
              Ast.makeNode(CAstNode.UNWIND, Ast.makeNode(CAstNode.TRY, tryBlock, catchBlock), finallyBlock), walkNodes(c, context));
        } else {
          return Ast.makeNode(CAstNode.BLOCK_STMT, Ast.makeNode(CAstNode.TRY, tryBlock, catchBlock), walkNodes(c, context));
        }
      } else {
        int i = 0;
        CAstNode[] tryAsts = new CAstNode[tryList.size()];
        for (Iterator<Node> tns = tryList.iterator(); tns.hasNext();) {
          tryAsts[i++] = walkNodes(tns.next(), context);
        }
        CAstNode tryBlock = Ast.makeNode(CAstNode.BLOCK_STMT, tryAsts);
        return Ast.makeNode(
            CAstNode.BLOCK_STMT,
            Ast.makeNode(CAstNode.UNWIND, Ast.makeNode(CAstNode.BLOCK_STMT, tryBlock),
                Ast.makeNode(CAstNode.BLOCK_STMT, finallyBlock)), walkNodes(c, context));
      }
    }
    case Token.JSR: {
      return Ast.makeNode(CAstNode.EMPTY);
    }
    case Token.COMMA: {
      int count = countSiblingsStartingFrom(n.getFirstChild());
      CAstNode[] cs = new CAstNode[count];
      int i = 0;
      for (Node c = n.getFirstChild(); c != null; i++, c = c.getNext()) {
        if (c.getNext() == null) {
          context.updateBase(n, c);
        }
        cs[i] = walkNodes(c, context);
      }
      return Ast.makeNode(CAstNode.BLOCK_EXPR, cs);
    }
    case Token.ENTERWITH:
    case Token.LEAVEWITH: {
      return Ast.makeNode(CAstNode.EMPTY);
    }
    case Token.LOOP: {
      LoopContext child = new LoopContext(context);
      CAstNode[] nodes = gatherChildren(n, child);
      if (child.forInInitExpr != null) {
        String nm = child.forInVar;
        return Ast.makeNode(CAstNode.BLOCK_STMT, Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(nm, true)),
            walkNodes(child.forInInitExpr, context)), nodes);
      } else {
        return Ast.makeNode(CAstNode.BLOCK_STMT, nodes);
      }
    }
    case Token.WITH:
    case Token.FINALLY:
    case Token.BLOCK:
    case Token.LABEL: {
      Node c1 = n.getFirstChild();
      if (c1 != null && c1.getType() == Token.SWITCH) {
        Node switchValue = c1.getFirstChild();
        CAstNode defaultLabel = Ast.makeNode(CAstNode.LABEL_STMT, Ast.makeNode(CAstNode.EMPTY));
        context.cfg().map(defaultLabel, defaultLabel);
        List<CAstNode> labelCasts = new ArrayList<CAstNode>();
        for (Node kase = switchValue.getNext(); kase != null; kase = kase.getNext()) {
          assert kase.getType() == Token.CASE;
          Node caseLbl = kase.getFirstChild();
          Node target = ((Node.Jump) kase).target;
          CAstNode labelCast = walkNodes(caseLbl, context);
          labelCasts.add(labelCast);
          context.cfg().add(c1, target, labelCast);
        }
        CAstNode[] children = new CAstNode[labelCasts.size() + 1];
        int i = 0;
        children[i++] = Ast.makeNode(CAstNode.BLOCK_STMT, defaultLabel, gatherChildren(n, context, 1));
        for (CAstNode labelCast : labelCasts) {
          children[i++] = labelCast;
        }
        context.cfg().add(c1, defaultLabel, CAstControlFlowMap.SWITCH_DEFAULT);
        CAstNode switchAst = Ast.makeNode(CAstNode.SWITCH, walkNodes(switchValue, context), children);
        noteSourcePosition(context, switchAst, c1);
        context.cfg().map(c1, switchAst);
        return switchAst;
      }
      else {
        return Ast.makeNode(CAstNode.BLOCK_STMT, gatherChildren(n, context));
      }
    }
    case Token.EXPR_VOID:
    case Token.EXPR_RESULT: {
      WalkContext child = new ExpressionContext(context);
      Node expr = n.getFirstChild();
      if (NT == Token.EXPR_RESULT) {
        child.updateBase(n, expr);
      }
      return walkNodes(expr, child);
    }
    case Token.POS: {
      return Ast.makeNode(CAstNode.UNARY_EXPR, translateOpcode(Token.ADD), walkNodes(n.getFirstChild(), context));
    }
    case Token.CALL: {
      if (!isPrimitiveCall(context, n)) {
        CAstNode base = makeVarRef("$$ base");
        Node callee = n.getFirstChild();
        WalkContext child = new BaseCollectingContext(context, callee, "$$ base");
        CAstNode fun = walkNodes(callee, child);
        Node firstParamInParens = callee.getNext();
        if (child.foundBase(callee))
          return Ast.makeNode(
              CAstNode.LOCAL_SCOPE,
              Ast.makeNode(CAstNode.BLOCK_EXPR,
                  Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl("$$ base")), Ast.makeConstant(null)),
                  makeCall(fun, base, firstParamInParens, context)));
        else {
          return makeCall(fun, makeVarRef(JSSSAPropagationCallGraphBuilder.GLOBAL_OBJ_VAR_NAME), firstParamInParens, context);
        }
      } else {
        return Ast.makeNode(CAstNode.PRIMITIVE, gatherChildren(n, context, 1));
      }
    }
    case Token.BINDNAME:
    case Token.NAME: {
      return readName(context, n.getString());
    }
    case Token.THIS: {
      return makeVarRef("this");
    }
    case Token.THISFN: {
      return makeVarRef(((FunctionNode) context.top()).getFunctionName());
    }
    case Token.STRING: {
      return Ast.makeConstant(n.getString());
    }
    case Token.NUMBER: {
      return Ast.makeConstant(n.getDouble());
    }
    case Token.FALSE: {
      return Ast.makeConstant(false);
    }
    case Token.TRUE: {
      return Ast.makeConstant(true);
    }
    case Token.NULL:
    case Token.VOID: {
      return Ast.makeConstant(null);
    }
    case Token.ADD:
    case Token.DIV:
    case Token.LSH:
    case Token.MOD:
    case Token.MUL:
    case Token.RSH:
    case Token.SUB:
    case Token.URSH:
    case Token.BITAND:
    case Token.BITOR:
    case Token.BITXOR:
    case Token.EQ:
    case Token.SHEQ:
    case Token.GE:
    case Token.GT:
    case Token.LE:
    case Token.LT:
    case Token.SHNE:
    case Token.NE: {
      Node l = n.getFirstChild();
      Node r = l.getNext();
      return Ast.makeNode(CAstNode.BINARY_EXPR, translateOpcode(NT), walkNodes(l, context), walkNodes(r, context));
    }
    case Token.NEG: {
      return Ast.makeNode(CAstNode.UNARY_EXPR, translateOpcode(Token.SUB), walkNodes(n.getFirstChild(), context));
    }
    case Token.BITNOT:
    case Token.NOT: {
      return Ast.makeNode(CAstNode.UNARY_EXPR, translateOpcode(NT), walkNodes(n.getFirstChild(), context));
    }
    case Token.VAR:
    case Token.CONST: {
      List<CAstNode> result = new ArrayList<CAstNode>();
      Node nm = n.getFirstChild();
      while (nm != null) {
        context.addNameDecl(Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(nm.getString())),
            readName(context, "$$undefined")));
        if (nm.getFirstChild() != null) {
          WalkContext child = new ExpressionContext(context);
          result.add(Ast.makeNode(CAstNode.ASSIGN, makeVarRef(nm.getString()),
              walkNodes(nm.getFirstChild(), child)));
        }
        nm = nm.getNext();
      }
      if (result.size() > 0) {
        return Ast.makeNode(CAstNode.BLOCK_EXPR, result.toArray(new CAstNode[result.size()]));
      } else {
        return Ast.makeNode(CAstNode.EMPTY);
      }
    }
    case Token.REGEXP: {
      int regexIdx = n.getIntProp(Node.REGEXP_PROP, -1);
      assert regexIdx != -1 : "while converting: " + context.top().toStringTree(context.top()) + "\nlooking at bad regex:\n "
          + n.toStringTree(context.top());
      String flags = context.top().getRegexpFlags(regexIdx);
      Node flagsNode = Node.newString(flags);
      String str = context.top().getRegexpString(regexIdx);
      Node strNode = Node.newString(str);
      strNode.addChildToFront(flagsNode);
      return handleNew(context, "RegExp", strNode);
    }
    case Token.ENUM_INIT_KEYS: {
      context.createForInVar(n.getFirstChild());
      return Ast.makeNode(CAstNode.EMPTY);
    }
    case Token.ENUM_ID: {
      return Ast.makeNode(CAstNode.EACH_ELEMENT_GET, makeVarRef(context.getForInInitVar()));
    }
    case Token.ENUM_NEXT: {
      return Ast.makeNode(CAstNode.EACH_ELEMENT_HAS_NEXT, makeVarRef(context.getForInInitVar()));
    }
    case Token.RETURN: {
      Node val = n.getFirstChild();
      if (val != null) {
        WalkContext child = new ExpressionContext(context);
        return Ast.makeNode(CAstNode.RETURN, walkNodes(val, child));
      } else {
        return Ast.makeNode(CAstNode.RETURN);
      }
    }
    case Token.SETNAME: {
      Node nm = n.getFirstChild();
      return Ast.makeNode(CAstNode.ASSIGN, walkNodes(nm, context), walkNodes(nm.getNext(), context));
    }
    case Token.IFNE:
    case Token.IFEQ: {
      context.cfg().add(n, ((Node.Jump) n).target, Boolean.TRUE);
      WalkContext child = new ExpressionContext(context);
      CAstNode gotoAst = Ast.makeNode(CAstNode.IFGOTO, translateOpcode(NT), walkNodes(n.getFirstChild(), child),
          Ast.makeConstant(1));
      context.cfg().map(n, gotoAst);
      return gotoAst;
    }
    case Token.GOTO: {
      context.cfg().add(n, ((Node.Jump) n).target, null);
      CAstNode gotoAst = Ast.makeNode(CAstNode.GOTO, Ast.makeConstant(((Node.Jump) n).target.labelId()));
      context.cfg().map(n, gotoAst);
      return gotoAst;
    }
    case Token.BREAK: {
      context.cfg().add(n, ((Node.Jump) n).getJumpStatement().target, null);
      CAstNode gotoAst = Ast.makeNode(CAstNode.GOTO, Ast.makeConstant(((Node.Jump) n).getJumpStatement().target.labelId()));
      context.cfg().map(n, gotoAst);
      return gotoAst;
    }
    case Token.CONTINUE: {
      context.cfg().add(n, ((Node.Jump) n).getJumpStatement().getContinue(), null);
      CAstNode gotoAst = Ast.makeNode(CAstNode.GOTO, Ast.makeConstant(((Node.Jump) n).getJumpStatement().getContinue().labelId()));
      context.cfg().map(n, gotoAst);
      return gotoAst;
    }
    case Token.TARGET: {
      CAstNode result = Ast.makeNode(CAstNode.LABEL_STMT, Ast.makeConstant(n.labelId()), Ast.makeNode(CAstNode.EMPTY));
      context.cfg().map(n, result);
      return result;
    }
    case Token.OR: {
    	Node l = n.getFirstChild();
    	Node r = l.getNext();
    	CAstNode lhs = walkNodes(l, context);
    	String lhsTempName = "or___lhs";
    	return Ast.makeNode(
    			CAstNode.LOCAL_SCOPE,
    			Ast.makeNode(CAstNode.BLOCK_EXPR,
    					Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(lhsTempName)), lhs),
    					Ast.makeNode(CAstNode.IF_EXPR, makeVarRef(lhsTempName), makeVarRef(lhsTempName), walkNodes(r, context))));
    }
    case Token.AND: {
      Node l = n.getFirstChild();
      Node r = l.getNext();
      CAstNode lhs = walkNodes(l, context);
      String lhsTempName = "and___lhs";
      return Ast.makeNode(
    		  CAstNode.LOCAL_SCOPE,
    		  Ast.makeNode(CAstNode.BLOCK_EXPR,
    				  Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(lhsTempName)), lhs),
    				  Ast.makeNode(CAstNode.IF_EXPR, makeVarRef(lhsTempName), walkNodes(r, context), makeVarRef(lhsTempName))));
    }
    case Token.HOOK: {
      Node cond = n.getFirstChild();
      Node thenBranch = cond.getNext();
      Node elseBranch = thenBranch.getNext();
      return Ast.makeNode(CAstNode.IF_EXPR, walkNodes(cond, context), walkNodes(thenBranch, context),
          walkNodes(elseBranch, context));
    }
    case Token.INC:
    case Token.DEC: {
      int flags = n.getIntProp(Node.INCRDECR_PROP, -1);
      CAstNode op = ((flags & Node.DECR_FLAG) != 0) ? CAstOperator.OP_SUB : CAstOperator.OP_ADD;
      Node l = n.getFirstChild();
      CAstNode last = walkNodes(l, context);
      return Ast.makeNode((((flags & Node.POST_FLAG) != 0) ? CAstNode.ASSIGN_POST_OP : CAstNode.ASSIGN_PRE_OP), last,
          Ast.makeConstant(1), op);
    }
    case Token.NEW: {
      if (isPrimitiveCreation(context, n)) {
        return makeBuiltinNew(n.getFirstChild().getString());
      } else {
        Node receiver = n.getFirstChild();
        return handleNew(context, walkNodes(receiver, context), receiver.getNext());
      }
    }
    case Token.ARRAYLIT: {
      int count = 0;
      for (Node x = n.getFirstChild(); x != null; count++, x = x.getNext())
        ;
      int i = 0;
      CAstNode[] args = new CAstNode[2 * count + 1];
      args[i++] = (isPrologueScript(context)) ? makeBuiltinNew("Array") : handleNew(context, "Array", null);
      int[] skips = (int[]) n.getProp(Node.SKIP_INDEXES_PROP);
      int skip = 0;
      int idx = 0;
      Node elt = n.getFirstChild();
      while (elt != null) {
        if (skips != null && skip < skips.length && skips[skip] == idx) {
          skip++;
          idx++;
          continue;
        }
        args[i++] = Ast.makeConstant(idx++);
        args[i++] = walkNodes(elt, context);
        elt = elt.getNext();
      }
      return Ast.makeNode(CAstNode.OBJECT_LITERAL, args);
    }
    case Token.OBJECTLIT: {
      Object[] propertyList = (Object[]) n.getProp(Node.OBJECT_IDS_PROP);
      CAstNode[] args = new CAstNode[propertyList.length * 2 + 1];
      int i = 0;
      args[i++] = ((isPrologueScript(context)) ? makeBuiltinNew("Object") : handleNew(context, "Object", null));
      Node val = n.getFirstChild();
      int nameIdx = 0;
      for (; nameIdx < propertyList.length; nameIdx++, val = val.getNext()) {
        args[i++] = Ast.makeConstant(propertyList[nameIdx]);
        args[i++] = walkNodes(val, context);
      }
      return Ast.makeNode(CAstNode.OBJECT_LITERAL, args);
    }
    case Token.GETPROP:
    case Token.GETELEM: {
      Node receiver = n.getFirstChild();
      Node element = receiver.getNext();
      CAstNode rcvr = walkNodes(receiver, context);
      String baseVarName = context.getBaseVarNameIfRelevant(n);
      CAstNode elt = walkNodes(element, context);
      CAstNode get, result;
      if (baseVarName != null) {
        result = Ast.makeNode(CAstNode.BLOCK_EXPR, Ast.makeNode(CAstNode.ASSIGN, makeVarRef(baseVarName), rcvr),
            get = Ast.makeNode(CAstNode.OBJECT_REF, makeVarRef(baseVarName), elt));
      } else {
        result = get = Ast.makeNode(CAstNode.OBJECT_REF, rcvr, elt);
      }
      if (context.getCatchTarget() != null) {
        context.cfg().map(get, get);
        context.cfg().add(get, context.getCatchTarget(), JavaScriptTypes.TypeError);
      }
      return result;
    }
    case Token.GET_REF: {
      Node child1 = n.getFirstChild();
      assert child1.getType() == Token.REF_SPECIAL;
      assert child1.getProp(Node.NAME_PROP).equals("__proto__");
      Node receiver = child1.getFirstChild();     
      assert child1.getNext() == null;
      CAstNode rcvr = walkNodes(receiver, context);
      final CAstNode result = Ast.makeNode(CAstNode.OBJECT_REF, rcvr, Ast.makeConstant("__proto__"));
      if (context.getCatchTarget() != null) {
        context.cfg().map(result, result);
        context.cfg().add(result, context.getCatchTarget(), JavaScriptTypes.TypeError);
      }
      return result;
    }
    case Token.SETPROP:
    case Token.SETELEM: {
      Node receiver = n.getFirstChild();
      Node elt = receiver.getNext();
      Node val = elt.getNext();
      CAstNode rcvr = walkNodes(receiver, context);
      return Ast.makeNode(CAstNode.ASSIGN, Ast.makeNode(CAstNode.OBJECT_REF, rcvr, walkNodes(elt, context)),
          walkNodes(val, context));
    }
    case Token.SET_REF: {
      Node child1 = n.getFirstChild();
      assert child1.getType() == Token.REF_SPECIAL;
      assert child1.getProp(Node.NAME_PROP).equals("__proto__");
      Node receiver = child1.getFirstChild();
      Node val = child1.getNext();
      CAstNode rcvr = walkNodes(receiver, context);
      return Ast.makeNode(CAstNode.ASSIGN, Ast.makeNode(CAstNode.OBJECT_REF, rcvr, Ast.makeConstant("__proto__")),
          walkNodes(val, context));
    }
    case Token.DELPROP: {
      Node receiver = n.getFirstChild();
      Node element = receiver.getNext();
      CAstNode rcvr = walkNodes(receiver, context);
      String baseVarName = context.getBaseVarNameIfRelevant(n);
      CAstNode elt = walkNodes(element, context);
      if (baseVarName != null) {
        return Ast.makeNode(CAstNode.BLOCK_EXPR, Ast.makeNode(CAstNode.ASSIGN, makeVarRef(baseVarName), rcvr),
            Ast.makeNode(CAstNode.ASSIGN, Ast.makeNode(CAstNode.OBJECT_REF, makeVarRef(baseVarName), elt), Ast.makeConstant(null)));
      } else {
        return Ast.makeNode(CAstNode.ASSIGN, Ast.makeNode(CAstNode.OBJECT_REF, rcvr, elt), Ast.makeConstant(null));
      }
    }
    case Token.TYPEOFNAME: {
      return Ast.makeNode(CAstNode.TYPE_OF, makeVarRef(n.getString()));
    }
    case Token.TYPEOF: {
      return Ast.makeNode(CAstNode.TYPE_OF, walkNodes(n.getFirstChild(), context));
    }
    case Token.SETPROP_OP:
    case Token.SETELEM_OP: {
      Node receiver = n.getFirstChild();
      Node elt = receiver.getNext();
      Node op = elt.getNext();
      CAstNode rcvr = walkNodes(receiver, context);
      return Ast.makeNode(CAstNode.ASSIGN_POST_OP, Ast.makeNode(CAstNode.OBJECT_REF, rcvr, walkNodes(elt, context)),
          walkNodes(op.getFirstChild().getNext(), context), translateOpcode(op.getType()));
    }
    case Token.THROW: {
      CAstNode catchNode = context.getCatchTarget();
      if (catchNode != null)
        context.cfg().add(n, context.getCatchTarget(), null);
      else
        context.cfg().add(n, CAstControlFlowMap.EXCEPTION_TO_EXIT, null);
      CAstNode throwAst = Ast.makeNode(CAstNode.THROW, walkNodes(n.getFirstChild(), context));
      context.cfg().map(n, throwAst);
      return throwAst;
    }
    case Token.EMPTY: {
      return Ast.makeConstant(null);
    }
    case Token.INSTANCEOF: {
      Node value = n.getFirstChild();
      Node type = value.getNext();
      return Ast.makeNode(CAstNode.INSTANCEOF, walkNodes(value, context), walkNodes(type, context));
    }
    case Token.IN: {
      Node value = n.getFirstChild();
      Node property = value.getNext();
      return Ast.makeNode(CAstNode.IS_DEFINED_EXPR, walkNodes(property, context), walkNodes(value, context));
    }
    default: {
      System.err.println("while converting: " + context.top().toStringTree(context.top()) + "\nlooking at unhandled:\n "
          + n.toStringTree(context.top()) + "\n(of type " + NT + ") (of class " + n.getClass() + ")" + " at " + n.getLineno());
      Assertions.UNREACHABLE();
      return null;
    }
    }
  }
