package apet.absunit; import static abs.backend.tests.AbsASTBuilderUtil.getDecl; import static abs.backend.tests.AbsASTBuilderUtil.namePred; import static apet.testCases.ABSTestCaseExtractor.getABSDataType; import static apet.testCases.ABSTestCaseExtractor.getABSDataValue; import static apet.testCases.ABSTestCaseExtractor.getABSTermArgs; import static apet.testCases.ABSTestCaseExtractor.getABSTermFunctor; import static apet.testCases.ABSTestCaseExtractor.getABSTermTypeName; import java.util.List; import java.util.Set; import abs.frontend.ast.DataConstructorExp; import abs.frontend.ast.DataTypeDecl; import abs.frontend.ast.DataTypeUse; import abs.frontend.ast.Decl; import abs.frontend.ast.IntLiteral; import abs.frontend.ast.InterfaceDecl; import abs.frontend.ast.Model; import abs.frontend.ast.NullExp; import abs.frontend.ast.ParametricDataTypeDecl; import abs.frontend.ast.PureExp; import abs.frontend.ast.StringLiteral; import abs.frontend.ast.TypeParameterDecl; import abs.frontend.ast.TypeSynDecl; import abs.frontend.ast.TypeUse; import abs.frontend.ast.VarUse; import apet.testCases.ABSData; import apet.testCases.ABSRef; import apet.testCases.ABSTerm; /** * * @author woner * */ final class PureExpressionBuilder { private final String INT = "Int"; private final String STRING = "String"; private final Model model; private final HeapReferenceBuilder heapRefBuilder = new HeapReferenceBuilder(); private final Set<String> importModules; PureExpressionBuilder(Model input, Set<String> importModules) { this.model = input; this.importModules = importModules; } void updateInitialisationOrder(List<String> initialisationsOrders, String cr, String nr) { int cpos = initialisationsOrders.indexOf(cr); int npos = initialisationsOrders.indexOf(nr); if (npos < 0 || npos > cpos) { initialisationsOrders.add(cpos, nr); } } PureExp createPureExpression( String testName, Set<String> heapNames, ABSData dataValue) { return createPureExpression(null, null, testName, heapNames, dataValue); } /** * @param currentHeapReference * @param initialisationsOrders * @param heapNames * @param dataValue * @return */ PureExp createPureExpression( String currentHeapReference, List<String> initialisationsOrders, String testName, Set<String> heapNames, ABSData dataValue) { String type = getABSDataType(dataValue); String value = getABSDataValue(dataValue); if (type.contains("(") && dataValue instanceof ABSTerm) { ABSTerm term = (ABSTerm) dataValue; type = getABSTermTypeName(term); } //import type Decl decl = getDecl(model, Decl.class, namePred(type)); importType(decl); if (dataValue instanceof ABSTerm) { ABSTerm term = (ABSTerm) dataValue; return makeDataTermValue(currentHeapReference, initialisationsOrders, testName, heapNames, term, decl); } else if (dataValue instanceof ABSRef) { if (heapNames.contains(value)) { String ref = heapRefBuilder.heapReferenceForTest(testName, value); if (currentHeapReference != null) { //we need to consider initialisation order! updateInitialisationOrder(initialisationsOrders, currentHeapReference, ref); } return new VarUse(ref); } else { return new NullExp(); } } else { throw new IllegalStateException("Cannot handle ABSData that is not " + "either a ABSRef or a ABSTerm"); } } /** * Resolve the type synonyms to its raw type (interface or data type) * @param d * @return */ Decl resolveTypeSynonym(TypeSynDecl d) { TypeUse use = d.getValue(); Decl decl = getDecl(model, Decl.class, namePred(use.getName())); if (decl instanceof TypeSynDecl) { return resolveTypeSynonym((TypeSynDecl) decl); } return decl; } void importType(Decl decl) { importModules.add(decl.getModuleDecl().getName()); if (decl instanceof TypeSynDecl) { decl = resolveTypeSynonym((TypeSynDecl) decl); importModules.add(decl.getModuleDecl().getName()); } //import type parameters if (decl instanceof ParametricDataTypeDecl) { for (TypeParameterDecl t : ((ParametricDataTypeDecl) decl).getTypeParameters()) { Decl type = getDecl(model, Decl.class, namePred(t.getName())); if (type == null) { //most likely a generic type continue; } importType(type); } } } /** * Construct a pure expression that is either a primitive literal * such as Int and String, or a value of a data type. * @param currentHeapReference * * @param initialisationsOrders * @param heap * @param testName * @param value * @param decl * * @return */ PureExp makeDataTermValue(String currentHeapReference, List<String> initialisationsOrders, String testName, Set<String> heap, ABSTerm term, Decl decl) { if (decl instanceof TypeSynDecl) { decl = resolveTypeSynonym((TypeSynDecl) decl); } if (decl instanceof DataTypeDecl) { if (STRING.equals(decl.getName())) { return new StringLiteral(getABSDataValue(term)); } else if (INT.equals(decl.getName())) { return new IntLiteral(getABSDataValue(term)); } else { return parseValue(currentHeapReference, initialisationsOrders, testName, heap, term); } } else if (decl instanceof InterfaceDecl) { String value = getABSDataValue(term); if (heap.contains(value)) { String ref = heapRefBuilder.heapReferenceForTest(testName, value); if (currentHeapReference != null) { //we need to consider initialisation order! updateInitialisationOrder(initialisationsOrders, currentHeapReference, ref); } return new VarUse(ref); } else { return new NullExp(); } } else { throw new IllegalStateException("Cannot handle declaration type "+decl); } } DataConstructorExp parseValue(String currentHeapReference, List<String> initialisationsOrders, String testName, Set<String> heap, ABSTerm term) { final DataConstructorExp result = new DataConstructorExp(); String fn = getABSTermFunctor(term); result.setConstructor(fn); result.setParamList(new abs.frontend.ast.List<PureExp>()); List<ABSData> vs = getABSTermArgs(term); for (int i=0; i<vs.size(); i++) { result.setParam(createPureExpression(currentHeapReference, initialisationsOrders, testName, heap, vs.get(i)),i); } return result; } }