Skip to content

Commit 0dc6c4e

Browse files
author
dlsmith
committed
DynamicJava: JLSTypeSystem improvements -- bug fix for looping recursion on type arguments; additional options for mimicking the behavior of javac. Also improved SourceChecker's ability to compare type systems.
git-svn-id: file:///tmp/test-svn/trunk@5140 fe72c1cf-3628-48e9-8b72-1c46755d3cff
1 parent 80debf5 commit 0dc6c4e

File tree

4 files changed

+486
-154
lines changed

4 files changed

+486
-154
lines changed

dynamicjava/lib/plt.jar

805 Bytes
Binary file not shown.

dynamicjava/src/edu/rice/cs/dynamicjava/sourcechecker/SourceChecker.java

Lines changed: 210 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,39 @@
77
import java.io.FileNotFoundException;
88
import java.io.FileReader;
99
import java.io.PrintWriter;
10+
import java.lang.reflect.Field;
1011
import java.util.ArrayList;
12+
import java.util.EnumSet;
13+
import java.util.HashSet;
14+
import java.util.Iterator;
15+
import java.util.LinkedHashMap;
1116
import java.util.LinkedHashSet;
1217
import java.util.List;
18+
import java.util.Map;
1319
import java.util.Set;
1420

1521
import koala.dynamicjava.interpreter.NodeProperties;
1622
import koala.dynamicjava.interpreter.error.ExecutionError;
1723
import koala.dynamicjava.parser.wrapper.JavaCCParser;
1824
import koala.dynamicjava.parser.wrapper.ParseError;
1925
import koala.dynamicjava.tree.CompilationUnit;
26+
import koala.dynamicjava.tree.IdentifierToken;
2027
import koala.dynamicjava.tree.Node;
2128
import koala.dynamicjava.tree.SourceInfo;
2229
import koala.dynamicjava.tree.TypeDeclaration;
2330
import koala.dynamicjava.tree.visitor.DepthFirstVisitor;
2431
import edu.rice.cs.dynamicjava.Options;
2532
import edu.rice.cs.dynamicjava.interpreter.*;
33+
import edu.rice.cs.dynamicjava.symbol.DJClass;
2634
import edu.rice.cs.dynamicjava.symbol.ExtendedTypeSystem;
35+
import edu.rice.cs.dynamicjava.symbol.Function;
2736
import edu.rice.cs.dynamicjava.symbol.JLSTypeSystem;
2837
import edu.rice.cs.dynamicjava.symbol.Library;
2938
import edu.rice.cs.dynamicjava.symbol.SymbolUtil;
3039
import edu.rice.cs.dynamicjava.symbol.TreeLibrary;
3140
import edu.rice.cs.dynamicjava.symbol.TypeSystem;
41+
import edu.rice.cs.dynamicjava.symbol.Variable;
42+
import edu.rice.cs.dynamicjava.symbol.type.Type;
3243
import edu.rice.cs.plt.collect.UnindexedRelation;
3344
import edu.rice.cs.plt.collect.Relation;
3445
import edu.rice.cs.plt.io.IOUtil;
@@ -39,20 +50,25 @@
3950
import edu.rice.cs.plt.reflect.PathClassLoader;
4051
import edu.rice.cs.plt.text.ArgumentParser;
4152
import edu.rice.cs.plt.text.TextUtil;
53+
import edu.rice.cs.plt.tuple.Option;
4254
import edu.rice.cs.plt.tuple.Pair;
4355

4456
public class SourceChecker {
4557

4658
private final Options _opt;
4759
private final boolean _quiet;
4860
private int _statusCount;
61+
private Iterable<CompilationUnit> _processed;
4962

5063
public SourceChecker(Options opt, boolean quiet) {
5164
_opt = opt;
5265
_quiet = quiet;
5366
_statusCount = 0;
67+
_processed = IterUtil.empty();
5468
}
5569

70+
public Iterable<CompilationUnit> processed() { return _processed; }
71+
5672
public void check(File... sources) throws InterpreterException {
5773
check(IterUtil.asIterable(sources), IterUtil.<File>empty());
5874
}
@@ -64,6 +80,7 @@ public void check(Iterable<? extends File> sources) throws InterpreterException
6480
public void check(Iterable<? extends File> sources, Iterable<? extends File> classPath)
6581
throws InterpreterException {
6682
Iterable<CompilationUnit> tree = parse(sources);
83+
_processed = IterUtil.compose(_processed, tree);
6784
TypeContext context = makeContext(tree, classPath);
6885
Relation<TypeDeclaration, ClassChecker> decls = extractDeclarations(tree, context);
6986
initializeClassSignatures(decls);
@@ -203,20 +220,6 @@ public void run(Node node) {
203220
return CompositeException.make(IterUtil.map(result, CheckerException.FACTORY));
204221
}
205222

206-
/**
207-
* Append the given prefix to all properties of the given AST (the root node and its children),
208-
* effectively hiding them so that the program can be re-processed.
209-
*/
210-
private static void archiveProperties(Node ast, final String prefix) {
211-
new DepthFirstVisitor() {
212-
public void run(Node node) {
213-
node.archiveProperties(prefix);
214-
super.run(node);
215-
}
216-
}.run(ast);
217-
}
218-
219-
220223
/**
221224
* A DepthFirstVisitor extension that recurs on Node-typed properties. Note that this may lead to
222225
* multiple invocations of the same node (because the properties are often used to create DAGs).
@@ -230,36 +233,216 @@ public void run(Node node) {
230233
if (NodeProperties.hasStatementTranslation(node)) { recur(NodeProperties.getTranslation(node)); }
231234
}
232235
}
236+
237+
private static final Map<String, Options> _options;
238+
static {
239+
_options = new LinkedHashMap<String, Options>();
240+
_options.put("jls", new Options() {
241+
@Override protected Thunk<? extends TypeSystem> typeSystemFactory() {
242+
TypeSystem result = new JLSTypeSystem(this);
243+
return LambdaUtil.valueLambda(result);
244+
}
245+
@Override public boolean enforceAllAccess() { return true; }
246+
@Override public boolean prohibitUncheckedCasts() { return false; }
247+
});
248+
_options.put("ext", new Options() {
249+
@Override protected Thunk<? extends TypeSystem> typeSystemFactory() {
250+
TypeSystem result = new ExtendedTypeSystem(this);
251+
return LambdaUtil.valueLambda(result);
252+
}
253+
@Override public boolean enforceAllAccess() { return true; }
254+
@Override public boolean prohibitUncheckedCasts() { return false; }
255+
});
256+
}
233257

234-
235-
236258
public static void main(String... args) {
259+
debug.logStart();
260+
237261
ArgumentParser argParser = new ArgumentParser();
238262
argParser.supportOption("classpath", "");
239263
argParser.supportAlias("cp", "classpath");
240-
argParser.supportOption("jls");
264+
argParser.supportOption("opt", 1);
241265
argParser.requireParams(1);
242266
final ArgumentParser.Result parsedArgs = argParser.parse(args);
243-
244-
Options opt = new Options() {
245-
@Override protected Thunk<? extends TypeSystem> typeSystemFactory() {
246-
TypeSystem result = parsedArgs.hasOption("jls") ? new JLSTypeSystem(this) : new ExtendedTypeSystem(this);
247-
return LambdaUtil.valueLambda(result);
248-
}
249-
@Override public boolean enforceAllAccess() { return true; }
250-
@Override public boolean prohibitUncheckedCasts() { return false; }
251-
};
252267
Iterable<File> cp = IOUtil.parsePath(parsedArgs.getUnaryOption("classpath"));
253268
Iterable<File> sources = IterUtil.map(parsedArgs.params(), IOUtil.FILE_FACTORY);
254269

270+
if (parsedArgs.hasOption("opt")) {
271+
Options opt = _options.get(parsedArgs.getUnaryOption("opt"));
272+
if (opt == null) { System.out.println("Unrecognized options name: " + parsedArgs.getUnaryOption("opt")); }
273+
else { processFiles(sources, cp, opt); }
274+
}
275+
276+
else {
277+
Iterator<String> optNames = _options.keySet().iterator();
278+
String canonicalName = optNames.next();
279+
Iterable<CompilationUnit> canonical = processFiles(sources, cp, _options.get(canonicalName));
280+
Map<String, Iterable<CompilationUnit>> others = new LinkedHashMap<String, Iterable<CompilationUnit>>();
281+
while (optNames.hasNext()) {
282+
String n = optNames.next();
283+
others.put(n, processFiles(sources, cp, _options.get(n)));
284+
}
285+
NodeDiff diff = new NodeDiff();
286+
for (Map.Entry<String, Iterable<CompilationUnit>> e : others.entrySet()) {
287+
diff.compare(canonicalName, canonical, e.getKey(), e.getValue());
288+
}
289+
}
290+
291+
debug.logEnd();
292+
}
293+
294+
295+
private static Iterable<CompilationUnit> processFiles(Iterable<File> sources, Iterable<File> cp, Options opt) {
296+
SourceChecker checker = new SourceChecker(opt, false);
255297
try {
256-
new SourceChecker(opt, false).check(sources, cp);
298+
checker.check(sources, cp);
257299
System.out.println("Completed checking successfully.");
258300
}
259301
catch (InterpreterException e) {
260302
debug.log(e);
261303
e.printUserMessage(new PrintWriter(System.out, true));
262304
}
305+
return checker.processed();
306+
}
307+
308+
309+
static class NodeDiff {
310+
311+
public void compare(String leftName, Iterable<CompilationUnit> left,
312+
String rightName, Iterable<CompilationUnit> right) {
313+
System.out.println("\n**********************************************************");
314+
System.out.println("Comparing " + leftName + " with " + rightName);
315+
System.out.println("**********************************************************");
316+
if (IterUtil.sizeOf(left) != IterUtil.sizeOf(right)) {
317+
System.out.println("Can't compare results: mismatched CompilationUnit lists");
318+
}
319+
else {
320+
for (Pair<CompilationUnit, CompilationUnit> p : IterUtil.zip(left, right)) {
321+
compare(p.first(), p.second());
322+
}
323+
}
324+
}
325+
326+
private void compare(Node left, Node right) {
327+
if (left.getClass().equals(right.getClass())) {
328+
Class<?> c = left.getClass();
329+
while (!c.equals(Node.class)) {
330+
compareDeclaredFields(c, left, right);
331+
c = c.getSuperclass();
332+
}
333+
}
334+
else {
335+
mismatch("Different node classes", left.getClass().getName(), left, right.getClass().getName(), right);
336+
}
337+
Field props;
338+
try { props = Node.class.getDeclaredField("properties"); }
339+
catch (NoSuchFieldException e) { throw new RuntimeException(e); }
340+
compareProperties((Map<?,?>) fieldValue(props, left), left, (Map<?,?>) fieldValue(props, right), right);
341+
}
342+
343+
private void compareDeclaredFields(Class<?> c, Node left, Node right) {
344+
for (Field f : c.getDeclaredFields()) {
345+
String name = "field " + c.getName() + "." + f.getName();
346+
compareObjects(name, fieldValue(f, left), left, fieldValue(f, right), right);
347+
}
348+
}
349+
350+
private void compareProperties(Map<?,?> leftProps, SourceInfo.Wrapper left,
351+
Map<?,?> rightProps, SourceInfo.Wrapper right) {
352+
Set<Object> keys = new HashSet<Object>(leftProps.keySet());
353+
keys.retainAll(rightProps.keySet());
354+
Set<Object> leftKeys = new HashSet<Object>(leftProps.keySet());
355+
leftKeys.removeAll(keys);
356+
Set<Object> rightKeys = new HashSet<Object>(rightProps.keySet());
357+
rightKeys.removeAll(keys);
358+
if (!leftKeys.isEmpty() || !rightKeys.isEmpty()) {
359+
mismatch("Extra properties", leftKeys.toString(), left, rightKeys.toString(), right);
360+
}
361+
for (Object k : keys) {
362+
compareObjects("property " + k, leftProps.get(k), left, rightProps.get(k), right);
363+
}
364+
}
365+
366+
private void compareObjects(String name, Object leftVal, SourceInfo.Wrapper left,
367+
Object rightVal, SourceInfo.Wrapper right) {
368+
369+
if (leftVal == null || rightVal == null) {
370+
if (leftVal != null || rightVal != null) {
371+
mismatch("Different " + name, ""+leftVal, left, ""+rightVal, right);
372+
}
373+
}
374+
375+
else if (leftVal instanceof IdentifierToken && rightVal instanceof IdentifierToken) {
376+
String leftName = ((IdentifierToken) leftVal).image();
377+
String rightName = ((IdentifierToken) rightVal).image();
378+
if (!leftName.equals(rightName)) {
379+
mismatch("Different " + name, leftName, left, rightName, right);
380+
}
381+
}
382+
383+
else if (leftVal instanceof Node && rightVal instanceof Node) {
384+
compare((Node) leftVal, (Node) rightVal);
385+
}
386+
387+
else if (leftVal instanceof List<?> && rightVal instanceof List<?>) {
388+
List<?> leftList = (List<?>) leftVal;
389+
List<?> rightList = (List<?>) rightVal;
390+
if (leftList.size() == rightList.size()) {
391+
for (Pair<Object, Object> p : IterUtil.zip(leftList, rightList)) {
392+
compareObjects("element of " + name, p.first(), left, p.second(), right);
393+
}
394+
}
395+
else {
396+
mismatch("Different lengths of " + name, ""+leftList.size(), left, ""+rightList.size(), right);
397+
}
398+
}
399+
400+
else if (leftVal instanceof Option<?> && rightVal instanceof Option<?>) {
401+
Option<?> leftOpt = (Option<?>) leftVal;
402+
Option<?> rightOpt = (Option<?>) rightVal;
403+
if (leftOpt.isSome() && rightOpt.isSome()) {
404+
compareObjects(name, leftOpt.unwrap(), left, rightOpt.unwrap(), right);
405+
}
406+
else if (!leftOpt.isNone() || !rightOpt.isNone()) {
407+
mismatch("Different " + name, leftVal.toString(), left, rightVal.toString(), right);
408+
}
409+
}
410+
411+
else if (supportedObject(leftVal) && supportedObject(rightVal)) {
412+
if (!leftVal.equals(rightVal)) {
413+
mismatch("Different " + name, leftVal.toString(), left, rightVal.toString(), right);
414+
}
415+
}
416+
417+
else {
418+
mismatch("Unsupported object type in " + name,
419+
leftVal.getClass().getName(), left, rightVal.getClass().getName(), right);
420+
}
421+
}
422+
423+
private boolean supportedObject(Object val) {
424+
return val instanceof String || val instanceof Number || val instanceof Boolean ||
425+
val instanceof Class<?> || val instanceof EnumSet<?> || val instanceof Enum<?> ||
426+
val instanceof DJClass || val instanceof Variable || val instanceof Function ||
427+
val instanceof Type;
428+
}
429+
430+
private Object fieldValue(Field f, Object receiver) {
431+
try { f.setAccessible(true); }
432+
catch (SecurityException e) { /* ignore -- we can't relax accessibility */ }
433+
try { return f.get(receiver); }
434+
catch (IllegalAccessException e) {
435+
throw new RuntimeException(e);
436+
}
437+
}
438+
439+
private void mismatch(String description, String leftData, SourceInfo.Wrapper left,
440+
String rightData, SourceInfo.Wrapper right) {
441+
System.out.println("*** " + description);
442+
System.out.println("Left (" + left.getSourceInfo() + "): " + leftData);
443+
System.out.println("Right (" + right.getSourceInfo() + "): " + rightData);
444+
}
445+
263446
}
264447

265448
}

0 commit comments

Comments
 (0)