package org.overture.codegen.vdm2jml.predgen.info; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.apache.log4j.Logger; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.analysis.DepthFirstAnalysisAdaptor; import org.overture.ast.types.ABracketType; import org.overture.ast.types.AInMapMapType; import org.overture.ast.types.ANamedInvariantType; import org.overture.ast.types.AOptionalType; import org.overture.ast.types.AProductType; import org.overture.ast.types.ASeq1SeqType; import org.overture.ast.types.AUnionType; import org.overture.ast.types.AUnknownType; import org.overture.ast.types.PType; import org.overture.ast.types.SMapTypeBase; import org.overture.ast.types.SSeqTypeBase; import org.overture.ast.types.SSetType; import org.overture.codegen.ir.IRInfo; import org.overture.codegen.ir.STypeIR; public class NamedTypeInvDepCalculator extends DepthFirstAnalysisAdaptor { private List<NamedTypeInfo> typeInfoList; private IRInfo info; private static Logger log = Logger.getLogger(NamedTypeInvDepCalculator.class.getName()); public NamedTypeInvDepCalculator(IRInfo info) { super(); this.info = info; this.typeInfoList = new LinkedList<NamedTypeInfo>(); } public List<NamedTypeInfo> getTypeDataList() { return typeInfoList; } public static NamedTypeInfo findTypeInfo(List<NamedTypeInfo> typeInfoList, String defModule, String typeName) { for (NamedTypeInfo t : typeInfoList) { if (NamedTypeInfo.isSameTypeDef(t, defModule, typeName)) { return t; } } return null; } public boolean containsExactly(ANamedInvariantType node) { String module = node.getName().getModule(); String typeName = node.getName().getName(); for (NamedTypeInfo t : typeInfoList) { if (NamedTypeInfo.isSameTypeDef(t, module, typeName)) { return true; } } return false; } @Override public void caseANamedInvariantType(ANamedInvariantType node) throws AnalysisException { // Avoid unnecessary construction if (!containsExactly(node)) { AbstractTypeInfo typeInfo = create(info, node, new HashSet<PType>()); if (typeInfo instanceof NamedTypeInfo) { typeInfoList.add((NamedTypeInfo) typeInfo); } else { log.error("Expected a '" + NamedTypeInfo.class.getSimpleName() + "' to be returned. Got: " + typeInfo); } } } private static AbstractTypeInfo create(IRInfo info, PType type, Set<PType> visited) { if (visited.contains(type)) { // Type recursion return new RecursiveLeaf(); } else { visited.add(type); } boolean optional = false; while (type instanceof AOptionalType || type instanceof ABracketType) { if (type instanceof AOptionalType) { type = ((AOptionalType) type).getType(); optional = true; } else if (type instanceof ABracketType) { type = ((ABracketType) type).getType(); } } if (type instanceof ANamedInvariantType) { ANamedInvariantType namedType = (ANamedInvariantType) type; AbstractTypeInfo domainInfo = create(info, namedType.getType(), visited); NamedTypeInfo namedInfo = new NamedTypeInfo(namedType.getName().getName(), namedType.getName().getModule(), namedType.getInvDef() != null, optional, domainInfo); return namedInfo; } else if (type instanceof AUnionType) { List<AbstractTypeInfo> types = new LinkedList<>(); for (PType t : ((AUnionType) type).getTypes()) { AbstractTypeInfo tInfo = create(info, t, visited); if (tInfo != null) { types.add(tInfo); } } return new UnionInfo(optional, types); } else if (type instanceof AProductType) { List<AbstractTypeInfo> types = new LinkedList<>(); for (PType t : ((AProductType) type).getTypes()) { AbstractTypeInfo tInfo = create(info, t, visited); if (tInfo != null) { types.add(tInfo); } } return new TupleInfo(optional, types); } else if (type instanceof SSeqTypeBase) { SSeqTypeBase seqType = (SSeqTypeBase) type; boolean isSeq1 = seqType instanceof ASeq1SeqType; return new SeqInfo(optional, create(info, seqType.getSeqof(), visited), isSeq1); } else if (type instanceof SSetType) { SSetType setType = (SSetType) type; return new SetInfo(optional, create(info, setType.getSetof(), visited)); } else if (type instanceof SMapTypeBase) { SMapTypeBase mapType = (SMapTypeBase) type; AbstractTypeInfo fromInfo = create(info, mapType.getFrom(), visited); AbstractTypeInfo toInfo = create(info, mapType.getTo(), visited); boolean injective = type instanceof AInMapMapType; return new MapInfo(optional, fromInfo, toInfo, injective); } else if (type instanceof AUnknownType) { return new UnknownLeaf(); } else { return new LeafTypeInfo(toIrType(type, info), optional); } } public static STypeIR toIrType(PType type, IRInfo info) { try { STypeIR irType = type.apply(info.getTypeVisitor(), info); if (irType != null) { irType.setOptional(false); } return irType; } catch (AnalysisException e) { log.error("Problems encountered while attempting " + "to construct the IR type from a VDM type: " + e.getMessage()); e.printStackTrace(); return null; } } }