package polyglot.visit;
import polyglot.main.*;
import polyglot.ast.*;
import polyglot.types.*;
import polyglot.util.*;
import java.io.*;
import java.util.*;
/**
* Visitor which serializes class objects and adds a field to the class
* containing the serialization.
*/
public class ClassSerializer extends NodeVisitor
{
protected TypeEncoder te;
protected ErrorQueue eq;
protected Date date;
protected TypeSystem ts;
protected NodeFactory nf;
protected Version ver;
public ClassSerializer(TypeSystem ts, NodeFactory nf, Date date, ErrorQueue eq, Version ver) {
this.ts = ts;
this.nf = nf;
this.te = new TypeEncoder( ts);
this.eq = eq;
this.date = date;
this.ver = ver;
}
public Node override(Node n) {
// Stop at class members. We only want to encode top-level classes.
if (n instanceof ClassMember && ! (n instanceof ClassDecl)) {
return n;
}
return null;
}
public Node leave(Node old, Node n, NodeVisitor v) {
if (! (n instanceof ClassDecl)) {
return n;
}
try {
ClassDecl cn = (ClassDecl) n;
ClassBody body = cn.body();
ParsedClassType ct = cn.type();
byte[] b;
// HACK: force class members to get created from lazy class
// initializer.
ct.superType();
ct.interfaces();
ct.memberClasses();
ct.constructors();
ct.methods();
ct.fields();
if (! (ct.isTopLevel() || ct.isMember())) {
return n;
}
/* Add the compiler version number. */
String suffix = ver.name();
// Check if we've already serialized.
if (ct.fieldNamed("jlc$CompilerVersion$" + suffix) != null ||
ct.fieldNamed("jlc$SourceLastModified$" + suffix) != null ||
ct.fieldNamed("jlc$ClassType$" + suffix) != null) {
eq.enqueue(ErrorInfo.SEMANTIC_ERROR,
"Cannot encode Polyglot type information " +
"more than once.");
return n;
}
Flags flags = Flags.PUBLIC.set(Flags.STATIC).set(Flags.FINAL);
FieldDecl f;
FieldInstance fi;
InitializerInstance ii;
/* Add the compiler version number. */
String version = ver.major() + "." +
ver.minor() + "." +
ver.patch_level();
Position pos = Position.COMPILER_GENERATED;
fi = ts.fieldInstance(pos, ct,
flags, ts.String(),
"jlc$CompilerVersion$" + suffix);
ii = ts.initializerInstance(pos, ct, Flags.STATIC);
f = nf.FieldDecl(fi.position(), fi.flags(),
nf.CanonicalTypeNode(fi.position(), fi.type()),
fi.name(),
nf.StringLit(pos, version).type(ts.String()));
f = f.fieldInstance(fi);
f = f.initializerInstance(ii);
body = body.addMember(f);
/* Add the date of the last source file modification. */
long time = date.getTime();
fi = ts.fieldInstance(pos, ct,
flags, ts.Long(),
"jlc$SourceLastModified$" + suffix);
ii = ts.initializerInstance(pos, ct, Flags.STATIC);
f = nf.FieldDecl(fi.position(), fi.flags(),
nf.CanonicalTypeNode(fi.position(), fi.type()),
fi.name(),
nf.IntLit(pos, IntLit.LONG, time).type(ts.Long()));
f = f.fieldInstance(fi);
f = f.initializerInstance(ii);
body = body.addMember(f);
/* Add the class type info. */
fi = ts.fieldInstance(pos, ct,
flags, ts.String(),
"jlc$ClassType$" + suffix);
ii = ts.initializerInstance(pos, ct, Flags.STATIC);
f = nf.FieldDecl(fi.position(), fi.flags(),
nf.CanonicalTypeNode(fi.position(), fi.type()),
fi.name(),
nf.StringLit(pos, te.encode(ct)).type(ts.String()));
f = f.fieldInstance(fi);
f = f.initializerInstance(ii);
body = body.addMember(f);
return cn.body(body);
}
catch (IOException e) {
if (Report.should_report(Report.serialize, 1))
e.printStackTrace();
eq.enqueue(ErrorInfo.IO_ERROR,
"Unable to encode Polyglot type information.");
return n;
}
}
}