KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > aspectj > compiler > base > CodeWriter


1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * This file is part of the compiler and core tools for the AspectJ(tm)
4  * programming language; see http://aspectj.org
5  *
6  * The contents of this file are subject to the Mozilla Public License
7  * Version 1.1 (the "License"); you may not use this file except in
8  * compliance with the License. You may obtain a copy of the License at
9  * either http://www.mozilla.org/MPL/ or http://aspectj.org/MPL/.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is AspectJ.
17  *
18  * The Initial Developer of the Original Code is Xerox Corporation. Portions
19  * created by Xerox Corporation are Copyright (C) 1999-2002 Xerox Corporation.
20  * All Rights Reserved.
21  *
22  * Contributor(s):
23  */

24
25 package org.aspectj.compiler.base;
26 import org.aspectj.compiler.base.ast.*;
27
28 import java.util.*;
29 import java.io.*;
30
31 import org.aspectj.tools.ide.SourceLine;
32 import org.aspectj.util.CollectionUtil;
33
34 public class CodeWriter extends CompilerObject {
35     private boolean writeComments = false;
36     private LineMap lineMap = null;
37     private CodeText out;
38     //private Writer out = null;
39

40     public CodeWriter(JavaCompiler compiler) {
41         this(compiler, 1024, null);
42     }
43
44     public CodeWriter(JavaCompiler compiler, int expectedSize, LineMap lineMap) {
45         super(compiler);
46         out = new CodeText(expectedSize);
47         this.lineMap = lineMap;
48         //XXX bogus
49
this.writeComments = !compiler.getOptions().nocomments;
50     }
51
52     public String JavaDoc getString() {
53         return out.getString();
54     }
55     
56     public void writeTo(OutputStream ostream) throws IOException {
57         out.writeTo(ostream);
58     }
59
60     private boolean onlySignatures = false;
61     public boolean isOnlySignatures() { return onlySignatures; }
62     public void setOnlySignatures(boolean v) { onlySignatures = v; }
63
64     private boolean onlyPatch = false;
65     public boolean isOnlyPatch() { return onlyPatch; }
66     public void setOnlyPatch(boolean v) { onlyPatch = v; }
67
68     public void parenExpr(Expr expr) {
69         openParen('(');
70         write(expr);
71         closeParen(')');
72     }
73
74     public void parenExprs(Exprs exprs) {
75         openParen('(');
76         write(exprs);
77         closeParen(')');
78     }
79
80     public void writeChildren(ASTObject parent) {
81         if (parent == null) return;
82         final int N = parent.getChildCount();
83         if (N > 0) write(parent.getChildAt(0));
84
85         for(int i=1; i<N; i++) {
86             write(parent.getChildAt(i));
87         }
88     }
89
90     public void writeChildrenWithCommas(ASTObject parent) {
91         if (parent == null) return;
92         final int N = parent.getChildCount();
93         if (N > 0) write(parent.getChildAt(0));
94
95         for(int i=1; i<N; i++) {
96             comma();
97             write(parent.getChildAt(i));
98         }
99     }
100
101
102     public void write(ASTObject node) {
103         try {
104             if (node == null) return;
105     
106             if (writeComments) {
107                 Comment comment = node.getComment();
108                 while (comment != null) {
109                     comment.unparse(this);
110                     comment = comment.getNextComment();
111                 }
112             }
113     
114             // This is to output line-number correspondences for the debugger
115
if (lineMap != null) {
116                 lineMap.noteNode(node);
117             }
118     
119             node.unparse(this);
120         } catch (IOException ioe) {
121             //XXX this clause needs to go away
122
}
123     }
124
125     public int getIndentSize() { return 2; }
126
127     private int lineStart = 0;
128     private int lastGoodBreak = -1;
129     private int lastPossibleBreak = -1;
130     
131     public void noteGoodBreak() {
132         breakTooLongLine();
133         lastGoodBreak = out.getIndex();
134     }
135     
136     public void notePossibleBreak() {
137         breakTooLongLine();
138         lastPossibleBreak = out.getIndex();
139     }
140     
141     public void breakTooLongLine() {
142         int column = out.getIndex() - lineStart;
143         //System.out.println("column: " + column);
144
if (column < MAX_COLUMNS) return;
145      
146 // int goodMetric = MAX_COLUMNS - lastGoodBreak;
147
// int possibleMetric = MAX_COLUMNS - lastPossibleBreak;
148

149         int breakPoint = -1;
150         if (lastGoodBreak != -1) {
151             breakPoint = lastGoodBreak;
152         } else if (lastPossibleBreak != -1) {
153             breakPoint = lastPossibleBreak;
154         } else {
155             // we can't manage to break this line
156
return;
157         }
158         
159         insertNewLine(breakPoint);
160     }
161     
162     public void insertNewLine(int breakAtIndex) {
163         byte[] saveData = out.backup(breakAtIndex);
164         // would like to also include pretty-breaking using parens, but not now
165
out.write(newLine);
166         lineStart = out.getIndex();
167         lastPossibleBreak = lastGoodBreak = -1;
168         writeSpaces(indents + 4);
169         out.write(saveData);
170         lastPossibleBreak = out.getIndex();
171     }
172     
173     
174     
175     public void comma() {
176         write(',');
177         optionalSpace();
178         noteGoodBreak();
179     }
180
181     public void requiredSpace() {
182         //column++;
183
out.write(' ');
184         notePossibleBreak();
185     }
186     public void optionalSpace() {
187         //column++;
188
out.write(' ');
189         notePossibleBreak();
190     }
191
192     public void writeKeyword(String JavaDoc keyword) {
193         write(keyword);
194     }
195
196     public void writeOp(String JavaDoc op) {
197         optionalSpace();
198         write(op);
199         optionalSpace();
200     }
201
202     // These fields keep a stack of open paren locations to use for pretty-printing lines
203
// that are too long
204
final int MAX_PAREN_DEPTH = 32;
205     private int[] parenPositions = new int[MAX_PAREN_DEPTH+1];
206     private int parenDepth = 0;
207     
208     public void openParen(char paren) {
209         write(paren);
210         parenDepth++;
211         parenPositions[parenDepth > MAX_PAREN_DEPTH ? MAX_PAREN_DEPTH : parenDepth] = out.getIndex();
212         notePossibleBreak();
213     }
214
215     public void closeParen(char paren) {
216         write(paren);
217         parenDepth--;
218     }
219
220
221     public void closeStmt() {
222         write(';');
223         //newLine();
224
}
225
226
227     private int indents=0;
228     public int getIndents() {
229         return indents;
230     }
231     public void setIndents(int indents) {
232         this.indents = indents;
233     }
234
235     public void openBlock() {
236         //if (!needIndent) write(" ");
237
writeln("{");
238         indent();
239     }
240
241     public void closeBlock() {
242         dedent();
243         write("} ");
244     }
245
246     public void indent() {
247         indents += getIndentSize();
248     }
249
250     public void dedent() {
251         indents -= getIndentSize();
252     }
253
254     // text may include newlines and will be nicely broken up on those
255
public void writeLines(String JavaDoc text) {
256         if (text == null) return;
257
258         // break text up into lines and write each individually
259
int currentPos = 0;
260         while (true) {
261             int newlinePos = text.indexOf('\n', currentPos);
262             if (newlinePos == -1) break;
263             writeln(text.substring(currentPos, newlinePos));
264             currentPos = newlinePos + 1;
265         }
266
267         write(text.substring(currentPos));
268     }
269
270
271     //int column = 0;
272
// text can not include new lines
273
public void write(String JavaDoc text) {
274         doIndent();
275         out.write(text);
276         //column += text.length();
277
}
278
279     public void write(char ch) {
280         doIndent();
281         out.write(ch);
282         //column += 1;
283
}
284
285     // text can not include new lines (but one is added)
286
public void writeln(String JavaDoc text) {
287         write(text);
288         newLine();
289     }
290
291     //XXX this should be made platform independent
292
final String JavaDoc newLine = "\n";
293
294     final int COMMENT_COLUMN = 67;
295     final int MAX_COLUMNS = 100;
296     public void newLine() {
297         // deal with long lines
298
breakTooLongLine();
299         
300         if (writeComments && lineMap != null && lineMap.hasCurrentSourceLine()) {
301             int column = out.getIndex() - lineStart;
302             if (column < COMMENT_COLUMN) {
303                 writeSpaces(COMMENT_COLUMN - column);
304             } else {
305                 out.write(' ');
306             }
307             
308             out.write("//");
309             // should add in a check to see if the file matches and use a shorter form
310
// that step should also optimize the computation of this
311
out.write(new File(lineMap.getCurrentSourceFile()).getName());
312             out.write(":" + lineMap.getCurrentSourceLine());
313         }
314         out.write(newLine);
315         if (lineMap != null) {
316             lineMap.noteNewLine();
317         }
318         lineStart = out.getIndex();
319         needIndent = true;
320         lastGoodBreak = -1;
321         lastPossibleBreak = -1;
322     }
323
324     private boolean needIndent = false;
325     void doIndent() {
326         if (!needIndent) return;
327         needIndent = false;
328         writeSpaces(indents);
329     }
330
331     //??? do this with an array for speed
332
final void writeSpaces(final int N) {
333         //column += N;
334
for (int i = 0; i < N; i++) {
335             out.write(' ');
336         }
337     }
338
339     public static final String JavaDoc HEADER_START =
340         "/* Generated by AspectJ version ";
341
342     public static boolean isGeneratedSource(File file) {
343         try {
344             Reader reader = new FileReader(file);
345             for(int i=0; i<HEADER_START.length(); i++) {
346                 int ch = reader.read();
347                 if (ch != HEADER_START.charAt(i)) return false;
348             }
349             reader.close();
350             return true;
351         } catch (IOException ioe) {
352             //!!! should I worry about closing the file under these circumstances?
353
return false;
354         }
355     }
356
357
358     public void writeHeader() {
359         writeln(HEADER_START+Options.version+" */");
360     }
361 }
362
363
364 class CodeText {
365     protected byte[] data;
366     protected int index;
367     protected boolean addSlash;
368
369     public CodeText(int expectedSize) {
370         data = new byte[expectedSize];
371         index = 0;
372         addSlash = false;
373     }
374
375     public int getIndex() {
376         return index;
377     }
378     
379     public byte[] backup(int toIndex) {
380         int backupSize = index - toIndex;
381         byte[] ret = new byte[backupSize];
382         
383         System.arraycopy(data, toIndex, ret, 0, backupSize);
384         
385         index = toIndex;
386         return ret;
387     }
388     
389     private final void expandTo(int newSize) {
390         if (newSize < data.length) return;
391
392         int newLength = data.length * 2;
393         while (newLength < newSize) newLength *= 2;
394         
395         byte[] newData = new byte[newLength];
396         System.arraycopy(data, 0, newData, 0, index);
397         data = newData;
398     }
399     
400     
401     public void write(byte b) {
402         expandTo(index + 1);
403         data[index++] = b;
404     }
405         
406     public void write(byte[] bytes) {
407         expandTo(index + bytes.length);
408         System.arraycopy(bytes, 0, data, index, bytes.length);
409         index += bytes.length;
410     }
411     
412     public void write(String JavaDoc s) {
413         final int N = s.length();
414         for (int i = 0; i < N; i++) {
415             write(s.charAt(i));
416         }
417     }
418     
419     public void write(int ch) {
420         expandTo(index + 7);
421         
422         if (addSlash && ch == 'u') {
423             data[index++] = (byte)'\\';
424             //data[index++] = 'u';
425
}
426
427         if (ch == '\\') {
428             addSlash = !addSlash;
429         } else {
430             addSlash = false;
431         }
432
433         if (ch < 1 || ch > 126) {
434             int b1 = ch>>12;
435             int b2 = ch>>8 & 0xf;
436             int b3 = ch>>4 & 0xf;
437             int b4 = ch & 0xf;
438
439             data[index++] = (byte)'\\';
440             data[index++] = (byte)'u';
441             data[index++] = (byte)Character.forDigit(b1, 16);
442             data[index++] = (byte)Character.forDigit(b2, 16);
443             data[index++] = (byte)Character.forDigit(b3, 16);
444             data[index++] = (byte)Character.forDigit(b4, 16);
445         } else {
446             data[index++] = (byte)ch;
447         }
448     }
449
450     public String JavaDoc getString() {
451         try {
452             return new String JavaDoc(data, 0, index, "US-ASCII");
453         } catch (UnsupportedEncodingException e) {
454             return new String JavaDoc(data, 0, index);
455         }
456     }
457     
458     public void writeTo(OutputStream ostream) throws IOException {
459         ostream.write(data, 0, index);
460         ostream.flush();
461     }
462 }
463
Popular Tags