package org.overture.codegen.vdm2java; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.commons.lang.BooleanUtils; import org.overture.ast.definitions.AClassClassDefinition; import org.overture.ast.definitions.SClassDefinition; import org.overture.ast.node.INode; import org.overture.codegen.assistant.AssistantBase; import org.overture.codegen.ir.IRGeneratedTag; import org.overture.codegen.ir.PIR; import org.overture.codegen.ir.analysis.AnalysisException; import org.overture.codegen.ir.analysis.DepthFirstAnalysisAdaptor; import org.overture.codegen.ir.declarations.ACpuClassDeclIR; import org.overture.codegen.ir.declarations.ADefaultClassDeclIR; import org.overture.codegen.ir.declarations.AFieldDeclIR; import org.overture.codegen.ir.declarations.AInterfaceDeclIR; import org.overture.codegen.ir.declarations.AMethodDeclIR; import org.overture.codegen.ir.declarations.ASystemClassDeclIR; import org.overture.codegen.ir.declarations.SClassDeclIR; import org.overture.codegen.ir.name.ATokenNameIR; import org.overture.codegen.trans.ITotalTransformation; import org.overture.codegen.trans.assistants.TransAssistantIR; public class ClassToInterfaceTrans extends DepthFirstAnalysisAdaptor implements ITotalTransformation { private PIR result; private Map<String, Boolean> isFullyAbstract; private Map<String, AInterfaceDeclIR> interfaces; public ClassToInterfaceTrans(TransAssistantIR assist) { this.isFullyAbstract = new HashMap<>(); this.interfaces = new HashMap<>(); for (SClassDeclIR c : assist.getInfo().getClasses()) { INode vdmNode = AssistantBase.getVdmNode(c); // AVoid system as CPU classes if (vdmNode instanceof AClassClassDefinition) { SClassDefinition vdmClazz = (SClassDefinition) vdmNode; isFullyAbstract.put(c.getName(), assist.getInfo().getDeclAssistant().isFullyAbstract(vdmClazz, assist.getInfo())); interfaces.put(c.getName(), convertToInterface(c)); } else { isFullyAbstract.put(c.getName(), false); } // This transformation is only helpful for IR classes that originate // from VDM classes. So we simply ignore classes that originate from // modules since SL does not support inheritance anyway. } } @Override public void caseASystemClassDeclIR(ASystemClassDeclIR node) throws AnalysisException { this.result = node; } @Override public void caseACpuClassDeclIR(ACpuClassDeclIR node) throws AnalysisException { this.result = node; } @Override public void caseADefaultClassDeclIR(ADefaultClassDeclIR node) throws AnalysisException { if (isFullyAbstract(node.getName())) { result = interfaces.get(node.getName()); } else { // node remains a class result = node; List<ATokenNameIR> toMove = new LinkedList<>(); for (ATokenNameIR s : node.getSuperNames()) { if (isFullyAbstract(s.getName())) { toMove.add(s); } } for (ATokenNameIR m : toMove) { node.getSuperNames().remove(m); node.getInterfaces().add(interfaces.get(m.getName()).clone()); } } } private AInterfaceDeclIR convertToInterface(SClassDeclIR c) { List<AFieldDeclIR> clonedFields = new LinkedList<>(); for (AFieldDeclIR f : c.getFields()) { clonedFields.add(f.clone()); } List<AMethodDeclIR> clonedMethods = new LinkedList<>(); for (AMethodDeclIR m : c.getMethods()) { if (!m.getIsConstructor() && !(m.getTag() instanceof IRGeneratedTag)) { clonedMethods.add(m.clone()); } } AInterfaceDeclIR inter = new AInterfaceDeclIR(); inter.setFields(clonedFields); inter.setMetaData(c.getMetaData()); inter.setMethodSignatures(clonedMethods); inter.setName(c.getName()); inter.setPackage(c.getPackage()); inter.setSourceNode(c.getSourceNode()); inter.setTag(c.getTag()); for (ATokenNameIR n : c.getSuperNames()) { inter.getExtension().add(n.clone()); } return inter; } private boolean isFullyAbstract(String name) { return BooleanUtils.isTrue(isFullyAbstract.get(name)); } @Override public PIR getResult() { return result; } }