Open Source Repository

Home /hibernate/hibernate-3.2.4.ga | Repository Home



org/hibernate/hql/ast/util/ASTPrinter.java
// $Id: ASTPrinter.java 7460 2005-07-12 20:27:29Z steveebersole $
package org.hibernate.hql.ast.util;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.hibernate.hql.ast.tree.DisplayableNode;
import org.hibernate.util.StringHelper;

import antlr.collections.AST;

/**
 * An 'ASCII art' AST printer for debugging ANTLR grammars.
 *
 @author Joshua Davis ([email protected])
 */
public class ASTPrinter {
  private Map tokenTypeNamesByTokenType;
  private Class tokenTypeConstants;
  private boolean showClassNames = true;

  /**
   * Constructs an org.hibernate.hql.antlr.ASTPrinter, given the class that contains the token type
   * constants (typically the '{grammar}TokenTypes' interface generated by
   * ANTLR).
   *
   @param tokenTypeConstants The class with token type constants in it.
   */
  public ASTPrinter(Class tokenTypeConstants) {
    this.tokenTypeConstants = tokenTypeConstants;
  }

  /**
   * Returns true if the node class names will be displayed.
   *
   @return true if the node class names will be displayed.
   */
  public boolean isShowClassNames() {
    return showClassNames;
  }

  /**
   * Enables or disables AST node class name display.
   *
   @param showClassNames true to enable class name display, false to disable
   */
  public void setShowClassNames(boolean showClassNames) {
    this.showClassNames = showClassNames;
  }

  /**
   * Prints the AST in 'ASCII art' tree form to the specified print stream.
   *
   @param ast The AST to print.
   @param out The print stream.
   */
  private void showAst(AST ast, PrintStream out) {
    showAstast, new PrintWriterout ) );
  }

  /**
   * Prints the AST in 'ASCII art' tree form to the specified print writer.
   *
   @param ast The AST to print.
   @param pw  The print writer.
   */
  public void showAst(AST ast, PrintWriter pw) {
    ArrayList parents = new ArrayList();
    showAstparents, pw, ast );
    pw.flush();
  }

  /**
   * Prints the AST in 'ASCII art' tree form into a string.
   *
   @param ast    The AST to display.
   @param header The header for the display.
   @return The AST in 'ASCII art' form, as a string.
   */
  public String showAsString(AST ast, String header) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    PrintStream ps = new PrintStreambaos );
    ps.printlnheader );
    showAstast, ps );
    ps.flush();
    return new Stringbaos.toByteArray() );
  }

  /**
   * Get a single token type name in the specified set of token type constants (interface).
   *
   @param tokenTypeConstants Token type constants interface (e.g. HqlSqlTokenTypes.class).
   @param type               The token type ( typically from ast.getType() ).
   @return The token type name, *or* the integer value if the name could not be found for some reason.
   */
  public static String getConstantName(Class tokenTypeConstants, int type) {
    String tokenTypeName = null;
    if tokenTypeConstants != null ) {
      Field[] fields = tokenTypeConstants.getFields();
      for int i = 0; i < fields.length; i++ ) {
        Field field = fields[i];
        tokenTypeName = getTokenTypeNamefield, type, true );
        if tokenTypeName != null ) {
          break;  // Stop if found.
        }
      // for
    // if type constants were provided

    // Use the integer value if no token type name was found
    if tokenTypeName == null ) {
      tokenTypeName = Integer.toStringtype );
    }

    return tokenTypeName;
  }

  private static String getTokenTypeName(Field field, int type, boolean checkType) {
    if Modifier.isStaticfield.getModifiers() ) ) {
      try {
        Object value = field.getnull );
        if !checkType ) {
          return field.getName();
        }
        else if value instanceof Integer ) {
          Integer integer = Integer value;
          if integer.intValue() == type ) {
            return field.getName();
          }
        // if value is an integer
      // try
      catch IllegalArgumentException ignore ) {
      }
      catch IllegalAccessException ignore ) {
      }
    // if the field is static
    return null;
  }

  /**
   * Returns the token type name for the given token type.
   *
   @param type The token type.
   @return String - The token type name from the token type constant class,
   *         or just the integer as a string if none exists.
   */
  private String getTokenTypeName(int type) {
    // If the class with the constants in it was not supplied, just
    // use the integer token type as the token type name.
    if tokenTypeConstants == null ) {
      return Integer.toStringtype );
    }

    // Otherwise, create a type id -> name map from the class if it
    // hasn't already been created.
    if tokenTypeNamesByTokenType == null ) {
      Field[] fields = tokenTypeConstants.getFields();
      tokenTypeNamesByTokenType = new HashMap();
      String tokenTypeName = null;
      for int i = 0; i < fields.length; i++ ) {
        Field field = fields[i];
        tokenTypeName = getTokenTypeNamefield, type, false );
        if tokenTypeName != null ) {
          try {
            tokenTypeNamesByTokenType.putfield.getnull ), field.getName() );
          }
          catch IllegalAccessException ignore ) {
          }
        }
      // for
    // if the map hasn't been created.

    return String tokenTypeNamesByTokenType.getnew Integertype ) );
  }

  private void showAst(ArrayList parents, PrintWriter pw, AST ast) {
    if ast == null ) {
      pw.println"AST is null!" );
      return;
    }

    for int i = 0; i < parents.size(); i++ ) {
      AST parent = AST parents.get);
      if parent.getNextSibling() == null ) {

        pw.print"   " );
      }
      else {
        pw.print" | " );
      }
    }

    if ast.getNextSibling() == null ) {
      pw.print" \\-" );
    }
    else {
      pw.print" +-" );
    }

    showNodepw, ast );

    ArrayList newParents = new ArrayListparents );
    newParents.addast );
    for AST child = ast.getFirstChild(); child != null; child = child.getNextSibling() ) {
      showAstnewParents, pw, child );
    }
    newParents.clear();
  }

  private void showNode(PrintWriter pw, AST ast) {
    String s = nodeToStringast, isShowClassNames() );
    pw.println);
  }

  public String nodeToString(AST ast, boolean showClassName) {
    if ast == null ) {
      return "{null}";
    }
    StringBuffer buf = new StringBuffer();
    buf.append"[" ).appendgetTokenTypeNameast.getType() ) ).append"] " );
    if showClassName ) {
      buf.appendStringHelper.unqualifyast.getClass().getName() ) ).append": " );
    }

        buf.append"'" );
        String text = ast.getText();
        appendEscapedMultibyteChars(text, buf);
        buf.append"'" );
    if ast instanceof DisplayableNode ) {
      DisplayableNode displayableNode = DisplayableNode ast;
      // Add a space before the display text.
      buf.append" " ).appenddisplayableNode.getDisplayText() );
    }
    String s = buf.toString();
    return s;
  }

    public static void appendEscapedMultibyteChars(String text, StringBuffer buf) {
        char[] chars = text.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            char aChar = chars[i];
            if (aChar > 256) {
                buf.append("\\u");
                buf.append(Integer.toHexString(aChar));
            }
            else
                buf.append(aChar);
        }
    }

    public static String escapeMultibyteChars(String text)
    {
        StringBuffer buf = new StringBuffer();
        appendEscapedMultibyteChars(text,buf);
        return buf.toString();
    }
}