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    import javafe.util.Assert;
009    import javafe.util.Location;
010    
011    public class StandardPrettyPrint extends PrettyPrint {
012    
013        public StandardPrettyPrint() { }
014    
015        //@ requires self != null;
016        public StandardPrettyPrint(PrettyPrint self) { super(self); }
017    
018        public void print(OutputStream o, CompilationUnit cu) {
019            if (cu == null) {
020                writeln(o, "<null CompilationUnit>");
021                return;
022            }
023            if (cu.lexicalPragmas != null) {
024                for (int i = 0; i < cu.lexicalPragmas.size(); i++)
025                    self.print(o, cu.lexicalPragmas.elementAt(i));
026                writeln(o);
027            }
028            if (cu.pkgName != null) {
029                write(o, "package "); self.print(o, cu.pkgName); writeln(o, ";");
030                writeln(o);
031            }
032            if (cu.imports.size() > 0) {
033                for(int j=0; j<cu.imports.size(); j++) {
034                    ImportDecl i = cu.imports.elementAt(j);
035                    write(o, "import ");
036                    if (i instanceof SingleTypeImportDecl)
037                        self.print(o, ((SingleTypeImportDecl)i).typeName);
038                    else {
039                        self.print(o, ((OnDemandImportDecl)i).pkgName);     //@ nowarn Cast;
040                        write(o, ".*");
041                    }
042                    writeln(o, ";");
043                }
044                writeln(o);
045            }
046            for(int j=0; j<cu.elems.size(); j++) {
047                self.print(o, 0, cu.elems.elementAt(j));
048                writeln(o);
049            }
050            for (int j=0; j<cu.otherPragmas.size(); ++j) {
051                TypeDeclElemPragma tde = (TypeDeclElemPragma)cu.otherPragmas.elementAt(j);
052                self.print(o, 0, tde);
053            }
054        }
055    
056        public void printnoln(OutputStream o, int ind, TypeDecl d) {
057            if (d == null) {
058                write(o, "<null TypeDecl>");
059                return;
060            }
061    
062            if (d.specOnly) {
063                writeln(o);
064                spaces(o, ind);
065                writeln(o, "/* Only specification information is available for "
066                        + "this type */");
067                writeln(o);
068                spaces(o, ind);
069            }
070            
071            if (d.pmodifiers != null)
072                for (int i = 0; i < d.pmodifiers.size(); i++) {
073                    self.print(o, ind, d.pmodifiers.elementAt(i));
074                    writeln(o);
075                    spaces(o, ind);
076                }
077            String mod = Modifiers.toString(d.modifiers);
078            if (!mod.equals("")) {
079                writeln(o, mod);
080                spaces(o, ind);
081            }
082    
083            Identifier id;
084    
085            switch (d.getTag()) {
086          
087                case TagConstants.CLASSDECL:
088                    {
089                        ClassDecl cd = (ClassDecl)d;
090                        writeln(o, "class "+(id=cd.id));
091                        if (cd.superClass != null) {
092                            if (!toString(cd.superClass).equals("java.lang.Object")
093                                || PrettyPrint.displayInferred) {
094                                spaces(o, ind);
095                                write(o, "extends ");
096                                self.print(o, cd.superClass);
097                                writeln(o);
098                            }
099                        }
100                        if (cd.superInterfaces.size() != 0) {
101                            spaces(o, ind);
102                            write(o, "implements ");
103                            self.print(o, cd.superInterfaces);
104                            writeln(o);
105                        }
106                        break;
107                    }
108          
109                case TagConstants.INTERFACEDECL:
110                    {
111                        InterfaceDecl cd = (InterfaceDecl)d;
112                        writeln(o, "interface "+(id=cd.id));
113                        if (cd.superInterfaces.size() != 0) {
114                            spaces(o, ind);
115                            write(o, "extends ");
116                            self.print(o, cd.superInterfaces);
117                            writeln(o,"");
118                        }
119                        break;
120                    }
121    
122                default:
123                    spaces(o, ind);
124                    writeln(o, unknownTag(d));
125                    id = Identifier.intern("?");
126            }
127    
128            spaces(o, ind);
129            writeln(o, "{");
130            for (int i = 0; i < d.elems.size(); i++) {
131                TypeDeclElem elem = d.elems.elementAt(i);
132                //@ assume elem.hasParent ;  // "invariant"
133                spaces(o, ind+INDENT);
134                self.print(o, ind+INDENT, elem, id, true);
135                if (i != d.elems.size()-1) writeln(o);
136            }
137            spaces(o, ind);
138            write(o, "}");
139        }
140    
141        public void print(OutputStream o, int ind, Stmt s) {
142            if (s == null) {
143                writeln(o, "<null Stmt>");
144                return;
145            }
146    
147            switch (s.getTag()) {
148          
149                case TagConstants.RETURNSTMT: 
150                    {
151                        ReturnStmt r = (ReturnStmt)s;
152                        if (r.expr == null)
153                            write(o, "return;");
154                        else {
155                            write(o, "return ");
156                            self.print(o, ind, r.expr);
157                            write(o, ';');
158                        }
159                        return;
160                    }
161          
162                case TagConstants.THROWSTMT: 
163                    {
164                        ThrowStmt t = (ThrowStmt)s;
165                        write(o, "throw "); self.print(o, ind, t.expr); write(o, ';');
166                        return;
167                    }
168          
169                case TagConstants.ASSERTSTMT: {
170                    AssertStmt a = (AssertStmt)s;
171                    write(o, "assert "); self.print(o, ind, a.pred); //write(o, ")");
172                    if (a.label != null) {
173                        write(o, " : ");
174                        self.print(o, ind, a.label);
175                    }
176                    write(o, ";");
177                    return;
178                }
179          
180                case TagConstants.SWITCHSTMT: 
181                    {
182                        SwitchStmt c = (SwitchStmt)s;
183                        write(o, "switch ("); self.print(o, ind, c.expr); write(o, ") ");
184                        // Fall through
185                    }
186    
187                case TagConstants.BLOCKSTMT: 
188                    {
189                        GenericBlockStmt b = (GenericBlockStmt)s;
190                        int nextInd = ind + INDENT;
191                        writeln(o, "{");
192                        boolean lastWasLabel = false;
193                        for(int i = 0; i < b.stmts.size(); i++) {
194                            Stmt sub = b.stmts.elementAt(i);
195                            if (sub.getTag() == TagConstants.SWITCHLABEL) {
196                                SwitchLabel x = (SwitchLabel)sub;
197                                if (x.expr == null && sub.getStartLoc() == b.locCloseBrace) {
198                                    // this is an implicit "default: break;" statement
199                                    Assert.notFalse(i == b.stmts.size() - 2); //@ nowarn Pre;
200                                    // don't print this statement or the next, which should be
201                                    // a "break"
202                                    Assert.notFalse(b.stmts.elementAt(i+1).getTag() //@ nowarn Pre;
203                                                    == TagConstants.BREAKSTMT);
204                                    if (!PrettyPrint.displayInferred)
205                                        break;
206                                }
207                                if (i != 0 && ! lastWasLabel) writeln(o);
208                                if (x.expr == null) { spaces(o, ind); writeln(o, "default:"); }
209                                else {
210                                    spaces(o, ind);
211                                    write(o, "case ");
212                                    self.print(o, ind, x.expr);
213                                    writeln(o, ":");
214                                }
215                                lastWasLabel = true;
216                            } else {
217                                spaces(o, nextInd);
218                                self.print(o, nextInd, sub);
219                                writeln(o);
220                                lastWasLabel = false;
221                            }
222                        }
223                        spaces(o, ind);
224                        write(o, '}');
225                        return;
226                    }
227          
228                case TagConstants.WHILESTMT: 
229                    {
230                        WhileStmt w = (WhileStmt)s;
231                        write(o, "while ("); self.print(o, ind, w.expr); write(o, ") ");
232                        self.print(o, ind, w.stmt);
233                        return;
234                    }
235          
236                case TagConstants.DOSTMT: 
237                    {
238                        DoStmt d = (DoStmt)s;
239                        write(o, "do ");
240                        self.print(o, ind, d.stmt);
241                        write(o, " while ("); self.print(o, ind, d.expr); write(o, ");");
242                        return;
243                    }
244          
245                case TagConstants.IFSTMT: 
246                    {
247                        IfStmt i = (IfStmt)s;
248                        write(o, "if ("); self.print(o, ind, i.expr); write(o, ") ");
249                        self.print(o, ind, i.thn);
250                        if (! (i.els.getTag() == TagConstants.SKIPSTMT)) {
251                            write(o, '\n');
252                            spaces(o, ind); write(o, "else "); self.print(o, ind, i.els);
253                        }
254                        return;
255                    }
256          
257                case TagConstants.BREAKSTMT: 
258                    {
259                        BreakStmt b = (BreakStmt)s;
260                        if (b.label == null) write(o, "break;");
261                        else {
262                            write(o, "break ");
263                            write(o, b.label.toString());
264                            write(o, ';');
265                        }
266                        return;
267                    }
268          
269                case TagConstants.CONTINUESTMT: 
270                    {
271                        ContinueStmt c = (ContinueStmt)s;
272                        if (c.label == null) write(o, "continue;");
273                        else {
274                            write(o, "continue ");
275                            write(o, c.label.toString());
276                            write(o, ';');
277                        }
278                        return;
279                    }
280          
281                case TagConstants.SYNCHRONIZESTMT: 
282                    {
283                        SynchronizeStmt x = (SynchronizeStmt)s;
284                        if (x.stmt.getTag() == TagConstants.BLOCKSTMT) {
285                            write(o, "synchronized (");
286                            self.print(o, ind, x.expr);
287                            write(o, ") ");
288                            self.print(o, ind, x.stmt);
289                        } else {
290                            write(o, "synchronized (");
291                            self.print(o, ind, x.expr);
292                            write(o, ") {\n");
293                            spaces(o, ind+INDENT);
294                            self.print(o, ind+INDENT, x.stmt);
295                            spaces(o, ind);
296                            write(o, '}');
297                        }
298                        return;
299                    }
300          
301                case TagConstants.EVALSTMT: 
302                    {
303                        EvalStmt x = (EvalStmt)s;
304                        self.print(o, ind, x.expr); write(o, ';');
305                        return;
306                    }
307          
308                case TagConstants.LABELSTMT: 
309                    {
310                        LabelStmt x = (LabelStmt)s;
311                        write(o, x.label.toString());
312                        write(o, ": ");
313                        self.print(o, ind, x.stmt);
314                        return;
315                    }
316          
317                case TagConstants.SKIPSTMT: 
318                    write(o, ';');
319                    return;
320          
321                case TagConstants.TRYFINALLYSTMT: 
322                    {
323                        TryFinallyStmt x = (TryFinallyStmt)s;
324                        if (x.tryClause.getTag() == TagConstants.TRYCATCHSTMT)
325                            self.print(o, ind, x.tryClause);
326                        else if (x.tryClause instanceof BlockStmt) {
327                            write(o, "try ");
328                            self.print(o, ind, x.tryClause);
329                        } else {
330                            write(o, "try {\b");
331                            spaces(o, ind);
332                            self.print(o, ind+INDENT, x.tryClause);
333                            spaces(o, ind);
334                            write(o, '}');
335                        }
336            
337                        if (x.finallyClause.getTag() == TagConstants.BLOCKSTMT) {
338                            write(o, " finally ");
339                            self.print(o, ind, x.finallyClause);
340                        } else {
341                            write(o, " finally {\n");
342                            spaces(o, ind);
343                            self.print(o, ind+INDENT, x.finallyClause);
344                            spaces(o, ind);
345                            write(o, '}');
346                        }
347                        return;
348                    }
349          
350                case TagConstants.TRYCATCHSTMT: 
351                    {
352                        TryCatchStmt x = (TryCatchStmt)s;
353                        if (x.tryClause.getTag() == TagConstants.BLOCKSTMT) {
354                            write(o, "try ");
355                            self.print(o, ind, x.tryClause);
356                        } else {
357                            write(o, "try {\n");
358                            spaces(o, ind+INDENT);
359                            self.print(o, ind+INDENT, x.tryClause);
360                            spaces(o, ind);
361                            write(o, '}');
362                        }
363            
364                        for(int i = 0; i < x.catchClauses.size(); i++) {
365                            CatchClause c = x.catchClauses.elementAt(i);
366                            write(o, " catch ("); self.print(o, c.arg); write(o, ") ");
367                            self.print(o, ind, c.body);
368                        }
369                        return;
370                    }
371          
372                case TagConstants.CLASSDECLSTMT: 
373                    {
374                        ClassDecl x = ((ClassDeclStmt)s).decl;
375                        self.printnoln(o, ind, x);
376                        return;
377                    }
378          
379                case TagConstants.VARDECLSTMT: 
380                    {
381                        LocalVarDecl x = ((VarDeclStmt)s).decl;
382                        self.print(o, ind, x, true);
383                        return;
384                    }
385          
386                case TagConstants.FORSTMT: 
387                    {
388                        ForStmt x = (ForStmt)s;
389                        write(o, "for (");
390            
391                        if (x.forInit.size() > 0)
392                            if (x.forInit.elementAt(0).getTag() == TagConstants.VARDECLSTMT) {
393                                self.print(o, ((VarDeclStmt)x.forInit.elementAt(0))//@nowarn Cast;
394                                           .decl.type);
395                                write(o, ' ');
396                                for(int i = 0; i < x.forInit.size(); i++) {
397                                    VarDeclStmt d = (VarDeclStmt)x.forInit.elementAt(i); //@nowarn Cast;
398                                    write(o, d.decl.id.toString());
399                                    if (d.decl.init != null) {
400                                        write(o, '=');
401                                        self.print(o, ind, d.decl.init);
402                                    }
403                                    if (i+1 < x.forInit.size()) write(o, ", ");
404                                }
405                            } else
406                                for(int i = 0; i < x.forInit.size(); i++) {
407                                    EvalStmt e = (EvalStmt) x.forInit.elementAt(i); //@nowarn Cast;
408                                    self.print(o, ind, e.expr);
409                                    if (i+1 < x.forInit.size()) write(o, ", ");
410                                }
411                        write(o, "; ");
412                        self.print(o, ind, x.test);
413                        write(o, "; ");
414                        for(int i = 0; i < x.forUpdate.size(); i++) {
415                            self.print(o, ind, x.forUpdate.elementAt(i));
416                            if (i+1 < x.forUpdate.size()) write(o, ", ");
417                        }
418                        write(o, ") ");
419                        self.print(o, ind, x.body);
420                        return;
421                    }
422          
423                case TagConstants.CONSTRUCTORINVOCATION: {
424                    ConstructorInvocation x = (ConstructorInvocation)s;
425                    if (x.enclosingInstance != null) {
426                        if (!(x.enclosingInstance instanceof ThisExpr) ||
427                            !(((ThisExpr)x.enclosingInstance).inferred) ||
428                            PrettyPrint.displayInferred) {
429                            self.print(o, ind, x.enclosingInstance);
430                            write(o, ".");
431                        }
432                    }
433                    write(o, (x.superCall ? "super" : "this"));
434                    self.print(o, ind, x.args);
435                    write(o, ';');
436                    return;
437                }
438    
439                case TagConstants.SWITCHLABEL: {
440                    /*
441                     * This case never happens unless a client directly calls us on
442                     * a SwitchLabel; normally block and switch statements handle
443                     * switch labels directly for better formating (multiple
444                     * cases/line).
445                     */
446                    SwitchLabel x = (SwitchLabel)s;
447    
448                    if (x.expr == null)
449                        writeln(o, "default:");
450                    else {
451                        write(o, "case ");
452                        self.print(o, ind, x.expr);
453                        writeln(o, ":");
454                    }
455                    return;
456                }
457    
458                default:
459                    if (s instanceof StmtPragma)
460                        self.print(o, ind, (StmtPragma)s);
461                    else write(o, unknownTag(s));
462                    return;
463            }
464        }
465    
466        public void print(OutputStream o, int ind, TypeDeclElem d, 
467                          Identifier classId, boolean showBody) {
468            if (d == null) {
469                writeln(o, "<null TypeDeclElem>");
470                return;
471            }
472            switch( d.getTag() ) {
473          
474                case TagConstants.FIELDDECL:
475                    self.print(o, ind, (FieldDecl)d, showBody); writeln(o);
476                    break;
477    
478                case TagConstants.INITBLOCK:
479                    {
480                        if (showBody) {
481                            InitBlock si = (InitBlock)d;
482                            write(o, Modifiers.toString(si.modifiers));
483                            if (si.pmodifiers != null)
484                                for (int i = 0; i < si.pmodifiers.size(); i++) {
485                                    write(o, ' ');
486                                    self.print(o, ind, si.pmodifiers.elementAt(i));
487                                }
488                            self.print(o, ind, si.block);
489                            writeln(o);
490                        }
491                        break;
492                    }
493    
494                case TagConstants.METHODDECL:
495                    {
496                        MethodDecl md = (MethodDecl)d;
497            
498                        if (md.id.toString().equals("<clinit>")) {
499                            break;
500                        }
501            
502                        write(o, Modifiers.toString(md.modifiers));
503                        self.print(o, md.returnType);
504                        write(o, ' ');
505                        write(o, md.id.toString());
506                        self.print(o, ind, md.args);
507                        if (md.raises.size() != 0)
508                        { write(o, " throws "); self.print(o, md.raises); }
509                        if (md.pmodifiers != null) {
510                            for (int i = 0; i < md.pmodifiers.size(); i++) {
511                                writeln(o);
512                                spaces(o, ind+1);
513                                self.print(o, ind, md.pmodifiers.elementAt(i));
514                            }
515                            write(o, ' ');
516                        }
517                        displayBody(o,ind, md.body, showBody,
518                                    d.getParent().specOnly,
519                                    "method");
520                        break;
521                    }
522            
523                case TagConstants.CONSTRUCTORDECL:
524                    {
525                        ConstructorDecl md = (ConstructorDecl)d;
526    
527                        // Don't print default constructors:
528                        if (md.implicit && !PrettyPrint.displayInferred) {
529                            // need to at least do a <newline> here!
530                            writeln(o, "// <default constructor>");
531                            break;
532                        }
533    
534                        write(o, Modifiers.toString(md.modifiers));
535                        write(o, classId.toString());
536                        self.print(o, ind, md.args);
537                        if (md.raises.size() != 0)
538                        { write(o, " throws "); self.print(o, md.raises); }
539                        if (md.pmodifiers != null) {
540                            for (int i = 0; i < md.pmodifiers.size(); i++) {
541                                writeln(o);
542                                spaces(o, ind+1);
543                                self.print(o, ind, md.pmodifiers.elementAt(i));
544                            }
545                            write(o, ' ');
546                        }
547    
548                        displayBody(o, ind, md.body, showBody,
549                                    d.getParent().specOnly,
550                                    "constructor");
551                        break;
552                    }
553    
554                case TagConstants.CLASSDECL:
555                case TagConstants.INTERFACEDECL:
556                    {
557                        self.print(o, ind, (TypeDecl)d);
558                        break;
559                    }
560    
561                default:
562                    if (d instanceof TypeDeclElemPragma)
563                        self.print(o, ind, (TypeDeclElemPragma)d);
564                    else writeln(o, unknownTagMsg(d.getTag()));
565                    break;
566            }
567        }
568    
569    
570        //@ requires o != null;
571        void displayBody(OutputStream o, int ind, BlockStmt body,
572                         boolean showBody, boolean specOnly, String kind) {
573            if (!showBody || body==null) {
574                writeln(o, ";");
575                return;
576            }
577    
578            writeln(o);
579            spaces(o, ind);
580    
581            if (specOnly) {
582                writeln(o,"{");
583                spaces(o, ind);
584                writeln(o, "  /* " + kind + " body unavailable */");
585                spaces(o, ind);
586                writeln(o,"}");
587            } else {
588                self.print(o, ind, body);
589                writeln(o);
590            }
591        }
592    
593         
594        public void print(OutputStream o, TypeNameVec tns) {
595            if (tns == null) write(o, "<null TypeNameVec>");
596            else
597                for( int i=0; i<tns.size(); i++ ) {
598                    if (i != 0) write(o, ", ");
599                    self.print(o, tns.elementAt(i));
600                }
601        }
602    
603        public void print(OutputStream o, int ind, FormalParaDeclVec fps) {
604            if (fps == null) write(o, "<null FormalParaDeclVec>");
605            else {
606                write(o, '(');
607                for (int i=0; i<fps.size(); i++) {
608                    if (i != 0) write(o, ", ");
609    
610                    FormalParaDecl d = fps.elementAt(i);
611                    write(o, Modifiers.toString(d.modifiers));
612                    self.print(o, d);
613                    if (d.pmodifiers != null)
614                        for (int j = 0; j < d.pmodifiers.size(); j++) {
615                            write(o, ' ');
616                            self.print(o, ind, d.pmodifiers.elementAt(j));
617                        }
618                }
619                write(o, ')');
620            }
621        }
622    
623        public void print(OutputStream o, int ind, ExprVec es) {
624            if (es == null) write(o, "<null ExprVec>");
625            else {
626                write(o, '(');
627                for (int i = 0; i < es.size(); i++) {
628                    if (i != 0) write(o, ", ");
629                    self.print(o, ind, es.elementAt(i));
630                }
631                write(o, ')');
632            }
633        }
634    
635        public void print(OutputStream o, GenericVarDecl d) {
636            if (d == null) write(o, "<null GenericVarDecl>");
637            else {
638                self.print(o, d.type);
639                write(o, ' ');
640                write(o, d.id.toString());
641            }
642        }
643      
644        public void print(OutputStream o, int ind, LocalVarDecl d,
645                          boolean showBody) {
646            if (d == null) write(o, "<null VarDecl>");
647            else {
648                write(o, Modifiers.toString(d.modifiers));
649                self.print(o, d.type);
650                write(o, ' ');
651                write(o, d.id.toString());
652                if (showBody && d.init != null)
653                { write(o, " = "); self.print(o, ind, d.init); }
654                if (d.pmodifiers != null)
655                    for (int i = 0; i < d.pmodifiers.size(); i++) {
656                        write(o, ' ');
657                        self.print(o, ind, d.pmodifiers.elementAt(i));
658                    }
659                write(o, ';');
660            }
661        }
662      
663        public void print(OutputStream o, int ind, FieldDecl d, boolean showBody) {
664            if (d == null) write(o, "<null VarDecl>");
665            else {
666                write(o, Modifiers.toString(d.modifiers));
667                self.print(o, d.type);
668                write(o, ' ');
669                write(o, d.id.toString());
670                if (showBody && d.init != null)
671                { write(o, " = "); self.print(o, ind, d.init); }
672                if (d.pmodifiers != null)
673                    for (int i = 0; i < d.pmodifiers.size(); i++) {
674                        write(o, ' ');
675                        self.print(o, ind, d.pmodifiers.elementAt(i));
676                    }
677                write(o, ';');
678            }
679        }
680      
681        public void print(OutputStream o, Type t) {
682            if (t == null) { write(o, "<null Type>"); return; }
683            switch (t.getTag()) {
684                case TagConstants.BOOLEANTYPE: write(o, "boolean"); break;
685                case TagConstants.BYTETYPE: write(o, "byte"); break;
686                case TagConstants.ERRORTYPE: write(o, "error"); break;
687                case TagConstants.SHORTTYPE: write(o, "short"); break;
688                case TagConstants.INTTYPE: write(o, "int"); break;
689                case TagConstants.LONGTYPE: write(o, "long"); break;
690                case TagConstants.CHARTYPE: write(o, "char"); break;
691                case TagConstants.FLOATTYPE: write(o, "float"); break;
692                case TagConstants.DOUBLETYPE: write(o, "double"); break;
693                case TagConstants.VOIDTYPE: write(o, "void"); break;
694                case TagConstants.NULLTYPE: write(o, "null"); break;
695                case TagConstants.TYPENAME:
696                    self.print(o, ((TypeName)t).name); break;
697                case TagConstants.ARRAYTYPE:
698                    self.print(o, ((ArrayType)t).elemType); write(o, "[");
699                    write(o,"]");
700                    break;
701                default:
702                    write(o, t.toString() );
703                    break;
704            }
705            print(o, 2, t.tmodifiers);
706        }
707      
708        public void print(OutputStream o, Name n) {
709            if (n == null) write(o, "<null Name>");
710            else write(o, n.printName());
711        }
712      
713        static public void println(VarInit e) {
714            inst.print(System.out,0,e);
715            System.out.println("");
716        }
717    
718        public void print(OutputStream o, int ind, VarInit e) {
719            if (e == null) {
720                write(o, "<null expression>");
721                return;
722            }
723    
724            int eTag = e.getTag();
725            switch (eTag) {
726          
727                case TagConstants.ARRAYINIT: 
728                    {
729                        VarInitVec v = ((ArrayInit)e).elems;
730                        write(o, "{ ");
731                        for(int i = 0; i < v.size(); i++) {
732                            if (i != 0 ) write(o, ", ");
733                            self.print(o, ind, v.elementAt(i));
734                        }
735                        write(o, " }");
736                        return;
737                    }
738                        
739                case TagConstants.THISEXPR: {
740                    ThisExpr t = (ThisExpr)e;
741                    if (t.classPrefix != null) {
742                        self.print(o, t.classPrefix);
743                        write(o, ".");
744                    }
745                    write(o, "this");
746                    return;
747                }
748    
749                    // Literals
750                case TagConstants.BOOLEANLIT: 
751                case TagConstants.STRINGLIT:
752                case TagConstants.CHARLIT:
753                case TagConstants.DOUBLELIT: 
754                case TagConstants.FLOATLIT:
755                case TagConstants.INTLIT:
756                case TagConstants.LONGLIT:
757                    write(o, toCanonicalString(eTag, ((LiteralExpr)e).value));
758                    return;
759    
760                case TagConstants.NULLLIT:
761                    write(o, "null");
762                    return;
763    
764                case TagConstants.ARRAYREFEXPR:
765                    {
766                        ArrayRefExpr r = (ArrayRefExpr)e;
767                        self.print(o, ind, r.array);
768                        write(o, '['); self.print(o, ind, r.index); write(o, ']');
769                        return;
770                    }
771    
772                case TagConstants.NEWINSTANCEEXPR:
773                    { 
774                        NewInstanceExpr ne = (NewInstanceExpr)e;
775                        if (ne.enclosingInstance != null) {
776                            if (!(ne.enclosingInstance instanceof ThisExpr) ||
777                                !(((ThisExpr)ne.enclosingInstance).inferred) ||
778                                PrettyPrint.displayInferred) {
779                                self.print(o, ind, ne.enclosingInstance);
780                                write(o, ".");
781                            }
782                        }
783                        write(o, "new "); self.print(o, ne.type); self.print(o, ind, ne.args);
784                        if (ne.anonDecl != null) {
785                            writeln(o, " {");
786                            for (int i = 0; i < ne.anonDecl.elems.size(); i++) {
787                                TypeDeclElem elem = ne.anonDecl.elems.elementAt(i);
788                                //@ assume elem.hasParent;   // "invariant"
789                                spaces(o, ind+INDENT);
790                                self.print(o, ind+INDENT, elem, ne.anonDecl.id, true);
791                                if (i != ne.anonDecl.elems.size()-1) writeln(o);
792                            }
793                            spaces(o, ind);
794                            write(o, "}");
795                        }
796                        return;
797                    }
798    
799                case TagConstants.NEWARRAYEXPR:
800                    {
801                        NewArrayExpr na = (NewArrayExpr)e;
802                        Type basetype = na.type;
803                        int cnt;
804    
805                        for (cnt = 0; basetype.getTag() == TagConstants.ARRAYTYPE; cnt++) {
806                            basetype = ((ArrayType)basetype).elemType;
807                        }
808                        write(o, "new "); self.print(o, basetype);
809                        for(int i=0; i<na.dims.size(); i++) {
810                            write(o, '[');
811                            if (na.init == null) {
812                                self.print(o, ind, na.dims.elementAt(i));
813                            }
814                            write(o, ']');
815                        }
816                        for ( ; 0 < cnt; cnt--) write(o, "[]");
817                        if (na.init != null) self.print(o, ind, na.init);
818                        return;
819                    }
820    
821                case TagConstants.CONDEXPR:
822                    {
823                        CondExpr ce = (CondExpr)e;
824                        self.print(o, ind, ce.test); write(o, " ? ");
825                        self.print(o, ind, ce.thn); write(o, " : ");
826                        self.print(o, ind, ce.els);
827                        return;
828                    }
829    
830                case TagConstants.INSTANCEOFEXPR:
831                    {
832                        InstanceOfExpr ie = (InstanceOfExpr)e;
833                        self.print(o, ind, ie.expr);
834                        write(o, " instanceof ");
835                        self.print(o, ie.type);
836                        return;
837                    }
838    
839                case TagConstants.CASTEXPR:
840                    {
841                        CastExpr ce = (CastExpr)e;
842                        write(o, '('); self.print(o, ce.type); write(o, ')');
843                        self.print(o, ind, ce.expr);
844                        return;
845                    }
846    
847                case TagConstants.CLASSLITERAL:
848                    {
849                        ClassLiteral cl = (ClassLiteral)e;
850                        self.print(o, cl.type); write(o, ".class");
851                        return;
852                    }
853    
854                    // Binary expressions
855                case TagConstants.OR: case TagConstants.AND:
856                case TagConstants.BITOR: case TagConstants.BITXOR:
857                case TagConstants.BITAND: case TagConstants.NE:
858                case TagConstants.EQ: case TagConstants.GE:
859                case TagConstants.GT: case TagConstants.LE:
860                case TagConstants.LT: case TagConstants.LSHIFT:
861                case TagConstants.RSHIFT: case TagConstants.URSHIFT:
862                case TagConstants.ADD: case TagConstants.SUB:
863                case TagConstants.DIV: case TagConstants.MOD:
864                case TagConstants.STAR:
865                case TagConstants.ASSIGN: case TagConstants.ASGMUL:
866                case TagConstants.ASGDIV: case TagConstants.ASGREM:
867                case TagConstants.ASGADD: case TagConstants.ASGSUB:
868                case TagConstants.ASGLSHIFT: case TagConstants.ASGRSHIFT:
869                case TagConstants.ASGURSHIFT: case TagConstants.ASGBITAND:
870                case TagConstants.ASGBITOR: case TagConstants.ASGBITXOR:
871                    {
872                        BinaryExpr be = (BinaryExpr)e;
873                        self.print(o, ind, be.left); write(o, ' ');
874                        write(o, OperatorTags.toString(be.op)); write(o, ' ');
875                        self.print(o, ind, be.right);
876                        return;
877                    }
878    
879                    // Unary expressions
880                case TagConstants.UNARYSUB: case TagConstants.UNARYADD:
881                case TagConstants.NOT: case TagConstants.BITNOT:
882                case TagConstants.INC: case TagConstants.DEC:
883                case TagConstants.POSTFIXINC: case TagConstants.POSTFIXDEC:
884                    {
885                        UnaryExpr ue = (UnaryExpr)e;
886                        if (ue.op == TagConstants.POSTFIXINC)
887                        { self.print(o, ind, ue.expr); write(o, "++"); }
888                        else if (ue.op == TagConstants.POSTFIXDEC)
889                        { self.print(o, ind, ue.expr); write(o, "--"); }
890                        else {
891                            write(o, OperatorTags.toString(ue.op));
892                            write(o, " "); self.print(o, ind, ue.expr);
893                        }
894                        return;
895                    }
896    
897                case TagConstants.PARENEXPR:
898                    {
899                        ParenExpr pe = (ParenExpr)e;
900                        write(o, '('); self.print(o, ind, pe.expr); write(o, ')');
901                        return;
902                    }
903    
904                case TagConstants.AMBIGUOUSVARIABLEACCESS:
905                    self.print(o, ((AmbiguousVariableAccess)e).name);
906                    return;
907    
908                case TagConstants.VARIABLEACCESS:
909                    {
910                        VariableAccess lva = (VariableAccess)e;
911                        write(o, lva.decl.id.toString());
912                        return;
913                    }
914          
915                case TagConstants.FIELDACCESS:
916                    {
917                        FieldAccess a = (FieldAccess)e;
918                        self.print(o, ind, a.od); write(o, a.id.toString());
919                        return;
920                    }
921          
922                case TagConstants.AMBIGUOUSMETHODINVOCATION:
923                    {
924                        AmbiguousMethodInvocation ie = (AmbiguousMethodInvocation)e;
925                        self.print(o, ie.name); self.print(o, ind, ie.args);
926                        return;
927                    }
928    
929                case TagConstants.METHODINVOCATION:
930                    {
931                        MethodInvocation ie = (MethodInvocation)e;
932                        self.print(o, ind, ie.od);
933                        write(o, ie.id.toString());
934                        self.print(o, ind, ie.args);
935                        return;
936                    }
937    
938                default:
939                    write(o, unknownTag(e));
940                    return;
941            }
942        }
943    
944        public void print(OutputStream o, int ind, ObjectDesignator od) {
945            if (od == null) { write(o, "<null object designator>"); return; }
946            switch (od.getTag()) {
947                case TagConstants.EXPROBJECTDESIGNATOR:
948                    {
949                        ExprObjectDesignator a = (ExprObjectDesignator)od;
950                        if (a.expr.getTag() != TagConstants.THISEXPR
951                            || !((ThisExpr)a.expr).inferred
952                            || PrettyPrint.displayInferred)
953                        { self.print(o, ind, a.expr); write(o, '.'); }
954                        return;
955                    }
956          
957                case TagConstants.TYPEOBJECTDESIGNATOR:
958                    {
959                        TypeObjectDesignator a = (TypeObjectDesignator)od;
960                        if (a.type.getTag() == TagConstants.TYPENAME
961                            || PrettyPrint.displayInferred)
962                        { self.print(o, a.type); write(o, '.'); }
963                        return;
964                    }
965          
966                case TagConstants.SUPEROBJECTDESIGNATOR:
967                    write(o, "super.");
968                    return;
969          
970                default:
971                    write(o, unknownTag(od));
972                    break;
973            }
974        }
975    
976        //// toString methods
977    
978        /**
979         * Requires that <code>tag</code> is one of constants on the left of this
980         * table:
981         * <center><code><table>
982         * <tr> <td> TagConstants.BOOLEANLIT </td> <td> Boolean </td> </tr>
983         * <tr> <td> TagConstants.CHARLIT </td>   <td> Integer </td> </tr>
984         * <tr> <td> TagConstants.DOUBLELIT </td> <td> Double </td> </tr>
985         * <tr> <td> TagConstants.FLOATLIT </td>  <td> Float </td> </tr>
986         * <tr> <td> TagConstants.INTLIT </td>    <td> Integer </td> </tr>
987         * <tr> <td> TagConstants.LONGLIT </td>   <td> Long </td> </tr>
988         * <tr> <td> TagConstants.STRINGLIT </td> <td> String </td> </tr>
989         * </center></code></table>
990         * 
991         * and that <code>val</code> is an instance of the corresponding type
992         * on the right.
993         * @return a canonical text representation for literal values.
994         */
995    
996        /*@ requires ((tag==TagConstants.BOOLEANLIT) ||
997          @           (tag==TagConstants.INTLIT) ||
998          @           (tag==TagConstants.LONGLIT) ||
999          @           (tag==TagConstants.FLOATLIT) ||
1000          @           (tag==TagConstants.DOUBLELIT) ||
1001          @           (tag==TagConstants.STRINGLIT) ||
1002          @           (tag==TagConstants.CHARLIT));
1003          @*/
1004        /*@ requires (((tag==TagConstants.BOOLEANLIT) ==> (val instanceof Boolean)) &&
1005          @           ((tag==TagConstants.INTLIT) ==> (val instanceof Integer)) &&
1006          @           ((tag==TagConstants.LONGLIT) ==> (val instanceof Long)) &&
1007          @           ((tag==TagConstants.FLOATLIT) ==> (val instanceof Float)) &&
1008          @           ((tag==TagConstants.DOUBLELIT) ==> (val instanceof Double)) &&
1009          @           ((tag==TagConstants.STRINGLIT) ==> (val instanceof String)) &&
1010          @           ((tag==TagConstants.CHARLIT) ==> (val instanceof Integer)));
1011          @*/
1012        //@ ensures \result != null;
1013        public static String toCanonicalString(int tag, Object val) {
1014            if (tag == TagConstants.BOOLEANLIT) return val.toString();
1015    
1016            if (tag == TagConstants.DOUBLELIT) {
1017                String s = val.toString();
1018                if (s.equals("Infinity")) return "1.0 / 0.0";
1019                if (s.equals("-Infinity")) return "-1.0 / 0.0";
1020                if (s.equals("NaN")) return "0.0d / 0.0";
1021                return val.toString() + "D";
1022            }
1023    
1024            if (tag == TagConstants.FLOATLIT) {
1025                String s = val.toString();
1026                if (s.equals("Infinity")) return "1.0f / 0.0f";
1027                if (s.equals("-Infinity")) return "-1.0f / 0.0f";
1028                if (s.equals("NaN")) return "0.0f / 0.0f";
1029                return val.toString() + "F";
1030            }
1031    
1032            if (tag == TagConstants.INTLIT) {
1033                int v = ((Integer) val).intValue();
1034                if (v == Integer.MIN_VALUE) return "0x80000000";
1035                else if (v < 0) return "0x" + Integer.toHexString(v);
1036                else return Integer.toString(v);
1037            }
1038    
1039            if (tag == TagConstants.LONGLIT) {
1040                long v = ((Long) val).longValue();
1041                if (v == Long.MIN_VALUE) return "0x8000000000000000L";
1042                else if (v < 0) return "0x" + Long.toHexString(v) + "L";
1043                else return Long.toString(v) + "L";
1044            }
1045    
1046            if (tag == TagConstants.CHARLIT || tag == TagConstants.STRINGLIT) {
1047                char quote;
1048                if (tag == TagConstants.CHARLIT) {
1049                    quote = '\'';
1050                    val = new Character((char)((Integer)val).intValue());
1051                } else quote = '\"';
1052                String s = val.toString();
1053                StringBuffer result = new StringBuffer(s.length()+2);
1054                result.append(quote);
1055                for(int i = 0, len = s.length(); i < len; i++) {
1056                    char c = s.charAt(i);
1057                    switch (c) {
1058                        case '\b': result.append("\\b"); break;
1059                        case '\t': result.append("\\t"); break;
1060                        case '\n': result.append("\\n"); break;
1061                        case '\f': result.append("\\f"); break;
1062                        case '\r': result.append("\\r"); break;
1063                        case '\"': result.append("\\\""); break;
1064                        case '\'': result.append("\\'"); break;
1065                        case '\\': result.append("\\\\"); break;
1066                        default:
1067                            if (32 <= c && c < 128) result.append(c);
1068                            else {
1069                                result.append("\\u");
1070                                for(int j=12; j>=0; j-=4)
1071                                    result.append(Character.forDigit((c>>j)&0xf, 16));
1072                            }
1073                    }
1074                }
1075                result.append(quote);
1076                return result.toString();
1077            }    
1078    
1079            Assert.precondition(false);
1080            return null; // Dummy
1081        }
1082    
1083        public void print(OutputStream o, LexicalPragma lp) {
1084            write(o, "// Lexical pragma at " + lp.getStartLoc() + " ");
1085            writeln(o, lp.toString());
1086        }
1087    
1088        public void print(OutputStream o, int ind, TypeDeclElemPragma tp) {
1089            spaces(o, ind);
1090            write(o, "// TypeDeclElemPragma pragma at " + tp.getStartLoc() + " ");
1091            write(o, tp.toString());
1092        }
1093    
1094        public void print(OutputStream o, int ind, ModifierPragma mp) {
1095            write(o, "// ModifierPragma pragma at " + mp.getStartLoc() + " ");
1096            write(o, mp.toString());
1097        }
1098    
1099        public void print(OutputStream o, int ind, StmtPragma sp) {
1100            spaces(o, ind);
1101            write(o, "// StmtPragma pragma at " + sp.getStartLoc() + " ");
1102            write(o, sp.toString());
1103        }
1104    
1105    
1106        public void print(OutputStream o, int ind, TypeModifierPragma tp) {
1107            spaces(o, ind);
1108            write(o, "// TypeModifierPragma pragma at " + tp.getStartLoc() + " ");
1109            write(o, tp.toString());
1110        }
1111      
1112        //@ requires o != null;
1113        public void print(OutputStream o, int ind, TypeModifierPragmaVec t) {
1114            if (t != null) {
1115                for (int i = 0; i < t.size(); i++) {
1116                    write(o, ' ');
1117                    self.print(o, ind, t.elementAt(i));
1118                }
1119            }
1120        }
1121      
1122        /**
1123         * Generate text to describe a ASTNote with an unknown tag
1124         */
1125        //@ requires n != null;
1126        //@ ensures \result != null;
1127        public String unknownTag(ASTNode n) {
1128            return unknownTagMsg(n.getTag());
1129        }
1130      
1131        /**
1132         * Generate text to describe a given unknown tag
1133         */
1134        //@ ensures \result != null;
1135        public String unknownTagMsg(int tag) {
1136            return "UnknownTag<" + tag + ":"
1137                + PrettyPrint.inst.toString(tag) + ">";
1138        }
1139    }