/**
* Copyright (c) 2009-2011, The HATS Consortium. All rights reserved.
* This file is licensed under the terms of the Modified BSD License.
*/
package abs.frontend.typechecker.ext;
import java.util.ArrayList;
import java.util.HashMap;
import abs.frontend.analyser.SemanticConditionList;
import abs.frontend.ast.*;
import abs.frontend.typechecker.BoundedType;
import abs.frontend.typechecker.DataTypeType;
import abs.frontend.typechecker.KindedName;
import abs.frontend.typechecker.Type;
import abs.frontend.typechecker.TypeParameter;
import abs.frontend.typechecker.KindedName.Kind;
public class TypeExtensionHelper implements TypeSystemExtension {
private java.util.List<TypeSystemExtension> obs = new ArrayList<TypeSystemExtension>();
private void registerDefaultExtensions(Model m) {
register(new ClassKindTypeExtension(m));
register(new FinalAnnotationTypeExtension(m));
register(new AtomicityChecker(m));
register(new NewExpressionChecker(m));
register(new DeadlineChecker(m));
register(new SizeAnnotationChecker(m));
register(new CostAnnotationChecker(m));
register(new SchedulerChecker(m));
register(new MainBlockChecker(m));
register(new HttpExportChecker(m));
}
public TypeSystemExtension getFirstRegisteredTypeExtension(Class<?> clazz) {
for (TypeSystemExtension tse : obs) {
if (tse.getClass().equals(clazz)) {
return tse;
}
}
return null;
}
public void setSemanticConditionList(SemanticConditionList s) {
for (TypeSystemExtension tse : obs) {
tse.setSemanticConditionList(s);
}
}
public void typeCheckStarted(Model m, SemanticConditionList e) {
registerDefaultExtensions(m);
setSemanticConditionList(e);
}
public void register(TypeSystemExtension tse) {
obs = new ArrayList<TypeSystemExtension>(obs);
obs.add(tse);
}
public void unregister(TypeSystemExtension tse) {
obs = new ArrayList<TypeSystemExtension>(obs);
obs.remove(tse);
}
public void clearTypeSystemExtensions() {
obs = new ArrayList<TypeSystemExtension>();
}
public java.util.List<TypeSystemExtension> getTypeSystemExtensionList() {
return new ArrayList<TypeSystemExtension>(obs);
}
public void checkMethodCall(Call call) {
for (TypeSystemExtension tse : obs) {
tse.checkMethodCall(call);
}
}
@Override
public void checkOverride(MethodSig impl, MethodSig overriden) {
for (TypeSystemExtension tse : obs) {
tse.checkOverride(impl,overriden);
}
assert overriden.getParent().getParent() instanceof InterfaceDecl;
Type expectedReturnType = overriden.getType();
Type actualReturnType = impl.getType();
checkAssignable(actualReturnType, expectedReturnType, impl);
for (int i = 0; i < overriden.getNumParam(); i++) {
Type texpected = overriden.getParam(i).getType();
Type tactual = impl.getParam(i).getType();
checkAssignable(texpected, tactual, impl);
}
}
public void checkNewExp(NewExp e) {
for (TypeSystemExtension tse : obs) {
tse.checkNewExp(e);
}
ClassDecl d = (ClassDecl) e.lookup(new KindedName(Kind.CLASS,e.getClassName()));
checkAssignable(e.getType(),d,e);
}
@Override
public void checkGetExp(GetExp e) {
for (TypeSystemExtension tse : obs) {
tse.checkGetExp(e);
}
}
public void checkAssignStmt(AssignStmt s) {
for (TypeSystemExtension tse : obs) {
tse.checkAssignStmt(s);
}
checkAssignable(s.getValue().getType(),s.getVar().getType(), s);
}
public void checkReturnStmt(ReturnStmt s) {
for (TypeSystemExtension tse : obs) {
tse.checkReturnStmt(s);
}
MethodImpl m = s.getContextMethod();
if (m == null) {
return;
}
checkAssignable(s.getRetExp().getType(), m.getMethodSig().getType(), s);
}
public void checkAssignable(Type callee, HasParams params, ASTNode<?> n) {
java.util.List<Type> paramsTypes = params.getTypes();
for (int i = 0; i < paramsTypes.size(); i++) {
Type argType = paramsTypes.get(i);
PureExp exp = ((HasActualParams)n).getParams().getChild(i);
checkAssignable(callee, AdaptDirection.TO, exp.getType(), argType, n);
}
}
public void checkAssignable(Type rht, Type lht, ASTNode<?> n) {
checkAssignable(null, null, rht, lht, n);
}
public void checkAssignable(Type adaptTo, AdaptDirection dir, Type rht, Type lht, ASTNode<?> n) {
rht = resolveBoundedType(rht);
if (lht.isDataType() && rht.isDataType()) {
DataTypeType dtl = (DataTypeType) lht;
DataTypeType dtr = (DataTypeType) rht;
if (dtl.hasTypeArgs() && dtr.hasTypeArgs() && dtl.getTypeArgs().size() == dtr.getTypeArgs().size()) {
for (int i = 0; i < dtl.getTypeArgs().size(); i++) {
checkAssignable(adaptTo, dir, dtr.getTypeArg(i), dtl.getTypeArg(i), n);
}
}
}
if (lht.isReferenceType() && rht.isReferenceType()) {
for (TypeSystemExtension tse : obs) {
tse.checkAssignable(adaptTo, dir, rht, lht, n);
}
}
}
public void annotateType(Type t, ASTNode<?> originatingNode) {
annotateType(t, originatingNode, null);
}
public void annotateType(Type t, ASTNode<?> originatingNode, ASTNode<?> typeNode) {
if (t.isDataType()) {
DataTypeType dt = (DataTypeType) t;
if (dt.hasTypeArgs()) {
ParametricDataTypeUse pu = null;
// typeNode maybe a type synonym
if (typeNode instanceof ParametricDataTypeUse)
pu = (ParametricDataTypeUse) typeNode;
int i = 0;
for (Type ta : dt.getTypeArgs()) {
ASTNode<?> childTypeNode = null;
if (pu != null)
childTypeNode = pu.getParam(i);
annotateType(ta, originatingNode, childTypeNode);
i++;
}
}
}
if (t.isReferenceType() || t.isNullType()) {
for (TypeSystemExtension tse : obs) {
tse.annotateType(t, originatingNode, typeNode);
}
}
}
public void checkCaseExp(CaseExp e) {
Type t = e.getType();
for (CaseBranch b : e.getBranchs()) {
checkAssignable(b.getType(),t, b.getRight());
}
}
public void checkIfExp(IfExp e) {
}
public void checkDataConstructorExp(DataConstructorExp e) {
DataConstructor decl = (DataConstructor) e.getDecl();
if (decl.getDataTypeDecl() instanceof ParametricDataTypeDecl) {
HashMap<TypeParameter, Type> map = new HashMap<TypeParameter, Type>();
for (int i = 0; i < decl.getNumConstructorArg(); i++) {
Type rht = e.getParam(i).getType();
Type arg = decl.getConstructorArg(i).getType();
checkTypeParameter(map, rht, arg, e.getParam(i));
}
}
}
public void checkFnApp(FnApp f) {
FunctionDecl decl = (FunctionDecl) f.getDecl();
if (decl instanceof ParametricFunctionDecl) {
HashMap<TypeParameter, Type> map = new HashMap<TypeParameter, Type>();
for (int i = 0; i < decl.getNumParam(); i++) {
Type t = f.getParam(i).getType();
Type arg = decl.getParam(i).getType();
checkTypeParameter(map, t, arg, f.getParam(i));
}
} else {
checkAssignable(null, decl, f);
}
}
private void checkTypeParameter(HashMap<TypeParameter, Type> map, Type rht, Type lht, ASTNode<?> origin) {
rht = resolveBoundedType(rht);
if (rht.isBoundedType())
return;
if (lht.isTypeParameter() && rht.isReferenceType()) {
TypeParameter typeParam = (TypeParameter) lht;
Type lt = map.get(typeParam);
if (lt != null) {
checkEq(lt,rht,origin);
} else {
map.put(typeParam, rht);
}
} else if (lht.isDataType()) {
DataTypeType argdt = (DataTypeType) lht;
if (argdt.hasTypeArgs()) {
DataTypeType dt = (DataTypeType)rht;
for (int i = 0; i < dt.numTypeArgs(); i++) {
checkTypeParameter(map,dt.getTypeArg(i),argdt.getTypeArg(i),origin);
}
}
} else if (lht.isReferenceType()) {
checkEq(lht,rht,origin);
}
}
private Type resolveBoundedType(Type t) {
if (t.isBoundedType()) {
BoundedType bt = (BoundedType)t;
if (bt.hasBoundType())
t = bt.getBoundType();
}
return t;
}
public void checkEq(Type lht, Type rht, ASTNode<?> origin) {
if (lht.isDataType() && rht.isDataType()) {
DataTypeType dtl = (DataTypeType) lht;
DataTypeType dtr = (DataTypeType) rht;
if (dtl.hasTypeArgs() && dtr.hasTypeArgs() && dtl.getTypeArgs().size() == dtr.getTypeArgs().size()) {
for (int i = 0; i < dtl.getTypeArgs().size(); i++) {
checkEq(dtr.getTypeArg(i), dtl.getTypeArg(i), origin);
}
}
}
if (lht.isReferenceType() && rht.isReferenceType()) {
for (TypeSystemExtension tse : obs) {
tse.checkEq(rht, lht, origin);
}
}
}
public void finished() {
for (TypeSystemExtension tse : obs) {
tse.finished();
}
}
@Override
public void checkClassDecl(ClassDecl decl) {
for (TypeSystemExtension tse : obs) {
tse.checkClassDecl(decl);
}
}
@Override
public void checkInterfaceDecl(InterfaceDecl decl) {
for (TypeSystemExtension tse : obs) {
tse.checkInterfaceDecl(decl);
}
}
@Override
public void checkDataTypeDecl(DataTypeDecl decl) {
for (TypeSystemExtension tse : obs) {
tse.checkDataTypeDecl(decl);
}
}
@Override
public void checkMethodImpl(MethodImpl method) {
for (TypeSystemExtension tse : obs) {
tse.checkMethodImpl(method);
}
}
@Override
public void checkStmt(Stmt s) {
for (TypeSystemExtension tse : obs) {
tse.checkStmt(s);
}
}
@Override
public void checkAssertStmt(AssertStmt assertStmt) {
for (TypeSystemExtension tse : obs) {
tse.checkAssertStmt(assertStmt);
}
}
@Override
public void checkAwaitStmt(AwaitStmt awaitStmt) {
for (TypeSystemExtension tse : obs) {
tse.checkAwaitStmt(awaitStmt);
}
}
@Override
public void checkBlock(Block block) {
for (TypeSystemExtension tse : obs) {
tse.checkBlock(block);
}
}
@Override
public void checkExpressionStmt(ExpressionStmt expressionStmt) {
for (TypeSystemExtension tse : obs) {
tse.checkExpressionStmt(expressionStmt);
}
}
@Override
public void checkIfStmt(IfStmt ifStmt) {
for (TypeSystemExtension tse : obs) {
tse.checkIfStmt(ifStmt);
}
}
@Override
public void checkSuspendStmt(SuspendStmt suspendStmt) {
for (TypeSystemExtension tse : obs) {
tse.checkSuspendStmt(suspendStmt);
}
}
@Override
public void checkVarDeclStmt(VarDeclStmt varDeclStmt) {
for (TypeSystemExtension tse : obs) {
tse.checkVarDeclStmt(varDeclStmt);
}
}
@Override
public void checkDurationStmt(DurationStmt durationStmt) {
for (TypeSystemExtension tse : obs) {
tse.checkDurationStmt(durationStmt);
}
}
@Override
public void checkWhileStmt(WhileStmt whileStmt) {
for (TypeSystemExtension tse : obs) {
tse.checkWhileStmt(whileStmt);
}
}
@Override
public void checkModel(Model model) {
for (TypeSystemExtension tse : obs) {
tse.checkModel(model);
}
}
public void registerAll(java.util.List<TypeSystemExtension> curr) {
obs = new ArrayList<TypeSystemExtension>(obs);
obs.addAll(curr);
}
}