/*
* This file is part of the X10 project (http://x10-lang.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* This file was originally derived from the Polyglot extensible compiler framework.
*
* (C) Copyright 2000-2007 Polyglot project group, Cornell University
* (C) Copyright IBM Corporation 2007-2012.
*/
package polyglot.util.typedump;
import polyglot.util.*;
import polyglot.types.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import x10.util.CollectionFactory;
class TypeDumper {
static Set<Class<?>> dontExpand;
static {
Class<?>[] primitiveLike = {
Void.class,
Boolean.class,
Short.class,
Integer.class,
Long.class,
Float.class,
Double.class,
Class.class,
String.class,
};
dontExpand =
CollectionFactory.newHashSet(java.util.Arrays.asList(primitiveLike));
}
TypeObject theType;
QName rawName;
String compilerVersion;
Date timestamp;
TypeDumper(QName rawName, TypeObject t, String compilerVersion,
Long timestamp) {
theType = t;
this.rawName = rawName;
this.compilerVersion = compilerVersion;
this.timestamp = new Date(timestamp.longValue());
}
public static TypeDumper load(QName name, TypeSystem ts)
throws ClassNotFoundException, NoSuchFieldException,
java.io.IOException, SecurityException
{
Class<?> c = Class.forName(name.toString());
try {
Field jlcVersion = c.getDeclaredField("jlc$CompilerVersion");
Field jlcTimestamp = c.getDeclaredField("jlc$SourceLastModified");
Field jlcType = c.getDeclaredField("jlc$ClassType");
String t = (String)jlcType.get(null);
TypeEncoder te = new TypeEncoder(ts);
return new TypeDumper(name,
te.decode(t, name),
(String)jlcVersion.get(null),
(Long)jlcTimestamp.get(null));
} catch (IllegalAccessException exn) {
throw new SecurityException("illegal access: "+exn.getMessage());
}
}
public void dump(CodeWriter w) {
Map<Object, Object> cache = CollectionFactory.newHashMap();
cache.put(theType, theType);
w.write("Type "+rawName+ " {");
w.allowBreak(2);
w.begin(0);
w.write("Compiled with polyglot version "+compilerVersion+". ");
w.allowBreak(0);
w.write("Last modified: "+timestamp.toString()+". ");
w.allowBreak(0);
w.write(theType.toString());
w.allowBreak(4);
w.write("<"+
theType.getClass().toString()+">");
w.allowBreak(0);
dumpObject(w, theType, cache);
w.allowBreak(0);
w.end();
w.allowBreak(0);
w.write("}");
w.newline(0);
}
protected void dumpObject(CodeWriter w, Object obj, Map<Object, Object> cache) {
w.write(" fields {");
w.allowBreak(2);
w.begin(0);
try {
Field[] declaredFields =
obj.getClass().getDeclaredFields();
java.lang.reflect.AccessibleObject.setAccessible(declaredFields,
true);
for (int i = 0; i < declaredFields.length; i++) {
if (Modifier.isStatic(declaredFields[i].getModifiers()))
continue;
w.begin(4);
w.write(declaredFields[i].getName()+": ");
w.allowBreak(0);
try {
Object o = declaredFields[i].get(obj);
if (o != null) {
Class<? extends Object> rtType = o.getClass();
w.write("<"+rtType.toString()+">:");
w.allowBreak(0);
w.write(o.toString());
w.allowBreak(4);
if (!Object.class.equals(rtType) &&
!dontDump(rtType) &&
!rtType.isArray() &&
!(cache.containsKey(o) &&
cache.get(o) == o)) {
cache.put(o, o);
dumpObject(w, o, cache);
}
} else {
w.write("null");
}
} catch (IllegalAccessException exn) {
w.write("##["+exn.getMessage()+"]");
}
w.end();
w.allowBreak(0);
}
} catch (SecurityException exn) {
} finally {
w.end();
w.allowBreak(0);
w.write("}");
}
}
static boolean dontDump(Class<?> c) {
return dontExpand.contains(c);
}
}