FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

JavaxToolsCompiler is compiling and running! · hispangle/drjava@08c6e04 · GitHub

Repository navigation

Commit 08c6e04

Browse files
committed
JavaxToolsCompiler is compiling and running!
1 parent 20e0eaf commit 08c6e04

1 file changed

Lines changed: 252 additions & 2 deletions

File tree

‎drjava/src/edu/rice/cs/drjava/model/compiler/JavaxToolsCompiler.java‎

Lines changed: 252 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,26 @@
33
import edu.rice.cs.drjava.model.DJError;
44
import edu.rice.cs.drjava.ui.SmartSourceFilter;
55
import edu.rice.cs.plt.reflect.JavaVersion;
6+
import edu.rice.cs.util.ArgumentTokenizer;
7+
68
import javax.swing.filechooser.FileFilter;
79
import java.io.File;
810
import java.io.IOException;
11+
import java.lang.reflect.Constructor;
912
import java.util.*;
1013
import javax.tools.*;
1114

12-
public class JavaxToolsCompiler implements CompilerInterface {
1315

16+
17+
public class JavaxToolsCompiler implements CompilerInterface {
18+
/** The set of class names that are run as ACM Java Task Force library programs. */
19+
protected static final Set<String> ACM_PROGRAM_CLASSES = new HashSet<String>();
20+
static {
21+
Collections.addAll(ACM_PROGRAM_CLASSES, new String[] {
22+
"acm.program.Program",
23+
"acm.graphics.GTurtle"
24+
});
25+
}
1426
private final JavaCompiler compiler;
1527

1628
public JavaxToolsCompiler() {
@@ -119,11 +131,249 @@ public List<File> additionalBootClassPathForInteractions() {
119131
return new ArrayList<File>();
120132
}
121133

134+
/** Transform the command line to be interpreted into something the Interactions JVM can use.
135+
* This replaces "java MyClass a b c" with Java code to call MyClass.main(new String[]{"a","b","c"}).
136+
* "import MyClass" is not handled here.
137+
* transformCommands should support at least "run", "java" and "applet".
138+
* @param interactionsString unprocessed command line
139+
* @return command line with commands transformed */
122140
public String transformCommands(String interactionsString) {
123-
// TODO: Implement command transformation logic (this is for interpreter)
141+
if (interactionsString.startsWith("java ")) {
142+
interactionsString = transformJavaCommand(interactionsString);
143+
}
144+
else if (interactionsString.startsWith("applet ")) {
145+
interactionsString = transformAppletCommand(interactionsString);
146+
}
147+
else if (interactionsString.startsWith("run ")) {
148+
interactionsString = transformRunCommand(interactionsString);
149+
}
124150
return interactionsString;
125151
}
126152

153+
public static String transformJavaCommand(String s) {
154+
// check the return type and public access before executing, per bug #1585210
155+
String command =
156+
"try '{'\n" +
157+
" java.lang.reflect.Method m = {0}.class.getMethod(\"main\", java.lang.String[].class);\n" +
158+
" if (!m.getReturnType().equals(void.class)) throw new java.lang.NoSuchMethodException();\n" +
159+
"'}'\n" +
160+
"catch (java.lang.NoSuchMethodException e) '{'\n" +
161+
" throw new java.lang.NoSuchMethodError(\"main\");\n" +
162+
"'}'\n" +
163+
"{0}.main(new String[]'{'{1}'}');";
164+
return _transformCommand(s, command);
165+
}
166+
167+
public static String transformAppletCommand(String s) {
168+
return _transformCommand(s,"edu.rice.cs.plt.swing.SwingUtil.showApplet(new {0}({1}), 400, 300);");
169+
}
170+
171+
/** This method performs the "smart run". Unfortunately, we don't get the right static error messages.
172+
* @param s full command line, i.e. "run MyClass 1 2 3"
173+
* @param c class to be run, i.e. MyClass.class
174+
* @throws Throwable if something goes wrong
175+
*/
176+
public static void runCommand(String s, Class<?> c) throws Throwable {
177+
if (s.endsWith(";")) s = _deleteSemiColon(s);
178+
List<String> tokens = ArgumentTokenizer.tokenize(s, true);
179+
String[] args = new String[tokens.size() - 2];
180+
for (int i = 2; i < tokens.size(); i++) {
181+
String t = tokens.get(i);
182+
args[i - 2] = t.substring(1, t.length() - 1);
183+
}
184+
185+
boolean isProgram = false;
186+
boolean isApplet = false;
187+
Class<?> oldC = c;
188+
while(c != null) {
189+
if (ACM_PROGRAM_CLASSES.contains(c.getName())) { isProgram = true; break; }
190+
c = c.getSuperclass();
191+
}
192+
c = oldC;
193+
if (!isProgram) {
194+
try {
195+
// if this doesn't throw, c is a subclass of Applet
196+
c.asSubclass(java.applet.Applet.class);
197+
isApplet = true;
198+
} catch(ClassCastException cce) { }
199+
}
200+
201+
java.lang.reflect.Method m = null;
202+
if (isApplet) {
203+
try {
204+
m = c.getMethod("main", java.lang.String[].class);
205+
if (!m.getReturnType().equals(void.class)) { m = null; }
206+
}
207+
catch (java.lang.NoSuchMethodException e) { m = null; }
208+
if (m == null) {
209+
java.applet.Applet instance = null;
210+
if (args.length == 0) {
211+
try {
212+
// try default (nullary) constructor first
213+
Constructor<?> ctor = c.getConstructor();
214+
instance = java.applet.Applet.class.cast(ctor.newInstance());
215+
}
216+
catch(NoSuchMethodException | InstantiationException | IllegalAccessException nsme) {
217+
instance = null;
218+
}
219+
catch(java.lang.reflect.InvocationTargetException ite) {
220+
if (ite.getCause()!=null) {
221+
throw ite.getCause();
222+
}
223+
else {
224+
System.err.println("Error: Please turn off 'Smart Run' or use 'java' command instead of 'run'.");
225+
}
226+
}
227+
if (instance == null) {
228+
try {
229+
// try String[] constructor next
230+
Constructor<?> ctor = c.getConstructor(String[].class);
231+
instance = java.applet.Applet.class.cast(ctor.newInstance(new Object[] { new String[0] }));
232+
}
233+
catch(NoSuchMethodException | InstantiationException | IllegalAccessException nsme) {
234+
instance = null;
235+
}
236+
catch(java.lang.reflect.InvocationTargetException ite) {
237+
if (ite.getCause()!=null) {
238+
throw ite.getCause();
239+
}
240+
else {
241+
System.err.println("Error: Please turn off 'Smart Run' or use 'java' command instead of 'run'.");
242+
return;
243+
}
244+
}
245+
}
246+
if (instance == null) {
247+
System.err.println("Static Error: This applet does not have a default constructor or a constructor "+
248+
"accepting String[].");
249+
return;
250+
}
251+
}
252+
else {
253+
try {
254+
// try String[] constructor
255+
Constructor<?> ctor = c.getConstructor(String[].class);
256+
instance = java.applet.Applet.class.cast(ctor.newInstance(new Object[] { args }));
257+
}
258+
catch(NoSuchMethodException | InstantiationException | IllegalAccessException nsme) {
259+
instance = null;
260+
}
261+
catch(java.lang.reflect.InvocationTargetException ite) {
262+
if (ite.getCause()!=null) {
263+
throw ite.getCause();
264+
}
265+
else {
266+
System.err.println("Error: Please turn off 'Smart Run' or use 'java' command instead of 'run'.");
267+
return;
268+
}
269+
}
270+
if (instance == null) {
271+
System.err.println("Static Error: This applet does not have a constructor accepting String[].");
272+
return;
273+
}
274+
}
275+
edu.rice.cs.plt.swing.SwingUtil.showApplet(instance, 400, 300);
276+
}
277+
}
278+
else {
279+
try {
280+
m = c.getMethod("main", java.lang.String[].class);
281+
if (!m.getReturnType().equals(void.class)) {
282+
System.err.println("Static Error: This class does not have a static void main method accepting String[].");
283+
m = null;
284+
}
285+
}
286+
catch (java.lang.NoSuchMethodException e) {
287+
System.err.println("Static Error: This class does not have a static void main method accepting String[].");
288+
m = null;
289+
}
290+
}
291+
if (m != null) {
292+
if (isProgram) {
293+
String[] newArgs = new String[args.length+1];
294+
newArgs[0] = "code="+c.getName();
295+
System.arraycopy(args, 0, newArgs, 1, args.length);
296+
args = newArgs;
297+
}
298+
try {
299+
m.setAccessible(true);
300+
m.invoke(null, new Object[] { args });
301+
}
302+
catch(SecurityException | IllegalAccessException se) {
303+
System.err.println("Error: Please turn off 'Smart Run' or use 'java' command instead of 'run'.");
304+
}
305+
catch(java.lang.reflect.InvocationTargetException ite) {
306+
if (ite.getCause()!=null) {
307+
throw ite.getCause();
308+
}
309+
else {
310+
System.err.println("Error: Please turn off 'Smart Run' or use 'java' command instead of 'run'.");
311+
}
312+
}
313+
}
314+
}
315+
316+
/** This is a method that automatically detects if
317+
* a) the class is an ACM Java Task Force program (subclass of acm.program.Program)
318+
* b) an applet
319+
* c) a class with a static main method
320+
*
321+
* If a), then DrJava inserts "code=MyClass" as argument 0.
322+
* If b), then DrJava performs the same as "applet MyClass" (see above).
323+
* If c), then DrJava executes MyClass.main (traditional java behavior).
324+
*
325+
* @param s the command to be transformed
326+
* @return the transformed command
327+
*/
328+
public String transformRunCommand(String s) {
329+
if (s.endsWith(";")) s = _deleteSemiColon(s);
330+
List<String> args = ArgumentTokenizer.tokenize(s, true);
331+
final String classNameWithQuotes = args.get(1); // this is "MyClass"
332+
final String className =
333+
classNameWithQuotes.substring(1, classNameWithQuotes.length() - 1); // removes quotes, becomes MyClass
334+
335+
// we pass MyClass.class just to get a "Static Error: Undefined class 'MyClass'"
336+
String ret = JavacCompiler.class.getName()+".runCommand(\""+s.toString()+"\", "+className+".class)";
337+
// System.out.println(ret);
338+
return ret;
339+
}
340+
341+
/** Assumes a trimmed String. Returns a string of the call that the interpreter can use.
342+
* The arguments get formatted as comma-separated list of strings enclosed in quotes.
343+
* Example: _transformCommand("java MyClass arg1 arg2 arg3", "{0}.main(new String[]'{'{1}'}');")
344+
* returns "MyClass.main(new String[]{\"arg1\",\"arg2\",\"arg3\"});"
345+
* NOTE: the command to run is constructed using {@link java.text.MessageFormat}. That means that certain characters,
346+
* single quotes and curly braces, for example, are special. To write single quotes, you need to double them.
347+
* To write curly braces, you need to enclose them in single quotes. Example:
348+
* MessageFormat.format("Abc {0} ''foo'' '{'something'}'", "def") returns "Abc def 'foo' {something}".
349+
* @param s the command line, either "java MyApp arg1 arg2 arg3" or "applet MyApplet arg1 arg2 arg3"
350+
* @param command the command to execute, with {0} marking the place for the class name and {1} the place for the arguments
351+
* @return the transformed command
352+
*/
353+
protected static String _transformCommand(String s, String command) {
354+
if (s.endsWith(";")) s = _deleteSemiColon(s);
355+
List<String> args = ArgumentTokenizer.tokenize(s, true);
356+
final String classNameWithQuotes = args.get(1); // this is "MyClass"
357+
final String className = classNameWithQuotes.substring(1, classNameWithQuotes.length() - 1); // removes quotes, becomes MyClass
358+
final StringBuilder argsString = new StringBuilder();
359+
boolean seenArg = false;
360+
for (int i = 2; i < args.size(); i++) {
361+
if (seenArg) argsString.append(",");
362+
else seenArg = true;
363+
argsString.append(args.get(i));
364+
}
365+
return java.text.MessageFormat.format(command, className, argsString.toString());
366+
}
367+
368+
/** Deletes the last character of a string. Assumes semicolon at the end, but does not check. Helper
369+
* for _transformCommand(String,String).
370+
* @param s the String containing the semicolon
371+
* @return a substring of s with one less character
372+
*/
373+
protected static String _deleteSemiColon(String s) { return s.substring(0, s.length() - 1); }
374+
375+
376+
127377
public boolean isSourceFileForThisCompiler(File f) {
128378
if (f == null) return false;
129379
String fileName = f.getName();

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL