    001    /* Copyright 2000, 2001, Compaq Computer Corporation */
    002
    003    package javafe.ast;
    004
    005    import java.io.OutputStream;
    006    import java.io.ByteArrayOutputStream;
    007    import java.io.IOException;
    008
    009    import javafe.util.Assert;
    010    import javafe.util.Location;
    011
    012    // FIXME - should this write Strings instead of bytes?
    013    public abstract class PrettyPrint {
    014
    015      /*****************************************************************************
    016       * * Creation & delegation support: * *
    017       ****************************************************************************/
    018
    019      /**
    020       * The only instance front-end code should use to pretty print information.
    021       * <p>
    022       *
    023       * Will be some subclass of PrettyPrint; defaults to an instance of
    024       * StandardPrettyPrint. Extensions should replace with an instance that
    025       * understands how to pretty print the extensions.
    026       */
    027      public static/*@ non_null */PrettyPrint inst = new StandardPrettyPrint();
    028
    029      /**
    030       * When an instance of PrettyPrint wishes to call itself recursively, it does
    031       * not do so by using this, but rather by using this explicit self instance
    032       * variable.
    033       * <p>
    034       *
    035       * This allows instances of PrettyPrint to be extended at runtime (rather than
    036       * by compile-time static subclassing) using the DelegatingPrettyPrint class.
    037       * See javafe.tc.TypePrint for an example of how this may be done.
    038       */
    039      public /*@ non_null */ PrettyPrint self;
    040
    041      /**
    042       * Create a normal instance of PrettyPrint that does not have a runtime
    043       * extension.
    044       */
    045      protected PrettyPrint() {
    046        this.self = this;
    047      }
    048
    049      /**
    050       * Create an instance of PrettyPrint that has a runtime extension.
    051       * <p>
    052       *
    053       * Self should be an instance of DelegatingPrettyPrint that eventually calls
    054       * us after some amount of filtering.
    055       */
    056      protected PrettyPrint(/*@ non_null */ PrettyPrint self) {
    057        this.self = self;
    058      }
    059
    060      /*****************************************************************************
    061       * * Variables controling printing: * *
    062       ****************************************************************************/
    063
    064      public static int INDENT = 3;
    065
    066      /**
    067       * Should we display code that is inferred?
    068       * <p>
    069       *
    070       * E.g., the inferred "this.", superclass constructor calls, etc.
    071       */
    072      public static boolean displayInferred = false;
    073
    074      /*****************************************************************************
    075       * * Procedures to print various things: * *
    076       ****************************************************************************/
    077
    078      /**
    079       * Print a compilation onto to a stream. Works best when <code>o</code> is
    080       * positioned at the start of a new line.
    081       */
    082
    083      public abstract void print(/*@ non_null */ OutputStream o, CompilationUnit cu);
    084
    085      /**
    086       * Print a type declaration onto to a stream.
    087       * <p>
    088       *
    089       * Ends with a newline.
    090       * <p>
    091       */
    092      public void print(/*@ non_null */ OutputStream o, int ind, TypeDecl d) {
    093        printnoln(o, ind, d);
    094        writeln(o);
    095      }
    096
    097      /**
    098       * Print a type declaration onto to a stream, without a final newline.
    099       * <p>
    100       */
    101      public abstract void printnoln(/*@ non_null */ OutputStream o, int ind, TypeDecl d);
    102
    103      /**
    104       * Print a statement. Assumes that <code>s</code> should be printed starting
    105       * at the current position of <code>o</code>. It does <em>not</em> print
    106       * a new-line at the end of the statement. However, if the statement needs to
    107       * span multiple lines (for example, because it has embedded statements), then
    108       * these lines are indented by <code>ind</code> spaces.
    109       */
    110
    111      public abstract void print(/*@ non_null */ OutputStream o, int ind, Stmt s);
    112
    113      /**
    114       * Print a member or static initializer of a type declaration. Assumes that
    115       * <code>s</code> should be printed starting at the current position of
    116       * <code>o</code>. If the declaration needs to span multiple lines (for
    117       * example, to print the statements in the body of a method), then these lines
    118       * are indented by <code>ind</code> spaces. It should leave <code>o</code>
    119       * at the start of a new-line.
    120       */
    121
    122      //@ requires o != null && classId != null;
    123      //@ requires d != null ==> d.hasParent;
    124      public abstract void print(/*@ non_null */ OutputStream o, int ind, TypeDeclElem d,
    125          Identifier classId, boolean showBody);
    126
    127      public abstract void print(/*@ non_null */ OutputStream o, TypeNameVec tns);
    128
    129      public abstract void print(/*@ non_null */ OutputStream o, int ind, FormalParaDeclVec fps);
    130
    131      public abstract void print(/*@ non_null */ OutputStream o, int ind, ExprVec es);
    132
    133      public abstract void print(/*@ non_null */ OutputStream o, GenericVarDecl d);
    134
    135      public abstract void print(/*@ non_null */ OutputStream o, int ind, LocalVarDecl d,
    136          boolean showBody);
    137
    138      public abstract void print(/*@ non_null */ OutputStream o, int ind, FieldDecl d,
    139          boolean showBody);
    140
    141      public abstract void print(/*@ non_null */ OutputStream o, Type t);
    142
    143      public abstract void print(/*@ non_null */ OutputStream o, Name n);
    144
    145      public abstract void print(/*@ non_null */ OutputStream o, int ind, ObjectDesignator od);
    146
    147      public abstract void print(/*@ non_null */ OutputStream o, int ind, VarInit e);
    148
    149      /**
    150       * Print a lexical pragma. Assumes <code>o</code> is at the start of the
    151       * line; should leave <code>o</code> at the start of a new line.
    152       */
    153
    154      //@ requires o != null && lp != null;
    155      public abstract void print(/*@ non_null */ OutputStream o, LexicalPragma lp);
    156
    157      //@ requires o != null && tp != null;
    158      public abstract void print(/*@ non_null */ OutputStream o, int ind, TypeDeclElemPragma tp);
    159
    160      /**
    161       * TODO Fill in class description
    162       *
    163       * @author David R. Cok
    164       */
    165
    166      /**
    167       * Print a member or static initializer of a type declaration. Assumes that
    168       * <code>s</code> should be printed starting at the current position of
    169       * <code>o</code>. If the declaration needs to span multiple lines (for
    170       * example, to print the statements in the body of a method), then these lines
    171       * are indented by <code>ind</code> spaces. It should leave <code>o</code>
    172       * at the start of a new-line.
    173       */
    174
    175      //@ requires o != null && mp != null;
    176      public abstract void print(/*@ non_null */ OutputStream o, int ind, ModifierPragma mp);
    177
    178      //@ requires o != null && sp != null;
    179      public abstract void print(/*@ non_null */ OutputStream o, int ind, StmtPragma sp);
    180
    181      //@ requires o != null && tp != null;
    182      public abstract void print(/*@ non_null */ OutputStream o, int ind, TypeModifierPragma tp);
    183
    184      /**
    185       * Writes an Object (a type of ASTNode) to the given PrintStream, followed by
    186       * an end-of-line.
    187       *
    188       * @param out The PrintStream to write to
    189       * @param e The expression to write
    190       */
    191      public void println(/*@ non_null */ java.io.PrintStream out, Object e) {
    192        out.println(e.toString());
    193      }
    194
    195      /**
    196       * Writes an Expr (a type of ASTNode) to the given PrintStream, followed by an
    197       * end-of-line.
    198       *
    199       * @param out The PrintStream to write to
    200       * @param e The expression to write
    201       */
    202      public void println(/*@ non_null */ java.io.PrintStream out, Expr e) {
    203        print(out, 0, e);
    204        out.println("");
    205      }
    206
    207      /**
    208       * Writes an ObjectDesignator (a type of ASTNode) to the given PrintStream,
    209       * followed by an end-of-line.
    210       *
    211       * @param out The PrintStream to write to
    212       * @param e The expression to write
    213       */
    214      public void println(/*@ non_null */ java.io.PrintStream out, ObjectDesignator e) {
    215        print(out, 0, e);
    216        out.println("");
    217      }
    218
    219      //// toString methods
    220
    221      /**
    222       * Returns a canonical text representation for literal values. Requires
    223       * <code>tag</code> is one of constants on the left of this table:
    224       *
    225       * <center><code><table>
    226       <tr> <td> TagConstants.BOOLEANLIT </td> <td> Boolean </td> </tr>
    227       <tr> <td> TagConstants.CHARLIT </td>   <td> Integer </td> </tr>
    228       <tr> <td> TagConstants.DOUBLELIT </td> <td> Double </td> </tr>
    229       <tr> <td> TagConstants.FLOATLIT </td>  <td> Float </td> </tr>
    230       <tr> <td> TagConstants.INTLIT </td>    <td> Integer </td> </tr>
    231       <tr> <td> TagConstants.LONGLIT </td>   <td> Long </td> </tr>
    232       <tr> <td> TagConstants.STRINGLIT </td> <td> String </td> </tr>
    233       </center></code> </table>
    234       *
    235       * and that <code>val</code> is an instance of the corresponding type on the
    236       * right.
    237       */
    238
    239      /*
    240       * @ requires ( (tag==TagConstants.BOOLEANLIT) || (tag==TagConstants.INTLIT) ||
    241       * (tag==TagConstants.LONGLIT) || (tag==TagConstants.FLOATLIT) ||
    242       * (tag==TagConstants.DOUBLELIT) || (tag==TagConstants.STRINGLIT) ||
    243       * (tag==TagConstants.CHARLIT) );
    244       */
    245      /*
    246       * @ requires ( ((tag==TagConstants.BOOLEANLIT) ==> (val instanceof Boolean)) &&
    247       * ((tag==TagConstants.INTLIT) ==> (val instanceof Integer)) &&
    248       * ((tag==TagConstants.LONGLIT) ==> (val instanceof Long)) &&
    249       * ((tag==TagConstants.FLOATLIT) ==> (val instanceof Float)) &&
    250       * ((tag==TagConstants.DOUBLELIT) ==> (val instanceof Double)) &&
    251       * ((tag==TagConstants.STRINGLIT) ==> (val instanceof String)) &&
    252       * ((tag==TagConstants.CHARLIT) ==> (val instanceof Integer)) );
    253       */
    254      //@ ensures \result != null;
    255      public static String toCanonicalString(int tag, Object val) {
    256        if (tag == TagConstants.BOOLEANLIT) return val.toString();
    257        if (tag == TagConstants.DOUBLELIT) return val.toString() + "D";
    258        if (tag == TagConstants.FLOATLIT) return val.toString() + "F";
    259
    260        if (tag == TagConstants.INTLIT) {
    261          //@ assert val instanceof Integer;
    262          int v = ((Integer)val).intValue();
    263          if (v == Integer.MIN_VALUE) return "0x80000000";
    264          else if (v < 0) return "0x" + Integer.toHexString(v);
    265          else return Integer.toString(v);
    266        }
    267
    268        if (tag == TagConstants.LONGLIT) {
    269          long v = ((Long)val).longValue();
    270          if (v == Long.MIN_VALUE) return "0x8000000000000000L";
    271          else if (v < 0) return "0x" + Long.toHexString(v) + "L";
    272          else return Long.toString(v) + "L";
    273        }
    274
    275        if (tag == TagConstants.CHARLIT || tag == TagConstants.STRINGLIT) {
    276          char quote;
    277          if (tag == TagConstants.CHARLIT) {
    278            quote = '\'';
    279            val = new Character((char)((Integer)val).intValue());
    280          } else quote = '\"';
    281          String s = val.toString();
    282          StringBuffer result = new StringBuffer(s.length() + 2);
    283          result.append(quote);
    284          for (int i = 0, len = s.length(); i < len; i++) {
    285            char c = s.charAt(i);
    286            switch (c) {
    287              case '\b':
    288                result.append("\\b");
    289                break;
    290              case '\t':
    291                result.append("\\t");
    292                break;
    293              case '\n':
    294                result.append("\\n");
    295                break;
    296              case '\f':
    297                result.append("\\f");
    298                break;
    299              case '\r':
    300                result.append("\\r");
    301                break;
    302              case '\"':
    303                result.append("\\\"");
    304                break;
    305              case '\'':
    306                result.append("\\'");
    307                break;
    308              case '\\':
    309                result.append("\\\\");
    310                break;
    311              default:
    312                if (32 <= c && c < 128) result.append(c);
    313                else {
    314                  result.append("\\u");
    315                  for (int j = 12; j >= 0; j -= 4)
    316                    result.append(Character.forDigit((c >> j) & 0xf, 16));
    317                }
    318            }
    319          }
    320          result.append(quote);
    321          return result.toString();
    322        }
    323
    324        Assert.precondition(false);
    325        return null; // Dummy
    326      }
    327
    328      //@ ensures \result != null;
    329      public String toString(int tag) {
    330        // Best version available in the front end:
    331        return javafe.tc.TagConstants.toString(tag);
    332      }
    333
    334      //@ ensures \result != null;
    335      public final String toString(TypeNameVec tns) {
    336        ByteArrayOutputStream result = new ByteArrayOutputStream(20);
    337        print(result, tns);
    338        return result.toString();
    339      }
    340
    341      //@ ensures \result != null;
    342      public final String toString(FormalParaDeclVec fps) {
    343        ByteArrayOutputStream result = new ByteArrayOutputStream(20);
    344        print(result, 0, fps);
    345        return result.toString();
    346      }
    347
    348      //@ ensures \result != null;
    349      public final String toString(ExprVec es) {
    350        ByteArrayOutputStream result = new ByteArrayOutputStream(20);
    351        print(result, 0, es);
    352        return result.toString();
    353      }
    354
    355      //@ ensures \result != null;
    356      public final String toString(GenericVarDecl d) {
    357        ByteArrayOutputStream result = new ByteArrayOutputStream(20);
    358        print(result, d);
    359        return result.toString();
    360      }
    361
    362      //@ ensures \result != null;
    363      public final String toString(LocalVarDecl d, boolean showBody) {
    364        ByteArrayOutputStream result = new ByteArrayOutputStream(20);
    365        print(result, 0, d, showBody);
    366        return result.toString();
    367      }
    368
    369      //@ ensures \result != null;
    370      public final String toString(FieldDecl d, boolean showBody) {
    371        ByteArrayOutputStream result = new ByteArrayOutputStream(20);
    372        print(result, 0, d, showBody);
    373        return result.toString();
    374      }
    375
    376      //@ ensures \result != null;
    377      public final String toString(Type t) {
    378        ByteArrayOutputStream result = new ByteArrayOutputStream(20);
    379        print(result, t);
    380        return result.toString();
    381      }
    382
    383      //@ ensures \result != null;
    384      public final String toString(Name n) {
    385        ByteArrayOutputStream result = new ByteArrayOutputStream(20);
    386        print(result, n);
    387        return result.toString();
    388      }
    389
    390      //@ ensures \result != null;
    391      public final String toString(VarInit e) {
    392        ByteArrayOutputStream result = new ByteArrayOutputStream(20);
    393        print(result, 0, e);
    394        return result.toString();
    395      }
    396
    397      //@ ensures \result != null;
    398      public final String toString(ObjectDesignator od) {
    399        ByteArrayOutputStream result = new ByteArrayOutputStream(20);
    400        print(result, 0, od);
    401        return result.toString();
    402      }
    403
    404      //// Helper methods
    405
    406      //@ requires o != null;
    407      public static void writeln(OutputStream o) {
    408        write(o, '\n');
    409      }
    410
    411      //@ requires o != null && s != null;
    412      public static void writeln(OutputStream o, String s) {
    413        write(o, s);
    414        write(o, '\n');
    415      }
    416
    417      //@ requires o != null;
    418      public static void write(OutputStream o, char c) {
    419        try {
    420          o.write((byte)c);
    421        } catch (IOException e) {
    422          Assert.fail("IO exception");
    423        }
    424      }
    425
    426      //@ requires o != null && s != null;
    427      public static void write(OutputStream o, String s) {
    428        byte[] outBuf = s.getBytes();
    429        try {
    430          o.write(outBuf);
    431        } catch (IOException e) {
    432          Assert.fail("IO Exception");
    433        }
    434      }
    435
    436      //@ requires o != null;
    437      public static void spaces(/*@ non_null */ OutputStream o, int number) {
    438        try {
    439          while (number > 0) {
    440            int i = Math.min(number, _spaces.length);
    441            o.write(_spaces, 0, i);
    442            number -= i;
    443          }
    444        } catch (IOException e) {
    445          Assert.fail("IO Exception");
    446        }
    447      }
    448
    449      //@ private invariant _spaces != null;
    450      private static byte[] _spaces = { (byte)' ', (byte)' ', (byte)' ', (byte)' ',
    451                                        (byte)' ', /* 5 spaces */
    452                                        (byte)' ', (byte)' ', (byte)' ', (byte)' ',
    453                                        (byte)' ', /* 5 spaces */
    454                                        (byte)' ', (byte)' ', (byte)' ', (byte)' ',
    455                                        (byte)' ', /* 5 spaces */
    456                                        (byte)' ', (byte)' ', (byte)' ', (byte)' ',
    457                                        (byte)' ', /* 5 spaces */
    458                                        (byte)' ', (byte)' ', (byte)' ', (byte)' ',
    459                                        (byte)' ', /* 5 spaces */
    460                                       (byte)' ', (byte)' ', (byte)' ', (byte)' ',
    461                                       (byte)' ' /* 5 spaces */
    462      };
    463    }