package algorithms; import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import code.ast.CompilationUnit; import code.ast.MethodDeclaration; import code.ast.TypeDeclaration; import models.Edge; import models.Node; import models.algebra.Expression; import models.algebra.InvalidMessage; import models.algebra.ParameterizedIdentifierIsFutureWork; import models.algebra.Symbol; import models.algebra.Term; import models.algebra.UnificationFailed; import models.algebra.ValueUndefined; import models.dataConstraintModel.ChannelGenerator; import models.dataConstraintModel.ChannelMember; import models.dataFlowModel.DataFlowModel; import models.dataFlowModel.DataflowChannelGenerator; import models.dataFlowModel.PushPullAttribute; import models.dataFlowModel.PushPullValue; import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; import models.dataFlowModel.ResourceDependency; import models.dataFlowModel.ResourceDependencyGraph; import models.dataFlowModel.ResourceNode; import models.dataFlowModel.StoreAttribute; public class MethodBodyGenerator { public static ArrayList<CompilationUnit> doGenerate(ResourceDependencyGraph graph, DataFlowModel model, ArrayList<CompilationUnit> codes) { Symbol floor = model.getSymbol("floor"); Symbol.Memento floorMem = null; if (floor != null) { floorMem = floor.createMemento(); floor.setImplName("(int)Math.floor"); floor.setImplOperatorType(Symbol.Type.PREFIX); } Symbol sum = model.getSymbol("sum"); Symbol.Memento sumMem = null; if (sum != null) { sumMem = sum.createMemento(); sum.setImplName("stream().mapToInt(x->x).sum"); sum.setImplOperatorType(Symbol.Type.METHOD); } // Create a map from type names (lower case) to their types. Map<String, TypeDeclaration> typeMap = new HashMap<>(); for (CompilationUnit code: codes) { for (TypeDeclaration type: code.types()) { typeMap.put(type.getTypeName().substring(0,1).toLowerCase() + type.getTypeName().substring(1), type); } } // Generate the body of each update or getter method. try { for (Edge e: graph.getEdges()) { ResourceDependency d = (ResourceDependency) e; PushPullAttribute pushPull = (PushPullAttribute) d.getAttribute(); ResourceNode src = (ResourceNode) d.getSource(); ResourceNode dst = (ResourceNode) d.getDestination(); String srcResourceName = src.getIdentifierTemplate().getResourceName(); String dstResourceName = dst.getIdentifierTemplate().getResourceName(); TypeDeclaration srcType = typeMap.get(srcResourceName); TypeDeclaration dstType = typeMap.get(dstResourceName); for (ChannelMember out: d.getChannelGenerator().getOutputChannelMembers()) { if (out.getIdentifierTemplate() == dst.getIdentifierTemplate()) { if (pushPull.getOptions().get(0) == PushPullValue.PUSH && srcType != null) { // for push data transfer MethodDeclaration update = getUpdateMethod(dstType, srcType); if (((StoreAttribute) dst.getAttribute()).isStored()) { // update stored state of dst resource (when every incoming edge is in push style) Expression updateExp = d.getChannelGenerator().deriveUpdateExpressionOf(out, CodeGenerator.pushAccessor); String curState = updateExp.toImplementation(); String updateStatement; if (updateExp instanceof Term && ((Term) updateExp).getSymbol().getImplOperatorType() == Symbol.Type.METHOD_WITH_SIDE_EFFECT) { updateStatement = curState + ";"; } else { updateStatement = dstResourceName + " = " + curState + ";"; } if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { update.addFirstStatement(updateStatement); } } if (dst.getIndegree() > 1) { // update a cash of src resource (when incoming edges are multiple) String cashStatement = "this." + srcResourceName + " = " + srcResourceName + ";"; if (update.getBody() == null || !update.getBody().getStatements().contains(cashStatement)) { update.addFirstStatement(cashStatement); } } MethodDeclaration getter = getGetterMethod(dstType); if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { getter.addStatement("return " + dstResourceName + ";"); } // src side (for a chain of update method invocations) for (MethodDeclaration srcUpdate: getUpdateMethods(srcType)) { srcUpdate.addStatement(dstResourceName + ".update" + srcType.getTypeName() + "(" + srcResourceName + ");"); } MethodDeclaration srcInput = getInputMethod(srcType, src, model); if (srcInput != null) srcInput.addStatement(dstResourceName + ".update" + srcType.getTypeName() + "(" + srcResourceName + ");"); } else { // for pull (or push/pull) data transfer MethodDeclaration getter = getGetterMethod(dstType); if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { String curState = d.getChannelGenerator().deriveUpdateExpressionOf(out, CodeGenerator.pullAccessor).toImplementation(); getter.addStatement("return " + curState + ";"); } } } } } // for source nodes String mainTypeName = CodeGenerator.mainTypeName.substring(0,1).toLowerCase() + CodeGenerator.mainTypeName.substring(1); TypeDeclaration mainType = typeMap.get(mainTypeName); for (Node n: graph.getNodes()) { ResourceNode resource = (ResourceNode) n; String resourceName = resource.getIdentifierTemplate().getResourceName(); TypeDeclaration type = typeMap.get(resourceName); if (type != null) { // getter method MethodDeclaration getter = getGetterMethod(type); if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { getter.addStatement("return " + resource.getIdentifierTemplate().getResourceName() + ";"); } // methods for input events Map.Entry<DataflowChannelGenerator, ChannelMember> ioChannelAndMember = getIOChannelAndMember(resource, model); if (ioChannelAndMember != null) { ChannelMember out = ioChannelAndMember.getValue(); Term message = (Term) out.getStateTransition().getMessageExpression(); MethodDeclaration input = getMethod(type, message.getSymbol().getName()); if (input != null) { Expression updateExp = ioChannelAndMember.getKey().deriveUpdateExpressionOf(out, CodeGenerator.pushAccessor); String newState = updateExp.toImplementation(); String updateStatement; if (updateExp instanceof Term && ((Term) updateExp).getSymbol().getImplOperatorType() == Symbol.Type.METHOD_WITH_SIDE_EFFECT) { updateStatement = newState + ";"; } else { updateStatement = "this." + resourceName + " = " + newState + ";"; } if (input.getBody() == null || !input.getBody().getStatements().contains(updateStatement)) { input.addFirstStatement(updateStatement); } if (mainType != null) { MethodDeclaration mainInput = getMethod(mainType, input.getName()); if (mainInput != null) { mainInput.addStatement("this." + resourceName + "." + input.getName() + "(" + resourceName + ");"); } } } } } } } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork | InvalidMessage | UnificationFailed | ValueUndefined e1) { e1.printStackTrace(); } if (floor != null) floor.setMemento(floorMem); if (sum != null) sum.setMemento(sumMem); return codes; } private static MethodDeclaration getUpdateMethod(TypeDeclaration type, TypeDeclaration from) { for (MethodDeclaration m: type.getMethods()) { if (m.getName().equals("update" + from.getTypeName())) return m; } return null; } private static ArrayList<MethodDeclaration> getUpdateMethods(TypeDeclaration type) { ArrayList<MethodDeclaration> updates = new ArrayList<>(); for (MethodDeclaration m: type.getMethods()) { if (m.getName().startsWith("update")) { updates.add(m); } } return updates; } private static MethodDeclaration getGetterMethod(TypeDeclaration type) { for (MethodDeclaration m: type.getMethods()) { if (m.getName().startsWith("get")) return m; } return null; } private static Map.Entry<DataflowChannelGenerator, ChannelMember> getIOChannelAndMember(ResourceNode resource, DataFlowModel model) { for (ChannelGenerator c: model.getIOChannelGenerators()) { DataflowChannelGenerator channel = (DataflowChannelGenerator) c; // I/O channel for (ChannelMember out: channel.getOutputChannelMembers()) { if (out.getIdentifierTemplate().equals(resource.getIdentifierTemplate())) { if (out.getStateTransition().getMessageExpression() instanceof Term) { // not an identity element return new AbstractMap.SimpleEntry<>(channel, out); } } } } return null; } private static MethodDeclaration getInputMethod(TypeDeclaration type, ResourceNode resource, DataFlowModel model) { for (ChannelGenerator c: model.getIOChannelGenerators()) { DataflowChannelGenerator channel = (DataflowChannelGenerator) c; // I/O channel for (ChannelMember out: channel.getOutputChannelMembers()) { if (out.getIdentifierTemplate().equals(resource.getIdentifierTemplate())) { if (out.getStateTransition().getMessageExpression() instanceof Term) { // not an identity element Term message = (Term) out.getStateTransition().getMessageExpression(); MethodDeclaration input = getMethod(type, message.getSymbol().getName()); return input; } } } } return null; } private static MethodDeclaration getMethod(TypeDeclaration type, String methodName) { for (MethodDeclaration m: type.getMethods()) { if (m.getName().equals(methodName)) return m; } return null; } }