private ISourceLocation getLocation(Object node) {
    if (node instanceof ITree) {
      return TreeAdapter.getLocation((ITree) node);
    }

    if (node instanceof INode) {
      INode n = (INode) node;
      IValue ann = n.asAnnotatable().getAnnotation("loc");
      if (ann != null) {
        return (ISourceLocation) ann;
      }
    }

    if (node instanceof AbstractAST) {
      return ((AbstractAST) node).getLocation();
    }

    if (node instanceof ModelTreeNode) {
      return getLocation(((ModelTreeNode) node).getASTNode());
    }

    if (node instanceof Group<?>) {
      Group<?> group = (Group<?>) node;
      Iterator<?> i = group.iterator();
      if (i.hasNext()) {
        return getLocation(i.next());
      }
      return group.getLocation();
    }

    return null;
  }
 private boolean checkIndent(INode o) {
   if (indent && o.arity() > 1) {
     for (IValue x : o) {
       Type type = x.getType();
       if (indented(type)) {
         return true;
       }
     }
   }
   return false;
 }
    public IValue visitNode(INode o) throws IOException {
      printString(o.getName());

      boolean indent = checkIndent(o);

      append('(');
      tab();
      indent(indent);
      Iterator<IValue> it = o.iterator();
      int k = 0;
      while (it.hasNext()) {
        it.next().accept(this);
        if (it.hasNext()) {
          append(',');
          indent(indent);
        }
        k++;
      }

      if (o.mayHaveKeywordParameters()) {
        IWithKeywordParameters<? extends INode> wkw = o.asWithKeywordParameters();
        if (wkw.hasParameters()) {
          if (k > 0) {
            append(',');
          }

          Iterator<Entry<String, IValue>> kwIt = wkw.getParameters().entrySet().iterator();
          while (kwIt.hasNext()) {
            Entry<String, IValue> e = kwIt.next();
            indent();
            append(e.getKey());
            append('=');
            e.getValue().accept(this);

            if (kwIt.hasNext()) {
              append(',');
            }
          }
        }
      }
      append(')');
      untab();
      if (o.isAnnotatable() && o.asAnnotatable().hasAnnotations()) {
        append('[');
        tab();
        indent();
        int i = 0;
        Map<String, IValue> annotations = o.asAnnotatable().getAnnotations();
        for (Entry<String, IValue> entry : annotations.entrySet()) {
          append("@" + entry.getKey() + "=");
          entry.getValue().accept(this);

          if (++i < annotations.size()) {
            append(",");
            indent();
          }
        }
        untab();
        indent();
        append(']');
      }

      return o;
    }