/*
* xtc - The eXTensible Compiler
* Copyright (C) 2004 Robert Grimm
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package xtc.tree;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Iterator;
import xtc.Constants;
import xtc.util.Utilities;
/**
* A node pretty printing utility. This class provides a set of
* convenience methods to simplify the pretty printing of an abstract
* syntax tree.
*
* @author Robert Grimm
* @version $Revision: 1.2 $
*/
public class Printer extends Utility {
/** The length of the line separator. */
public static final int SEPARATOR_LENGTH =
System.getProperty("line.separator").length();
/** The print writer to print to. */
protected PrintWriter out;
/** The current indentation level. */
protected int indent = 0;
/**
* The number of characters printed by the most recently invoked
* method.
*/
protected int printed = 0;
// ========================================================================
/**
* Create a new printer with the specified print writer.
*
* @param out The print writer to output to.
*/
public Printer(PrintWriter out) {
this.out = out;
}
// ========================================================================
/**
* Increase the current indentation level.
*
* @return This printer.
*/
public Printer incr() {
indent += Constants.INDENTATION;
return this;
}
/**
* Decrease the current indentation level.
*
* @return This printer.
*/
public Printer decr() {
indent -= Constants.INDENTATION;
return this;
}
/**
* Indent.
*
* @return This printer.
*/
public Printer indent() {
for (int i=0; i<indent; i++) {
out.print(' ');
}
printed = indent;
return this;
}
/**
* Indent one tab stop less than the current indentation level.
*
* @return This printer.
*/
public Printer indentLess() {
int w = indent - Constants.INDENTATION;
if (0 > w) {
w = 0;
}
for (int i=0; i<w; i++) {
out.print(' ');
}
printed = w;
return this;
}
// ========================================================================
/**
* Print the specified character.
*
* @param c The character to print.
* @return This printer.
*/
public Printer p(char c) {
out.print(c);
printed = 1;
return this;
}
/**
* Print the specified integer.
*
* @param i The integer to print.
* @return This printer.
*/
public Printer p(int i) {
return p(Integer.toString(i));
}
/**
* Print the specified string.
*
* @param s The string to print.
* @return This printer.
*/
public Printer p(String s) {
out.print(s);
printed = s.length();
return this;
}
/**
* Print the specified character followed by a newline.
*
* @param c The character to print.
* @return This printer.
*/
public Printer pln(char c) {
out.println(c);
printed = 1 + SEPARATOR_LENGTH;
return this;
}
/**
* Print the specified integer followed by a newline.
*
* @param i The integer to print.
* @return This printer.
*/
public Printer pln(int i) {
return pln(Integer.toString(i));
}
/**
* Print the specified string followed by a newline.
*
* @param s The string to print.
* @return This printer.
*/
public Printer pln(String s) {
out.println(s);
printed = s.length() + SEPARATOR_LENGTH;
return this;
}
/**
* Print a newline.
*
* @return This printer.
*/
public Printer pln() {
out.println();
printed = SEPARATOR_LENGTH;
return this;
}
// ========================================================================
/**
* Print whitespace to align the output. This method prints
* whitespace to cover the difference between the specified number
* of printed characters and the specified alignment. If the number
* of characters already printed is equal or larger than the number
* of characters to align the output at, a single space character is
* printed.
*
* @param printed The number of characters already printed.
* @param alignment The number of characters to align at.
*/
public Printer align(int printed, int alignment) {
int toPrint = alignment - printed;
if (0 >= toPrint) toPrint = 1;
for (int i=0; i<toPrint; i++) {
out.write(' ');
}
printed = toPrint;
return this;
}
/**
* Print whitespace to align the output. This method prints
* whitespace to cover the difference between the number of
* characters printed by the last invocation to any of this
* printer's methods (besides {@link #incr()} and {@link #decr()})
* and the specified alignment. If the number of characters already
* printed is equal or larger than the number of characters to align
* the output at, a single space character is printed.
*
* @param alignment The number of characters to align at.
*/
public Printer align(int alignment) {
return align(printed, alignment);
}
// ========================================================================
/**
* Print the specified character with the specified escape sequences.
*
* @see Utilities
*
* @param c The character to print.
* @param flags The escape flags.
* @return This printer.
*/
public Printer escape(char c, int flags) {
return p(Utilities.escape(c, flags));
}
/**
* Print the specified string with the specified escape sequences.
*
* @see Utilities
*
* @param s The string to print.
* @param flags The escape flags.
* @return This printer.
*/
public Printer escape(String s, int flags) {
return p(Utilities.escape(s, flags));
}
// ========================================================================
/**
* Print an indented separation comment.
*
* @return This printer.
*/
public Printer sep() {
indent().p("// ");
int n = 80 - indent - 3 - 3;
for (int i=0; i<n; i++) {
out.print('=');
}
out.println();
printed = 77 + SEPARATOR_LENGTH;
return this;
}
// ========================================================================
/**
* Print the specified node. If the specified node is
* <code>null</code>, nothing is printed.
*
* @param node The node to print.
* @return This printer.
*/
public Printer p(Node node) {
if (null != node) node.accept(visitor());
return this;
}
/**
* Print the specified collection of nodes. Nodes are printed in the
* order of the collection's iterator. If the specified collection
* is <code>null</code>, nothing is printed.
*
* @param coll The collection of nodes to print.
* @return This printer.
*/
public Printer p(Collection coll) {
if (null != coll) {
Iterator iter = coll.iterator();
while (iter.hasNext()) {
p((Node)iter.next());
}
}
return this;
}
/**
* Print the specified collection of nodes. Nodes are printed in the
* order of the collection's iterator. If the specified collection
* is <code>null</code> or empty, nothing is printed.
*
* @param coll The collection of nodes to print.
* @param before The string to print before the nodes.
* @param sep The string to print between nodes.
*/
public Printer p(Collection coll, String before, String sep) {
if (null != coll) {
boolean first = true;
Iterator iter = coll.iterator();
while (iter.hasNext()) {
if (first) {
p(before);
first = false;
} else {
p(sep);
}
p((Node)iter.next());
}
}
return this;
}
// ========================================================================
/**
* Print the original location for the specified node. Note that
* this method prints nothing.
*
* @param node The node.
* @return This printer.
*/
public Printer loc(Node node) {
return this;
}
}