private Action<?> walk(AmObject cobj) {

    Action<?> action = visitor.preorderVisit(cobj, context);
    if (action == null) action = Action.next();

    final AmObject walkObj = extractWalkObject(cobj, action);
    if (walkObj != null) {
      // walk children
      UpdatingIterator it = getChildrenOf(walkObj);
      context.getAmParents().addLast(walkObj);
      while (it.hasNext()) {
        AmObject child = it.next();
        Action<?> childAction = walk(child);
        processAction(childAction, it);
      }
      context.getAmParents().removeLast();
    }

    Action<?> postAction =
        visitor.postorderVisit(walkObj != null ? walkObj : cobj, context, action);
    if (postAction == null) postAction = Action.next;

    action = action.mergeWith(postAction);
    return action;
  }
 private void processAction(Action<?> action, UpdatingIterator parentIterator) {
   if (action.act == Action.Act.next || action.act == Action.Act.nextSibling) {
     // do nothing
   } else if (action.act == Action.Act.remove) {
     parentIterator.remove();
   } else if (action.act == Action.Act.replace) {
     AmObject replacement = action.getReplaceWith();
     parentIterator.set(replacement);
   } else throw new AssertionError(action);
 }
 @Nullable
 private AmObject extractWalkObject(AmObject amObject, Action<?> result) {
   if (result.act == Action.Act.next) {
     return amObject;
   } else if (result.act == Action.Act.nextSibling) {
     return null;
   } else if (result.act == Action.Act.remove) {
     return null;
   } else if (result.act == Action.Act.replace) {
     return result.getReplaceWith();
   } else throw new AssertionError(result);
 }
 public static <T extends AmObject> Action<T> replaceWith(T replacement) {
   Action<T> result = new Action<>(Act.replace);
   result.replaceWith = replacement;
   return result;
 }