docs: def visit_tree(node, previsit, postvisit):
    """
    Scans the tree under the node depth-first using an explicit stack. It avoids implicit recursion
    via the function call stack to avoid hitting 'maximum recursion depth exceeded' error.
  
    It calls ``previsit()`` and ``postvisit()`` as follows:
  
    * ``previsit(node, par_value)`` - should return ``(par_value, value)``
          ``par_value`` is as returned from ``previsit()`` of the parent.
  
    * ``postvisit(node, par_value, value)`` - should return ``value``
          ``par_value`` is as returned from ``previsit()`` of the parent, and ``value`` is as
          returned from ``previsit()`` of this node itself. The return ``value`` is ignored except
          the one for the root node, which is returned from the overall ``visit_tree()`` call.
  
    For the initial node, ``par_value`` is None. Either ``previsit`` and ``postvisit`` may be None.
    """
    if not previsit:
      previsit = lambda node, pvalue: (None, None)
    if not postvisit:
      postvisit = lambda node, pvalue, value: None
  
    iter_children = iter_children_func(node)
    done = set()
    ret = None
    stack = [(node, None, _PREVISIT)]
    while stack:
      current, par_value, value = stack.pop()
      if value is _PREVISIT:
        assert current not in done    # protect againt infinite loop in case of a bad tree.
        done.add(current)
  
        pvalue, post_value = previsit(current, par_value)
        stack.append((current, par_value, post_value))
  
        # Insert all children in reverse order (so that first child ends up on top of the stack).
        ins = len(stack)
        for n in iter_children(current):
          stack.insert(ins, (n, pvalue, _PREVISIT))
      else:
        ret = postvisit(current, par_value, value)
    return ret