package org.rascalmpl.library.experiments.Compiler.RVM.Interpreter;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import org.rascalmpl.interpreter.types.FunctionType;
import org.rascalmpl.interpreter.types.NonTerminalType;
import org.rascalmpl.interpreter.types.OverloadedFunctionType;
import org.rascalmpl.interpreter.types.RascalTypeFactory;
import org.rascalmpl.interpreter.types.ReifiedType;
import org.rascalmpl.value.IConstructor;
import org.rascalmpl.value.IValueFactory;
import org.rascalmpl.value.type.ITypeVisitor;
import org.rascalmpl.value.type.Type;
import org.rascalmpl.value.type.TypeFactory;
import org.rascalmpl.value.type.TypeStore;
import org.rascalmpl.values.uptr.RascalValueFactory;
import org.nustaq.serialization.FSTBasicObjectSerializer;
import org.nustaq.serialization.FSTClazzInfo;
import org.nustaq.serialization.FSTClazzInfo.FSTFieldInfo;
import org.nustaq.serialization.FSTObjectInput;
import org.nustaq.serialization.FSTObjectOutput;
/**
* FSTSerializableType acts as a serializer and wrapper for Rascal Types.
* - On writing a FSTSerializableType oject is written
* - On reading, the wrapped Type is returned.
*/
enum TYPE {REAL, INT, RAT, LIST, MAP, MAP_NAMED_FIELDS, NUMBER, ALIAS, SET, LOC,STR, NODE, CONSTRUCTOR, CONSTRUCTOR_NAMED_FIELDS,
ADT, TUPLE, TUPLE_NAMED_FIELDS, VALUE,VOID,BOOL, PARAMETER, FUNCTION, REIFIED, OVERLOADED, NONTERMINAL, DATETIME};
public class FSTSerializableType extends FSTBasicObjectSerializer implements Serializable {
private static final long serialVersionUID = 5122014003014853428L;
private static transient TypeStore store;
private static transient TypeFactory tf;
private static transient RascalTypeFactory rtf;
public static void initSerialization(IValueFactory vfactory, TypeStore ts){
store = ts;
store.extendStore(RascalValueFactory.getStore());
tf = TypeFactory.getInstance();
rtf = RascalTypeFactory.getInstance();
}
private transient Type type;
FSTSerializableType(Type t){
this.type = t;
}
public FSTSerializableType() {
}
public Type getType(){
return type;
}
private void writeType(final FSTObjectOutput out, Type t) throws IOException{
out.writeObject(new FSTSerializableType(t));
}
@Override
public void writeObject(final FSTObjectOutput out, Object toWrite,
FSTClazzInfo arg2, FSTFieldInfo arg3, int arg4)
throws IOException {
Type t = ((FSTSerializableType) toWrite).getType();
t.accept(new ITypeVisitor<Void,IOException>() {
// Atomic types
@Override
public Void visitBool(Type type) throws IOException {
out.writeObject(TYPE.BOOL);
return null;
}
@Override
public Void visitDateTime(Type type) throws IOException {
out.writeObject(TYPE.DATETIME);
return null;
}
@Override
public Void visitInteger(Type type) throws IOException {
out.writeObject(TYPE.INT);
return null;
}
@Override
public Void visitNode(Type type) throws IOException {
out.writeObject(TYPE.NODE);
return null;
}
@Override
public Void visitNumber(Type type) throws IOException {
out.writeObject(TYPE.NUMBER);
return null;
}
@Override
public Void visitRational(Type type) throws IOException {
out.writeObject(TYPE.RAT);
return null;
}
@Override
public Void visitReal(Type type) throws IOException {
out.writeObject(TYPE.REAL);
return null;
}
@Override
public Void visitSourceLocation(Type type) throws IOException {
out.writeObject(TYPE.LOC);
return null;
}
@Override
public Void visitString(Type type) throws IOException {
out.writeObject(TYPE.STR);
return null;
}
@Override
public Void visitValue(Type type) throws IOException {
out.writeObject(TYPE.VALUE);
return null;
}
@Override
public Void visitVoid(Type type) throws IOException {
out.writeObject(TYPE.VOID);
return null;
}
// Composite types
@Override
public Void visitAbstractData(Type type) throws IOException {
out.writeObject(TYPE.ADT);
out.writeObject(type.getName());
Type typeParameters = type.getTypeParameters();
writeType(out, typeParameters);
return null;
}
@Override
public Void visitAlias(Type type) throws IOException {
out.writeObject(TYPE.ALIAS);
out.writeObject(type.getName());
writeType(out, type.getAliased());
writeType(out, type.getTypeParameters());
return null;
}
@Override
public Void visitConstructor(Type type) throws IOException {
String[] fieldNames = type.getFieldNames();
if(fieldNames == null){
out.writeObject(TYPE.CONSTRUCTOR);
} else {
out.writeObject(TYPE.CONSTRUCTOR_NAMED_FIELDS);
out.writeObject(fieldNames);
}
out.writeObject(type.getName());
int arity = type.getArity();
out.writeObject(arity);
writeType(out, type.getAbstractDataType());
Type elemType = type.getFieldTypes();
for(int i = 0; i < arity; i++){
writeType(out, elemType.getFieldType(i));
}
return null;
}
@Override
public Void visitExternal(Type type) throws IOException {
if(type instanceof FunctionType){
FunctionType ft = (FunctionType) type;
out.writeObject(TYPE.FUNCTION);
writeType(out, ft.getReturnType());
writeType(out, ft.getArgumentTypes());
writeType(out, ft.getKeywordParameterTypes());
} else if(type instanceof ReifiedType){
//System.out.println("writeType: " + type);
ReifiedType rt = (ReifiedType) type;
out.writeObject(TYPE.REIFIED);
Type elemType = rt.getTypeParameters(); // TODO ok?
writeType(out, elemType);
} else if(type instanceof OverloadedFunctionType){
out.writeObject(TYPE.OVERLOADED);
Set<FunctionType> alternatives = ((OverloadedFunctionType) type).getAlternatives();
out.writeObject(alternatives.size());
for(FunctionType ft : alternatives){
writeType(out, ft);
}
} else if(type instanceof NonTerminalType){
out.writeObject(TYPE.NONTERMINAL);
NonTerminalType nt = (NonTerminalType) type;
IConstructor cons = nt.getSymbol();
out.writeObject(new FSTSerializableIValue(cons));
} else {
throw new RuntimeException("External type not supported: " + type);
}
return null;
}
@Override
public Void visitList(Type type) throws IOException {
out.writeObject(TYPE.LIST);
writeType(out, type.getElementType());
return null;
}
@Override
public Void visitMap(Type type) throws IOException {
String keyLabel = type.getKeyLabel();
String valLabel = type.getValueLabel();
if(keyLabel == null && valLabel == null){
out.writeObject(TYPE.MAP);
} else {
out.writeObject(TYPE.MAP_NAMED_FIELDS);
out.writeObject(keyLabel);
out.writeObject(valLabel);
}
writeType(out, type.getKeyType());
writeType(out, type.getValueType());
return null;
}
@Override
public Void visitParameter(Type type) throws IOException {
out.writeObject(TYPE.PARAMETER);
out.writeObject(type.getName());
writeType(out, type.getBound());
return null;
}
@Override
public Void visitSet(Type type) throws IOException {
out.writeObject(TYPE.SET);
writeType(out, type.getElementType());
return null;
}
@Override
public Void visitTuple(Type type) throws IOException {
String[] fieldNames = type.getFieldNames();
if(fieldNames == null){
out.writeObject(TYPE.TUPLE);
} else {
out.writeObject(TYPE.TUPLE_NAMED_FIELDS);
out.writeObject(fieldNames);
}
int arity = type.getArity();
out.writeObject(arity);
for(int i = 0; i < arity; i++){
writeType(out, type.getFieldType(i));
}
return null;
}
});
}
public void readObject(FSTObjectInput in, Object toRead, FSTClazzInfo clzInfo, FSTClazzInfo.FSTFieldInfo referencedBy)
{
}
public Object instantiate(@SuppressWarnings("rawtypes") Class objectClass, final FSTObjectInput in, FSTClazzInfo serializationInfo, FSTClazzInfo.FSTFieldInfo referencee, int streamPosition) throws ClassNotFoundException, IOException
{
Type t = readType(in);
return t;
}
@SuppressWarnings("deprecation")
private Type readType(final FSTObjectInput in) throws ClassNotFoundException, IOException{
Object o = in.readObject();
if(o instanceof Type){
return (Type) o;
}
TYPE start = (TYPE) o;
String [] fieldNames = null;
String keyLabel = null;
String valLabel = null;
String name;
Type typeParameters;
int arity;
Type elemType;
switch(start){
// Atomic types
case BOOL: return tf.boolType();
case DATETIME: return tf.dateTimeType();
case INT: return tf.integerType();
case NODE: return tf.nodeType();
case NUMBER: return tf.numberType();
case RAT: return tf.rationalType();
case REAL: return tf.realType();
case LOC: return tf.sourceLocationType();
case STR: return tf.stringType();
case VALUE: return tf.valueType();
case VOID: return tf.voidType();
// Composite types
case ADT: name = (String) in.readObject();
typeParameters = readType(in);
arity = typeParameters.getArity();
if(arity > 0){
Type targs[] = new Type[arity];
for(int i = 0; i < arity; i++){
targs[i] = typeParameters.getFieldType(i);
}
return tf.abstractDataType(store, name, targs);
}
return tf.abstractDataType(store, name);
case ALIAS: name = (String) in.readObject();
Type aliasedType = readType(in);
typeParameters = readType(in);
return tf.aliasType(store, name, aliasedType, typeParameters);
case CONSTRUCTOR_NAMED_FIELDS:
fieldNames = (String[]) in.readObject();
// fall through to "constructor" case
case CONSTRUCTOR:
name = (String) in.readObject();
arity = (Integer) in.readObject();
Type adtType = readType(in);
Type declaredAdt = store.lookupAbstractDataType(name);
if(declaredAdt != null){
adtType = declaredAdt;
}
Type fieldTypes[] = new Type[arity];
for(int i = 0; i < arity; i++){
fieldTypes[i] = readType(in);
}
if(fieldNames == null){
Type res = store.lookupConstructor(adtType, name, tf.tupleType(fieldTypes));
if(res == null) {
return tf.constructor(store, adtType, name, fieldTypes);
} else {
return res;
}
}
Object[] typeAndNames = new Object[2*arity];
for(int i = 0; i < arity; i++){
typeAndNames[2 * i] = fieldTypes[i];
typeAndNames[2 * i + 1] = fieldNames[i];
}
Type res = store.lookupConstructor(adtType, name, tf.tupleType(typeAndNames));
if(res == null){
return tf.constructor(store, adtType, name, typeAndNames);
} else {
return res;
}
// External
case FUNCTION: Type returnType = readType(in);
Type argumentTypes = readType(in);
Type keywordParameterTypes = readType(in);
return rtf.functionType(returnType, argumentTypes, keywordParameterTypes);
case REIFIED: elemType = readType(in);
elemType = elemType.getFieldType(0);
res = rtf.reifiedType(elemType);
return res;
case OVERLOADED:
int n = (Integer) in.readObject();
Set<FunctionType> alternatives = new HashSet<FunctionType>(n);
for(int i = 0; i < n; i++){
alternatives.add((FunctionType)in.readObject());
}
return rtf.overloadedFunctionType(alternatives);
case NONTERMINAL:
IConstructor nt = (IConstructor) in.readObject();
return rtf.nonTerminalType(nt);
case LIST: elemType = readType(in);
return tf.listType(elemType);
case MAP_NAMED_FIELDS:
keyLabel = (String) in.readObject();
valLabel = (String) in.readObject();
// fall through to "map" case
case MAP: Type keyType = readType(in);
Type valType = readType(in);
if(keyLabel == null){
return tf.mapType(keyType, valType);
}
return tf.mapType(keyType, keyLabel, valType, valLabel);
case PARAMETER: name = (String) in.readObject();
Type bound = readType(in);
return tf.parameterType(name, bound);
case SET: elemType = readType(in);
return tf.setType(elemType);
case TUPLE_NAMED_FIELDS:
fieldNames = (String[]) in.readObject();
// fall through to "tuple" case
case TUPLE: arity = (Integer) in.readObject();
Type[] elemTypes = new Type[arity];
for(int i = 0; i < arity; i++){
elemTypes[i] = readType(in);
}
if(fieldNames != null){
return tf.tupleType(elemTypes, fieldNames);
}
return tf.tupleType(elemTypes);
}
throw new RuntimeException("readType: unhandled case " + start);
}
}