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