Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: mijava/JavaCompiler.java


1   /*
2     @(#) $Id: JavaCompiler.java,v 1.16 2002/03/27 18:50:29 hobb0001 Exp $
3     Copyright 2002 Michael Hobbs
4   
5     This file is part of MIJava.
6   
7     MIJava is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11  
12    MIJava is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16  
17    You should have received a copy of the GNU General Public License
18    along with MIJava; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21  
22  package mijava;
23  
24  import java.io.InputStream;
25  import java.io.PrintStream;
26  import java.io.File;
27  import java.io.IOException;
28  import java.util.Collection;
29  import java.util.Map;
30  import java.util.Iterator;
31  import java.util.HashMap;
32  import java.util.regex.Pattern;
33  import java.util.regex.Matcher;
34  
35  
36  
37  class JavaCompiler
38  {
39    public static final class FileInfo
40    {
41      private final String givenFileName;
42      private final String tempFileName;
43      private final DiffString contents;
44      private final int type;
45      public final static int TYPE_NORMAL_CLASS = 0;
46      public final static int TYPE_MICLASS_INTERFACE = 1;
47      public final static int TYPE_EMPTY_CLASS = 2;
48      public final static int TYPE_MICLASS = 3;
49      public final static int TYPE_ERROR_FILE = 4;
50      public FileInfo
51        (String givenFileName, String tempFileName, DiffString contents, 
52         int type)
53      {
54        this.givenFileName = givenFileName;
55        this.tempFileName = tempFileName;
56        this.contents = contents;
57        this.type = type;
58      }
59    }
60  
61    public static void compile
62      (Collection compilerFlags, Collection files, File buildDir,
63       MIJavaCompiler.Result result)
64      throws IOException
65    {
66      if (files.size() == 0) return;
67      StringBuffer command = new StringBuffer("javac");
68      for (Iterator i=compilerFlags.iterator(); i.hasNext(); ) {
69        String flag = (String) i.next();
70        command.append(" " + flag);
71      }
72      command.append(" " + MIJava.getClassPathArgs());
73      command.append(" -d " + buildDir.getCanonicalPath());
74      Map fileNameInfoMap = new HashMap();
75      for (Iterator i=files.iterator(); i.hasNext(); ) {
76        FileInfo fileInfo = (FileInfo) i.next();
77        command.append(" " + fileInfo.tempFileName);
78        fileNameInfoMap.put(fileInfo.tempFileName, fileInfo);
79      }    
80      Process javac = Runtime.getRuntime().exec(command.toString());    
81      ConvertOutput convertStdOut = 
82        new ConvertOutput(javac.getInputStream(), System.out, fileNameInfoMap,
83                          result);
84      ConvertOutput convertStdErr = 
85        new ConvertOutput(javac.getErrorStream(), System.err, fileNameInfoMap,
86                          result);
87      try {
88        javac.waitFor();
89        convertStdOut.print();
90        convertStdErr.print();
91      } catch (InterruptedException e) {
92        result.success = false;
93        javac.destroy();
94      }
95    }
96  
97    private static final class ConvertOutput
98    {
99      private static final String EOL =
100       "(?:\\r\\n|\\r|\\n|\\u0085|\\u2028|\\u2029)";
101     private static final Pattern errStmtP = Pattern.compile
102       ("(.+?):([0-9]+): (.*)" + EOL +
103        "(?:symbol  : (.*)" + EOL +
104        "location: (.*)" + EOL + ")?" +
105        "(?:found   : .*" + EOL +
106        "required: .*" + EOL + ")?" +
107        "(.*)" + EOL +
108        "( *\\^)" + EOL);
109     private static final String javaLetter = "[$_A-Za-z]";
110     private static final String javaDigit = "[0-9]";
111     private static final String identifier = 
112       "(?:" + javaLetter + "(?:" + javaLetter + "|" + javaDigit + ")*)";
113     private static final Pattern miClassNameP =
114       Pattern.compile("(?<=\\s|\\.)\\$(" + identifier + ")");
115 
116     private final InputStream in;
117     private final PrintStream out;
118     // Map(String [fileName], FileInfo)
119     private final Map fileNameInfoMap;
120     private final MIJavaCompiler.Result compileResult;
121 
122     public ConvertOutput
123       (InputStream in, PrintStream out, Map fileNameInfoMap,
124        MIJavaCompiler.Result compileResult)
125     {
126       this.in = in;
127       this.out = out;
128       this.fileNameInfoMap = fileNameInfoMap;
129       this.compileResult = compileResult;
130     }
131 
132     public void print()
133       throws IOException
134     {
135       StringBuffer outputBuffer = new StringBuffer();
136       byte[] buffer = new byte[4096];
137       for (;;) {
138         int bytesRead = in.read(buffer);
139         if (bytesRead <= 0) break;
140         String output = new String(buffer, 0, bytesRead);
141         compileResult.appendJavaCompilerOutput(output);
142         outputBuffer.append(output);
143         for (;;) {
144           Matcher matcher = errStmtP.matcher(outputBuffer);
145           if (!matcher.lookingAt()) break;
146           CharSequence orig = convertToOrig(matcher);
147           if (orig != null && orig.length() > 0) {
148             compileResult.incrementErrorCount();
149             compileResult.appendOutput(orig);
150             out.print(orig);
151           }
152           outputBuffer.delete(0, matcher.end());
153         }
154       }
155       in.close();
156     }
157 
158     private CharSequence convertToOrig(Matcher m)
159     {
160       CharSequence result;
161       result = convertExtendClass(m);
162       if (result != null) return result;
163       result = convertUnresolvedSymbols(m);
164       if (result != null) return result;
165       result = ignoreNonSyntaxErrors(m);
166       if (result != null) return result;
167       return defaultConvert(m, false, null);
168     }    
169 
170     private CharSequence convertExtendClass(Matcher m)
171     {
172       String message = m.group(3);
173       if (!message.equals("interface expected here")) return null;
174       return defaultConvert(m, false, 
175                             "a miclass can only extend another miclass");
176     }
177 
178     private CharSequence convertUnresolvedSymbols(Matcher m)
179     {
180       String message = m.group(3);
181       String symbol = m.group(4);
182       String location = m.group(5);
183       if (!message.equals("cannot resolve symbol") || 
184           symbol == null || location == null) {
185         return null;
186       }
187       return defaultConvert(m, true, null);
188     }
189 
190     private CharSequence ignoreNonSyntaxErrors(Matcher m)
191     {
192       String fileName = m.group(1);
193       FileInfo fileInfo = (FileInfo) fileNameInfoMap.get(fileName);
194       if (fileInfo == null || fileInfo.type != FileInfo.TYPE_ERROR_FILE) {
195         return null;
196       }
197       String message = m.group(3);
198       // Returning 'null' will cause the error to be displayed.
199       if (message.startsWith("unclosed")) return null;
200       if (message.indexOf("expected") >= 0) return null;
201       if (message.equals("illegal start of expression")) return null;
202       // Returning "" will cause the error to be skipped.
203       return "";
204     }
205 
206     private CharSequence defaultConvert
207       (Matcher m, boolean force, String alternateMessage)
208     {
209       DiffString errStmt = new DiffString(m.group());
210       String fileName = m.group(1);
211       String lineNum = m.group(2);
212       String line = m.group(6);
213       String pointer = m.group(7);
214       FileInfo fileInfo = (FileInfo) fileNameInfoMap.get(fileName);
215       if (fileInfo == null || fileInfo.contents == null) return "";
216       DiffString.LineInfo lineInfo = 
217         getOrigLineInfo(fileInfo.contents, Integer.parseInt(lineNum),
218                         toLineOffset(pointer), force);
219       if (lineInfo == null) return null;
220       errStmt.replace(m.start(1), m.end(1), fileInfo.givenFileName);
221       errStmt.replace(m.start(2), m.end(2), 
222                       Integer.toString(lineInfo.lineNumber));
223       if (alternateMessage != null) {
224         errStmt.replace(m.start(3), m.end(3), alternateMessage);
225       }
226       errStmt.replace(m.start(6), m.end(6), lineInfo.line);
227       errStmt.replace(m.start(7), m.end(7), toPointer(lineInfo.lineOffset));
228       if (fileInfo.type == FileInfo.TYPE_MICLASS_INTERFACE && 
229           m.group(5) != null) {
230         // Convert the word 'interface' that shows up in the "location:"
231         // to 'miclass', so as not to confuse the reader.
232         int idx = m.group(5).indexOf("interface");
233         if (idx >= 0) {
234           errStmt.replace(m.start(5) + idx, m.start(5) + idx + 9, "miclass");
235         }
236       }
237       // Convert mangled class names that show up in the error statements back
238       // to their original name.
239       Matcher matcher = miClassNameP.matcher(errStmt);
240       return matcher.replaceAll("$1");
241     }
242 
243     private static int toLineOffset(String pointer)
244     {
245       return pointer.indexOf('^');
246     }
247 
248     private static CharSequence toPointer(int lineOffset)
249     {
250       StringBuffer result = new StringBuffer();
251       for (int i=0; i<lineOffset; ++i) {
252         result.append(' ');
253       }
254       result.append('^');
255       return result;
256     }
257 
258     private static DiffString.LineInfo getOrigLineInfo
259       (DiffString ds, int valueLineNumber, int valueLineOffset, boolean force)
260     {
261       DiffString.LineInfo lineInfo = 
262         ds.getOrigLineInfo(valueLineNumber, valueLineOffset, force);
263       if (lineInfo == null) return null;
264       CharSequence orig = ds.getOriginal();
265       if (orig instanceof DiffString) {
266         return getOrigLineInfo((DiffString) orig, lineInfo.lineNumber,
267                                lineInfo.lineOffset, force);
268       }
269       return lineInfo;
270     }
271 
272   }
273 
274   private static final String _ID_ =
275     "@(#) $Id: JavaCompiler.java,v 1.16 2002/03/27 18:50:29 hobb0001 Exp $";
276 } 
277 
278