/Users/lyon/j4p/src/javassist/preproc/Compiler.java
|
1 /*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16 package javassist.preproc;
17
18 import java.io.IOException;
19 import java.io.BufferedReader;
20 import java.io.FileReader;
21 import java.io.BufferedWriter;
22 import java.io.FileWriter;
23 import java.util.Vector;
24
25 import javassist.CannotCompileException;
26 import javassist.CtClass;
27 import javassist.ClassPool;
28
29 /**
30 * This is a preprocessor for Java source programs using annotated
31 * import declarations.
32 *
33 * <ul><pre>
34 * import <i>class-name</i> by <i>assistant-name</i> [(<i>arg1, arg2, ...</i>)]
35 * </pre></ul>
36 *
37 * <p>To process this annotation, run this class as follows:
38 *
39 * <ul><pre>
40 * java javassist.preproc.Compiler sample.j
41 * </pre></ul>
42 *
43 * <p>This command produces <code>sample.java</code>, which only includes
44 * regular import declarations. Also, the Javassist program
45 * specified by <i>assistant-name</i> is executed so that it produces
46 * class files under the <code>./tmpjvst</code> directory. The class
47 * specified by <i>assistant-name</i> must implement
48 * <code>javassist.preproc.Assistant</code>.
49 *
50 * @see javassist.preproc.Assistant
51 */
52
53 public class Compiler {
54 protected BufferedReader input;
55 protected BufferedWriter output;
56 protected ClassPool classPool;
57
58 /**
59 * Constructs a <code>Compiler</code> with a source file.
60 *
61 * @param inputname the name of the source file.
62 */
63 public Compiler(String inputname) throws CannotCompileException {
64 try {
65 input = new BufferedReader(new FileReader(inputname));
66 } catch (IOException e) {
67 throw new CannotCompileException("cannot open: " + inputname);
68 }
69
70 String outputname = getOutputFilename(inputname);
71 if (outputname.equals(inputname))
72 throw new CannotCompileException("invalid source name: "
73 + inputname);
74
75 try {
76 output = new BufferedWriter(new FileWriter(outputname));
77 } catch (IOException e) {
78 throw new CannotCompileException("cannot open: " + outputname);
79 }
80
81 classPool = ClassPool.getDefault();
82 }
83
84 /**
85 * Starts preprocessing.
86 */
87 public void process() throws IOException, CannotCompileException {
88 int c;
89 CommentSkipper reader = new CommentSkipper(input, output);
90 while ((c = reader.read()) != -1) {
91 output.write(c);
92 if (c == 'p') {
93 if (skipPackage(reader))
94 break;
95 } else if (c == 'i')
96 readImport(reader);
97 else if (c != ' ' && c != '\t' && c != '\n' && c != '\r')
98 break;
99 }
100
101 while ((c = input.read()) != -1)
102 output.write(c);
103
104 input.close();
105 output.close();
106 }
107
108 private boolean skipPackage(CommentSkipper reader) throws IOException {
109 int c;
110 c = reader.read();
111 output.write(c);
112 if (c != 'a')
113 return true;
114
115 while ((c = reader.read()) != -1) {
116 output.write(c);
117 if (c == ';')
118 break;
119 }
120
121 return false;
122 }
123
124 private void readImport(CommentSkipper reader)
125 throws IOException, CannotCompileException {
126 int word[] = new int[5];
127 int c;
128 for (int i = 0; i < 5; ++i) {
129 word[i] = reader.read();
130 output.write(word[i]);
131 }
132
133 if (word[0] != 'm' || word[1] != 'p' || word[2] != 'o'
134 || word[3] != 'r' || word[4] != 't')
135 return; // syntax error?
136
137 c = skipSpaces(reader, ' ');
138 StringBuffer classbuf = new StringBuffer();
139 while (c != ' ' && c != '\t' && c != '\n' && c != '\r'
140 && c != ';' && c != -1) {
141 classbuf.append((char) c);
142 c = reader.read();
143 }
144
145 String importclass = classbuf.toString();
146 c = skipSpaces(reader, c);
147 if (c == ';') {
148 output.write(importclass);
149 output.write(';');
150 return;
151 }
152 if (c != 'b')
153 syntaxError(importclass);
154
155 reader.read(); // skip 'y'
156
157 StringBuffer assistant = new StringBuffer();
158 Vector args = new Vector();
159 c = readAssistant(reader, importclass, assistant, args);
160 c = skipSpaces(reader, c);
161 if (c != ';')
162 syntaxError(importclass);
163
164 runAssistant(importclass, assistant.toString(), args);
165 }
166
167 void syntaxError(String importclass) throws CannotCompileException {
168 throw new CannotCompileException("Syntax error. Cannot import "
169 + importclass);
170 }
171
172 int readAssistant(CommentSkipper reader, String importclass,
173 StringBuffer assistant, Vector args)
174 throws IOException, CannotCompileException {
175 int c = readArgument(reader, assistant);
176 c = skipSpaces(reader, c);
177 if (c == '(') {
178 do {
179 StringBuffer arg = new StringBuffer();
180 c = readArgument(reader, arg);
181 args.addElement(arg.toString());
182 c = skipSpaces(reader, c);
183 } while (c == ',');
184
185 if (c != ')')
186 syntaxError(importclass);
187
188 return reader.read();
189 }
190
191 return c;
192 }
193
194 int readArgument(CommentSkipper reader, StringBuffer buf)
195 throws IOException {
196 int c = skipSpaces(reader, ' ');
197 while ('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
198 || '0' <= c && c <= '9' || c == '.' || c == '_') {
199 buf.append((char) c);
200 c = reader.read();
201 }
202
203 return c;
204 }
205
206 int skipSpaces(CommentSkipper reader, int c) throws IOException {
207 while (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
208 if (c == '\n' || c == '\r')
209 output.write(c);
210
211 c = reader.read();
212 }
213
214 return c;
215 }
216
217 /**
218 * Is invoked if this compiler encoutenrs:
219 *
220 * <ul><pre>
221 * import <i>class name</i> by <i>assistant</i> (<i>args1</i>, <i>args2</i>, ...);
222 * </pre></ul>
223 *
224 * @param classname class name
225 * @param assistantname assistant
226 * @param argv args1, args2, ...
227 */
228 private void runAssistant(String importname, String assistantname,
229 Vector argv)
230 throws IOException, CannotCompileException {
231 Class assistant;
232 Assistant a;
233 int s = argv.size();
234 String[] args = new String[s];
235 for (int i = 0; i < s; ++i)
236 args[i] = (String) argv.elementAt(i);
237
238 try {
239 assistant = Class.forName(assistantname);
240 } catch (ClassNotFoundException e) {
241 throw new CannotCompileException("Cannot find " + assistantname);
242 }
243
244 try {
245 a = (Assistant) assistant.newInstance();
246 } catch (Exception e) {
247 throw new CannotCompileException(e);
248 }
249
250 CtClass[] imports = a.assist(classPool, importname, args);
251 s = imports.length;
252 if (s < 1)
253 output.write(" java.lang.Object;");
254 else {
255 output.write(' ');
256 output.write(imports[0].getName());
257 output.write(';');
258 for (int i = 1; i < s; ++i) {
259 output.write(" import ");
260 output.write(imports[1].getName());
261 output.write(';');
262 }
263 }
264 }
265
266 private String getOutputFilename(String input) {
267 int i = input.lastIndexOf('.');
268 if (i < 0)
269 i = input.length();
270
271 return input.substring(0, i) + ".java";
272 }
273
274 public static void main(String[] args) {
275 if (args.length > 0)
276 try {
277 Compiler c = new Compiler(args[0]);
278 c.process();
279 } catch (IOException e) {
280 System.err.println(e);
281 } catch (CannotCompileException e) {
282 System.err.println(e);
283 }
284 else {
285 System.err.println("Javassist version " + CtClass.version);
286 System.err.println("No source file is specified.");
287 }
288 }
289 }
290
291 class CommentSkipper {
292 private BufferedReader input;
293 private BufferedWriter output;
294
295 public CommentSkipper(BufferedReader reader, BufferedWriter writer) {
296 input = reader;
297 output = writer;
298 }
299
300 public int read() throws IOException {
301 int c;
302 while ((c = input.read()) != -1)
303 if (c != '/')
304 return c;
305 else {
306 c = input.read();
307 if (c == '/')
308 skipCxxComments();
309 else if (c == '*')
310 skipCComments();
311 else
312 output.write('/');
313 }
314
315 return c;
316 }
317
318 private void skipCxxComments() throws IOException {
319 int c;
320 output.write("//");
321 while ((c = input.read()) != -1) {
322 output.write(c);
323 if (c == '\n' || c == '\r')
324 break;
325 }
326 }
327
328 private void skipCComments() throws IOException {
329 int c;
330 boolean star = false;
331 output.write("/*");
332 while ((c = input.read()) != -1) {
333 output.write(c);
334 if (c == '*')
335 star = true;
336 else if (star && c == '/')
337 break;
338 else
339 star = false;
340 }
341 }
342 }
343