blob: 717c8f38237dae05a4885cd27a2f0114c2cca7ec [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 University of Illinois at Urbana-Champaign and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* UIUC - Initial API and implementation
*******************************************************************************/
package org.eclipse.photran.internal.core.analysis.types;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.photran.internal.core.analysis.binding.Definition;
import org.eclipse.photran.internal.core.parser.ASTTypeSpecNode;
import org.eclipse.photran.internal.core.vpg.IPhotranSerializable;
import org.eclipse.photran.internal.core.vpg.PhotranVPGSerializer;
/**
* Represents the type of a Fortran expression or variable.
* <p>
* Does not include any information about kinds or character lengths. Does not include any
* information about array indexing; that is stored in the variable's {@link Definition}.
*
* @author Jeff Overbey
*/
@SuppressWarnings("serial")
public abstract class Type implements IPhotranSerializable, Serializable
{
private static final long serialVersionUID = 1L;
// ***WARNING*** If any fields change, the serialization methods (below) must also change!
@Override public abstract String toString();
public abstract String getThreeLetterTypeSerializationCode();
abstract void finishWriteTo(OutputStream out) throws IOException;
public abstract <T> T processUsing(TypeProcessor<T> p);
public Type getCommonType(Type another)
{
return this.equals(another) ? this : null;
}
@Override public boolean equals(Object other)
{
return other instanceof Type && ((Type)other).toString().equals(this.toString());
}
// # R502
// <TypeSpec> ::=
// T_INTEGER
// | T_REAL
// | T_DOUBLEPRECISION
// | T_COMPLEX
// | T_LOGICAL
// | T_CHARACTER
// | T_INTEGER <KindSelector>
// | T_REAL <KindSelector>
// | T_DOUBLE T_PRECISION
// | T_COMPLEX <KindSelector>
// | T_CHARACTER <CharSelector>
// | T_LOGICAL <KindSelector>
// | T_TYPE T_LPAREN <TypeName> T_RPAREN
public static Type parse(ASTTypeSpecNode node)
{
if (node.isInteger())
return Type.INTEGER;
else if (node.isReal())
return Type.REAL;
else if (node.isDouble())
return Type.DOUBLEPRECISION;
else if (node.isComplex())
return Type.COMPLEX;
else if (node.isDblComplex())
return Type.DOUBLECOMPLEX;
else if (node.isLogical())
return Type.LOGICAL;
else if (node.isCharacter())
return Type.CHARACTER;
else if (node.isDerivedType())
return node.getTypeName() == null ? new DerivedType("") : new DerivedType(node.getTypeName().getText()); //$NON-NLS-1$
else
throw new Error("Unexpected case parsing <TypeSpec> node"); //$NON-NLS-1$
}
private static abstract class PrimitiveType extends Type
{
@Override final void finishWriteTo(OutputStream out) throws IOException
{
// Nothing extra to write for primitive types
}
}
public static Type INTEGER = new PrimitiveType()
{
@Override public String toString()
{
return "integer"; //$NON-NLS-1$
}
@Override public String getThreeLetterTypeSerializationCode()
{
return "int"; //$NON-NLS-1$
}
@Override public <T> T processUsing(TypeProcessor<T> p)
{
return p.ifInteger(this);
}
@Override
public Type getCommonType(Type other)
{
return this.processUsing(new TypeProcessor<Type>()
{
@Override public Type ifComplex(Type type) { return Type.COMPLEX; }
@Override public Type ifDoublePrecision(Type type) { return Type.DOUBLEPRECISION; }
@Override public Type ifInteger(Type type) { return Type.INTEGER; }
@Override public Type ifReal(Type type) { return Type.REAL; }
});
}
};
public static Type REAL = new PrimitiveType()
{
@Override public String toString()
{
return "real"; //$NON-NLS-1$
}
@Override public String getThreeLetterTypeSerializationCode()
{
return "rea"; //$NON-NLS-1$
}
@Override public <T> T processUsing(TypeProcessor<T> p)
{
return p.ifReal(this);
}
@Override
public Type getCommonType(Type other)
{
return this.processUsing(new TypeProcessor<Type>()
{
@Override public Type ifComplex(Type type) { return Type.COMPLEX; }
@Override public Type ifDoublePrecision(Type type) { return Type.DOUBLEPRECISION; }
@Override public Type ifInteger(Type type) { return Type.REAL; }
@Override public Type ifReal(Type type) { return Type.REAL; }
});
}
};
public static Type DOUBLEPRECISION = new PrimitiveType()
{
@Override public String toString()
{
return "double precision"; //$NON-NLS-1$
}
@Override public String getThreeLetterTypeSerializationCode()
{
return "dbl"; //$NON-NLS-1$
}
@Override public <T> T processUsing(TypeProcessor<T> p)
{
return p.ifDoublePrecision(this);
}
@Override
public Type getCommonType(Type other)
{
return this.processUsing(new TypeProcessor<Type>()
{
@Override public Type ifComplex(Type type) { return Type.COMPLEX; }
@Override public Type ifDoublePrecision(Type type) { return Type.DOUBLEPRECISION; }
@Override public Type ifInteger(Type type) { return Type.DOUBLEPRECISION; }
@Override public Type ifReal(Type type) { return Type.DOUBLEPRECISION; }
});
}
};
public static Type COMPLEX = new PrimitiveType()
{
@Override public String toString()
{
return "complex"; //$NON-NLS-1$
}
@Override public String getThreeLetterTypeSerializationCode()
{
return "cpx"; //$NON-NLS-1$
}
@Override public <T> T processUsing(TypeProcessor<T> p)
{
return p.ifComplex(this);
}
@Override
public Type getCommonType(Type other)
{
return this.processUsing(new TypeProcessor<Type>()
{
@Override public Type ifComplex(Type type) { return Type.COMPLEX; }
@Override public Type ifDoublePrecision(Type type) { return Type.COMPLEX; }
@Override public Type ifInteger(Type type) { return Type.COMPLEX; }
@Override public Type ifReal(Type type) { return Type.COMPLEX; }
});
}
};
public static Type DOUBLECOMPLEX = new PrimitiveType()
{
@Override public String toString()
{
return "doublecomplex"; //$NON-NLS-1$
}
@Override public String getThreeLetterTypeSerializationCode()
{
return "dcx"; //$NON-NLS-1$
}
@Override public <T> T processUsing(TypeProcessor<T> p)
{
return p.ifDoubleComplex(this);
}
@Override
public Type getCommonType(Type other)
{
return this.processUsing(new TypeProcessor<Type>()
{
@Override public Type ifComplex(Type type) { return Type.DOUBLECOMPLEX; }
@Override public Type ifDoublePrecision(Type type) { return Type.DOUBLECOMPLEX; }
@Override public Type ifInteger(Type type) { return Type.DOUBLECOMPLEX; }
@Override public Type ifReal(Type type) { return Type.DOUBLECOMPLEX; }
});
}
};
public static Type LOGICAL = new PrimitiveType()
{
@Override public String toString()
{
return "logical"; //$NON-NLS-1$
}
@Override public String getThreeLetterTypeSerializationCode()
{
return "log"; //$NON-NLS-1$
}
@Override public <T> T processUsing(TypeProcessor<T> p)
{
return p.ifLogical(this);
}
};
public static Type CHARACTER = new PrimitiveType()
{
@Override public String toString()
{
return "character"; //$NON-NLS-1$
}
@Override public String getThreeLetterTypeSerializationCode()
{
return "chr"; //$NON-NLS-1$
}
@Override public <T> T processUsing(TypeProcessor<T> p)
{
return p.ifCharacter(this);
}
};
/**
* Type of
* <ul>
* <li> entities imported from a module that could not be found or was not loaded
* <li> interface blocks
* <li> external subprograms
* <li> intrinsics
* <li> functions
* </ul>
*/
public static Type UNKNOWN = new PrimitiveType()
{
@Override public String toString()
{
return "(unknown)"; //$NON-NLS-1$
}
@Override public String getThreeLetterTypeSerializationCode()
{
return "unk"; //$NON-NLS-1$
}
@Override public <T> T processUsing(TypeProcessor<T> p)
{
return p.ifUnknown(this);
}
};
/**
* Name of a derived type, namelist, common block, where statement, program name, etc.
*/
public static Type VOID = new PrimitiveType()
{
@Override public String toString()
{
return "(unclassified)"; //$NON-NLS-1$
}
@Override public String getThreeLetterTypeSerializationCode()
{
return "voi"; //$NON-NLS-1$
}
@Override public <T> T processUsing(TypeProcessor<T> p)
{
return p.ifUnclassified(this);
}
};
/**
* Type of expressions which do not type check
*/
public static Type TYPE_ERROR = new PrimitiveType()
{
@Override public String toString()
{
return "(type error)"; //$NON-NLS-1$
}
@Override public String getThreeLetterTypeSerializationCode()
{
return "err"; //$NON-NLS-1$
}
@Override public <T> T processUsing(TypeProcessor<T> p)
{
return p.ifError(this);
}
};
////////////////////////////////////////////////////////////////////////////////
// IPhotranSerializable Implementation
////////////////////////////////////////////////////////////////////////////////
private static Map<String, Object> threeLetterTypeSerializationCodes;
private static void setThreeLetterTypeSerializationCode(Type type)
{
String code = type.getThreeLetterTypeSerializationCode();
checkCode(code);
threeLetterTypeSerializationCodes.put(code, type);
}
private static void setThreeLetterSerializationCode(Class<? extends Type> typeClass)
{
threeLetterTypeSerializationCodes.put((String)invokeStatic("getStaticThreeLetterTypeSerializationCode", typeClass, new Class<?>[0]), typeClass); //$NON-NLS-1$
}
private static void checkCode(String code)
{
if (code == null || code.length() != 3)
throw new IllegalArgumentException("Invalid three-letter code for Type serialization: " + code); //$NON-NLS-1$
else if (threeLetterTypeSerializationCodes.containsKey(code))
throw new IllegalArgumentException("Duplicate three-letter code for Type serialization: " + code); //$NON-NLS-1$
}
static
{
threeLetterTypeSerializationCodes = new HashMap<String, Object>();
setThreeLetterTypeSerializationCode(INTEGER);
setThreeLetterTypeSerializationCode(REAL);
setThreeLetterTypeSerializationCode(DOUBLEPRECISION);
setThreeLetterTypeSerializationCode(COMPLEX);
setThreeLetterTypeSerializationCode(DOUBLECOMPLEX);
setThreeLetterTypeSerializationCode(LOGICAL);
setThreeLetterTypeSerializationCode(CHARACTER);
setThreeLetterTypeSerializationCode(UNKNOWN);
setThreeLetterTypeSerializationCode(VOID);
setThreeLetterTypeSerializationCode(TYPE_ERROR);
setThreeLetterSerializationCode(DerivedType.class);
setThreeLetterSerializationCode(FunctionType.class);
}
public static Type readFrom(InputStream in) throws IOException
{
String code = PhotranVPGSerializer.deserialize(in);
if (!threeLetterTypeSerializationCodes.containsKey(code))
throw new IOException("Unrecognized type code: " + code); //$NON-NLS-1$
Object o = threeLetterTypeSerializationCodes.get(code);
if (o instanceof Type)
return (Type)o;
else if (o instanceof Class)
return invokeStatic("finishReadFrom", (Class<?>)o, new Class<?>[] { InputStream.class }, in); //$NON-NLS-1$
else
throw new IOException();
}
public void writeTo(OutputStream out) throws IOException
{
PhotranVPGSerializer.serialize(getThreeLetterTypeSerializationCode(), out);
finishWriteTo(out);
}
public char getSerializationCode()
{
return PhotranVPGSerializer.CLASS_TYPE;
}
@SuppressWarnings("unchecked")
private static <T> T invokeStatic(String method, Class<?> o, Class<?>[] argTypes, Object... args)
{
try
{
return (T)o.getMethod(method, argTypes).invoke(null, args);
}
catch (Exception e)
{
throw new Error(e.getClass().getSimpleName() + ": " + e.getMessage()); //$NON-NLS-1$
}
}
}