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