diff --git a/AlgebraicDataflowArchitectureModel/models/Triangle.model b/AlgebraicDataflowArchitectureModel/models/Triangle.model new file mode 100644 index 0000000..0f83427 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/Triangle.model @@ -0,0 +1,13 @@ +channel cio1 { + out base(x: Double, setBase(x2)) == x2 +} + +channel cio2 { + out height(y: Double, setHeight(y2)) == y2 +} + +channel triable { + in base(x, update(x2, y2)) == x2 + in height(y, update(x2, y2)) == y2 + out hypothenuse(z: Double, update(x2, y2)) == sqrt(x2 * x2 + y2 * y2) +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 3a7ebcb..3706917 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -1,6 +1,7 @@ package generators; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -16,6 +17,7 @@ import code.ast.VariableDeclaration; import models.Edge; import models.Node; +import models.algebra.Constant; import models.algebra.Expression; import models.algebra.Field; import models.algebra.InvalidMessage; @@ -220,11 +222,13 @@ // Reconstruct data-flow information. Map>> dataFlowInform = new HashMap<>(); for (Node root: controlFlowGraph.getPushCallGraph().getRootNodes()) { - annotateDataFlowAttributes(root, dataFlowInform, new ArrayList<>()); + Set treeResources = traverseCallTree(root, new HashSet<>()); + annotateDataFlowAttributes(root, dataFlowInform, treeResources, new ArrayList<>()); removeRedundantAttributes(root, dataFlowInform); } for (Node root: controlFlowGraph.getPullCallGraph().getRootNodes()) { - annotateDataFlowAttributes(root, dataFlowInform, new ArrayList<>()); + Set treeResources = traverseCallTree(root, new HashSet<>()); + annotateDataFlowAttributes(root, dataFlowInform, treeResources, new ArrayList<>()); removeRedundantAttributes(root, dataFlowInform); } @@ -309,50 +313,69 @@ } } - private static void annotateDataFlowAttributes(Node node, Map>> dataFlowInform, List path) { + private static Set traverseCallTree(Node node, Set visited) { + if (node instanceof StatefulObjectNode) { + ResourceNode resNode = ((StatefulObjectNode) node).getResource(); + visited.add(resNode); + } + // Traverse the call tree. + for (Edge e: node.getOutEdges()) { + visited = traverseCallTree(e.getDestination(), visited); + } + return visited; + } + + private static void annotateDataFlowAttributes(Node node, Map>> dataFlowInform, Set resourceNodes, List path) { if (node instanceof StatefulObjectNode) { // Add data-flow attributes to the path to node. ResourceNode resNode = ((StatefulObjectNode) node).getResource(); for (Edge outE: resNode.getOutEdges()) { // If resNode is the source of data-flow. - for (Edge e: path) { - // Add pull attributes to the path to resNode. - Map> edgeAttributes = dataFlowInform.get(e); - if (edgeAttributes == null) { - edgeAttributes = new HashMap<>(); - dataFlowInform.put(e, edgeAttributes); + ResourceNode dstOfDataFlowNode = (ResourceNode) outE.getDestination(); + if (resourceNodes.contains(dstOfDataFlowNode)) { + // If the data transfer is closed within this call tree. + for (Edge e: path) { + // Add pull attributes to the path to resNode. + Map> edgeAttributes = dataFlowInform.get(e); + if (edgeAttributes == null) { + edgeAttributes = new HashMap<>(); + dataFlowInform.put(e, edgeAttributes); + } + List pullSrcs = edgeAttributes.get(PushPullValue.PULL); + if (pullSrcs == null) { + pullSrcs = new ArrayList<>(); + edgeAttributes.put(PushPullValue.PULL, pullSrcs); + } + pullSrcs.add(resNode); } - List pullSrcs = edgeAttributes.get(PushPullValue.PULL); - if (pullSrcs == null) { - pullSrcs = new ArrayList<>(); - edgeAttributes.put(PushPullValue.PULL, pullSrcs); - } - pullSrcs.add(resNode); } } for (Edge inE: resNode.getInEdges()) { // If resNode is a destination of data-flow. ResourceNode srcOfDataFlowNode = (ResourceNode) inE.getSource(); - for (Edge e: path) { - // Add push attributes to the path to resNode. - Map> edgeAttributes = dataFlowInform.get(e); - if (edgeAttributes == null) { - edgeAttributes = new HashMap<>(); - dataFlowInform.put(e, edgeAttributes); + if (resourceNodes.contains(srcOfDataFlowNode)) { + // If the data transfer is closed done within this call tree. + for (Edge e: path) { + // Add push attributes to the path to resNode. + Map> edgeAttributes = dataFlowInform.get(e); + if (edgeAttributes == null) { + edgeAttributes = new HashMap<>(); + dataFlowInform.put(e, edgeAttributes); + } + List pushSrcs = edgeAttributes.get(PushPullValue.PUSH); + if (pushSrcs == null) { + pushSrcs = new ArrayList<>(); + edgeAttributes.put(PushPullValue.PUSH, pushSrcs); + } + pushSrcs.add(srcOfDataFlowNode); } - List pushSrcs = edgeAttributes.get(PushPullValue.PUSH); - if (pushSrcs == null) { - pushSrcs = new ArrayList<>(); - edgeAttributes.put(PushPullValue.PUSH, pushSrcs); - } - pushSrcs.add(srcOfDataFlowNode); } } } // Traverse the call tree. for (Edge e: node.getOutEdges()) { path.add(e); - annotateDataFlowAttributes(e.getDestination(), dataFlowInform, path); + annotateDataFlowAttributes(e.getDestination(), dataFlowInform, resourceNodes, path); path.remove(e); } } @@ -361,9 +384,17 @@ // Traverse the call tree. for (Edge e: node.getOutEdges()) { // Remove attributes that are common to PUSH and PULL. + if (dataFlowInform.get(e) == null) { + dataFlowInform.put(e, new HashMap<>()); + } List pushFlows = dataFlowInform.get(e).get(PushPullValue.PUSH); List pullFlows = dataFlowInform.get(e).get(PushPullValue.PULL); - if (pushFlows == null || pullFlows == null) return; + if (pushFlows == null) { + pushFlows = new ArrayList<>(); + } + if (pullFlows == null) { + pullFlows = new ArrayList<>(); + } List pushFlowsOrg = new ArrayList<>(pushFlows); for (ResourceNode r: pullFlows) { pushFlows.remove(r); @@ -371,6 +402,8 @@ for (ResourceNode r: pushFlowsOrg) { pullFlows.remove(r); } + pushFlows = new ArrayList<>(new HashSet<>(pushFlows)); + pullFlows = new ArrayList<>(new HashSet<>(pullFlows)); dataFlowInform.get(e).put(PushPullValue.PUSH, pushFlows); dataFlowInform.get(e).put(PushPullValue.PULL, pullFlows); removeRedundantAttributes(e.getDestination(), dataFlowInform); @@ -408,18 +441,28 @@ for (Edge eIn: resourceNode.getInEdges()) { DataFlowEdge dIn = (DataFlowEdge) eIn; if (((PushPullAttribute) dIn.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - // PUSH transfer + // PUSH data transfer isContainedPush = true; inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), getPushAccessor()); } else { - // PULL transfer + // PULL data transfer for (Edge outEdge: node.getOutEdges()) { + // For each call edge. ObjectNode dstNode = (ObjectNode) outEdge.getDestination(); - List returnedResoueces = dataFlowInform.get(outEdge).get(PushPullValue.PULL); - if (returnedResoueces.contains((ResourceNode) dIn.getSource())) { // The case of returnedResoueces are multiple, ToDo. - MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); - inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), getPullAccessor(dstNode.getName(), nextGetter.getName())); - break; + List returnedResources = dataFlowInform.get(outEdge).get(PushPullValue.PULL); + if (returnedResources.contains((ResourceNode) dIn.getSource())) { + if (returnedResources.size() == 1) { + MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); + inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), getPullAccessor(dstNode.getName(), nextGetter.getName())); + break; + } else { + MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); + int idx = returnedResources.indexOf((ResourceNode) dIn.getSource()); + int len = returnedResources.size(); + inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), + getPullAccessor(langSpec.getTupleGet(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNode.getName()), nextGetter.getName()), idx, len))); + break; + } } } ch = dIn.getChannelGenerator(); // Always unique. @@ -468,7 +511,7 @@ ObjectNode dstNode = (ObjectNode) outEdge.getDestination(); MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); mediateGetter.addStatement( - langSpec.getReturnStatement(langSpec.getMethodInvocation(dstNode.getName(), nextGetter.getName())) + langSpec.getReturnStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNode.getName()), nextGetter.getName())) + langSpec.getStatementDelimiter()); } else { // Unexpected. @@ -486,33 +529,43 @@ component.addMethod(mediateGetter); // Add a return statement. - List params = new ArrayList<>(); - for (ResourceNode rn: resourcesToReturn) { - IdentifierTemplate rId = rn.getIdentifierTemplate(); - if (rId.getResourceName().equals(((ObjectNode) node).getName())) { - params.add(langSpec.getMethodInvocation(getterOfResourceState)); - } else { - for (Edge outEdge: node.getOutEdges()) { - ObjectNode dstNode = (ObjectNode) outEdge.getDestination(); - List returnedResources = dataFlowInform.get(outEdge).get(PushPullValue.PULL); - if (returnedResources.contains(rn)) { - if (returnedResources.size() == 1) { - MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); - params.add(langSpec.getMethodInvocation(dstNode.getName(), nextGetter.getName())); - } else { - MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); - int idx = returnedResources.indexOf(rn); - int len = returnedResources.size(); - params.add(langSpec.getTupleGet(langSpec.getMethodInvocation(dstNode.getName(), nextGetter.getName()), idx, len)); + if (node.getOutdegree() == 1 && resourcesToReturn != null + && resourcesToReturn.equals(dataFlowInform.get(node.getOutEdges().iterator().next()).get(PushPullValue.PULL))) { + // Directly returns the returned value. + Edge outEdge = node.getOutEdges().iterator().next(); + ObjectNode dstNode = (ObjectNode) outEdge.getDestination(); + MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); + String getterInvocation = langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNode.getName()), nextGetter.getName()); + mediateGetter.addStatement(langSpec.getReturnStatement(getterInvocation) + langSpec.getStatementDelimiter()); + } else { + List params = new ArrayList<>(); + for (ResourceNode rn: resourcesToReturn) { + IdentifierTemplate rId = rn.getIdentifierTemplate(); + if (rId.getResourceName().equals(((ObjectNode) node).getName())) { + params.add(langSpec.getMethodInvocation(getterOfResourceState)); + } else { + for (Edge outEdge: node.getOutEdges()) { + ObjectNode dstNode = (ObjectNode) outEdge.getDestination(); + List returnedResources = dataFlowInform.get(outEdge).get(PushPullValue.PULL); + if (returnedResources.contains(rn)) { + if (returnedResources.size() == 1) { + MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); + params.add(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNode.getName()), nextGetter.getName())); + } else { + MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); + int idx = returnedResources.indexOf(rn); + int len = returnedResources.size(); + params.add(langSpec.getTupleGet(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNode.getName()), nextGetter.getName()), idx, len)); + } + break; } - break; } } } + mediateGetter.addStatement( + langSpec.getReturnStatement(langSpec.getConstructorInvocation(returnType.getImplementationTypeName(), params)) + + langSpec.getStatementDelimiter()); } - mediateGetter.addStatement( - langSpec.getReturnStatement(langSpec.getConstructorInvocation(returnType.getImplementationTypeName(), params)) - + langSpec.getStatementDelimiter()); return mediateGetter; } @@ -553,10 +606,16 @@ List returnedResources = dataFlowInform.get(outEdge).get(PushPullValue.PULL); String varName = addInvocationInResourceUpdate(node, updateOrInput, calleeMethod, ((ObjectNode) dstNode).getName(), returnedResources, langSpec); if (varName != null && returnedResources != null) { - varToRes.put(varName, returnedResources); for (ResourceNode rn: returnedResources) { - resToVar.put(rn, varName); + String resName = rn.getIdentifierTemplate().getResourceName(); + resToVar.put(rn, resName); + varToRes.put(resName, Arrays.asList(new ResourceNode[] {rn})); } +// // Alternative implementation. +// varToRes.put(varName, returnedResources); +// for (ResourceNode rn: returnedResources) { +// resToVar.put(rn, varName); +// } } } @@ -597,10 +656,12 @@ updateOrInput = declareUpdateMethod(node, inEdge, component, dataFlowInform, langSpec); component.addMethod(updateOrInput); } - Map resToVar = new HashMap<>(); - Map> varToRes = new HashMap<>(); - for (Edge outEdge: node.getOutEdges()) { - Node dstNode = outEdge.getDestination(); + + if (node.getOutdegree() == 1 && resourcesToReturn != null + && resourcesToReturn.equals(dataFlowInform.get(node.getOutEdges().iterator().next()).get(PushPullValue.PULL))) { + // Directly returns the returned value. + Edge outEdge = node.getOutEdges().iterator().next(); + ObjectNode dstNode = (ObjectNode) outEdge.getDestination(); MethodDeclaration calleeMethod = declareAndFillUpdateAndInputMethods(dstNode, outEdge, prevResNode, dataFlowInform, componentMap, langSpec); if (updateOrInput == null && prevResNode instanceof EntryPointObjectNode) { // Declare an input method. @@ -611,23 +672,49 @@ } component.addMethod(updateOrInput); } - // Add a statement to call the destination method. - List returnedResources = dataFlowInform.get(outEdge).get(PushPullValue.PULL); - String varName = addInvocationInMediatorUpdate(updateOrInput, calleeMethod, ((ObjectNode) dstNode).getName(), returnedResources, langSpec); - if (varName != null && returnedResources != null) { - varToRes.put(varName, returnedResources); - for (ResourceNode rn: returnedResources) { - resToVar.put(rn, varName); + // Set the return type and add a return statement. + updateOrInput.setReturnType(calleeMethod.getReturnType()); + String updateInvocation = langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNode.getName()), calleeMethod.getName()); + updateOrInput.addStatement(langSpec.getReturnStatement(updateInvocation) + langSpec.getStatementDelimiter()); + } else { + Map resToVar = new HashMap<>(); + Map> varToRes = new HashMap<>(); + for (Edge outEdge: node.getOutEdges()) { + Node dstNode = outEdge.getDestination(); + MethodDeclaration calleeMethod = declareAndFillUpdateAndInputMethods(dstNode, outEdge, prevResNode, dataFlowInform, componentMap, langSpec); + if (updateOrInput == null && prevResNode instanceof EntryPointObjectNode) { + // Declare an input method. + if (calleeMethod.getParameters() != null) { + updateOrInput = langSpec.newMethodDeclaration(calleeMethod.getName(), false, null, new ArrayList<>(calleeMethod.getParameters())); + } else { + updateOrInput = langSpec.newMethodDeclaration(calleeMethod.getName(), null); + } + component.addMethod(updateOrInput); + } + // Add a statement to call the destination method. + List returnedResources = dataFlowInform.get(outEdge).get(PushPullValue.PULL); + String varName = addInvocationInMediatorUpdate(updateOrInput, calleeMethod, ((ObjectNode) dstNode).getName(), returnedResources, langSpec); + if (varName != null && returnedResources != null) { + for (ResourceNode rn: returnedResources) { + String resName = rn.getIdentifierTemplate().getResourceName(); + resToVar.put(rn, resName); + varToRes.put(resName, Arrays.asList(new ResourceNode[] {rn})); + } +// // Alternative implementation. +// varToRes.put(varName, returnedResources); +// for (ResourceNode rn: returnedResources) { +// resToVar.put(rn, varName); +// } } } - } - if (resourcesToReturn != null && resourcesToReturn.size() > 0) { - // Set the return type and add a return statement. - Type returnType = createReturnType(resourcesToReturn, langSpec); - updateOrInput.setReturnType(returnType); - String returnValue = createReturnValue(resourcesToReturn, node, returnType, resToVar, varToRes, langSpec); - updateOrInput.addStatement(langSpec.getReturnStatement(returnValue) + langSpec.getStatementDelimiter()); - } + if (resourcesToReturn != null && resourcesToReturn.size() > 0) { + // Set the return type and add a return statement. + Type returnType = createReturnType(resourcesToReturn, langSpec); + updateOrInput.setReturnType(returnType); + String returnValue = createReturnValue(resourcesToReturn, node, returnType, resToVar, varToRes, langSpec); + updateOrInput.addStatement(langSpec.getReturnStatement(returnValue) + langSpec.getStatementDelimiter()); + } + } return updateOrInput; } } @@ -866,8 +953,8 @@ resourceUpdateMethod.addStatement( langSpec.getDecomposedTuple( langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNodeName), calleeMethod.getName(), params), - targetVar, - vars)); + targetVar, // ResType res = this.dst.updateSrc(value, refParams); + vars)); // Type1 res1 = res.getKey(); Type2 res2 = res.getValue(); } return targetVarName; } @@ -907,8 +994,8 @@ resourceUpdateMethod.addStatement( langSpec.getDecomposedTuple( langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNodeName), calleeMethod.getName(), params), - targetVar, - vars)); + targetVar, // ResType res = this.dst.updateSrc(value, refParams); + vars)); // Type1 res1 = res.getKey(); Type2 res2 = res.getValue(); } return targetVarName; } @@ -1480,4 +1567,26 @@ } }; } + + public static IResourceStateAccessor getPullAccessor(final String resourceAccessor) { + return new IResourceStateAccessor() { + @Override + public Expression getCurrentStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { + if (target.equals(from)) { + return new Field(fieldOfResourceState, + target.getResourceStateType() != null ? target.getResourceStateType() + : DataConstraintModel.typeInt); + } + // for reference channel member + Term getter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); + getter.addChild(new Field(target.getResourceName(), target.getResourceStateType())); + return getter; + } + + @Override + public Expression getNextStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { + return new Constant(resourceAccessor); + } + }; + } }