/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