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