diff --git a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java index fb48b10..4e190bf 100644 --- a/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java +++ b/AlgebraicDataflowArchitectureModel/src/algorithms/TypeInference.java @@ -1516,7 +1516,7 @@ } } - private static Type createNewListType(Type compType, Type parentType) { + public static Type createNewListType(Type compType, Type parentType) { String compTypeName = getInterfaceTypeName(compType); List childrenTypes = getChildrenTypes(parentType, listComponentTypes.keySet()); Type newListType = new Type("List", "ArrayList<>", "List<" + compTypeName + ">", parentType); @@ -1536,7 +1536,7 @@ return newListType; } - private static Type createNewTupleType(List componentTypes, Type parentTupleType) { + public static Type createNewTupleType(List componentTypes, Type parentTupleType) { String implTypeName = "AbstractMap.SimpleEntry<>"; String interfaceTypeName = "Map.Entry<$x>"; if (componentTypes.size() >= 2) { @@ -1571,7 +1571,7 @@ return newTupleType; } - private static Type createNewMapType(List componentTypes, Type parentMapType) { + public static Type createNewMapType(List componentTypes, Type parentMapType) { String implTypeName = "HashMap<>"; String interfaceTypeName = "Map<$x, $y>"; if (componentTypes.size() == 2) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 86f5e35..beae21c 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -7,6 +7,7 @@ import java.util.Map; import java.util.Set; +import algorithms.TypeInference; import code.ast.Block; import code.ast.CompilationUnit; import code.ast.FieldDeclaration; @@ -16,19 +17,24 @@ import models.Edge; import models.Node; import models.algebra.Expression; +import models.algebra.Field; import models.algebra.InvalidMessage; +import models.algebra.Parameter; import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.Symbol; import models.algebra.Term; import models.algebra.Type; import models.algebra.UnificationFailed; import models.algebra.ValueUndefined; import models.algebra.Variable; +import models.controlFlowModel.CallEdge; import models.controlFlowModel.ControlFlowGraph; import models.controlFlowModel.EntryPointObjectNode; import models.controlFlowModel.ObjectNode; import models.controlFlowModel.StatefulObjectNode; import models.dataConstraintModel.ChannelGenerator; import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.DataConstraintModel; import models.dataConstraintModel.IdentifierTemplate; import models.dataFlowModel.DataFlowEdge; import models.dataFlowModel.DataFlowGraph; @@ -212,18 +218,28 @@ private static void generateCodeFromControlFlowGraph(DataTransferModel model, ControlFlowGraph controlFlowGraph, ArrayList components, TypeDeclaration mainComponent, MethodDeclaration mainConstructor, ArrayList codes, ILanguageSpecific langSpec) { + // Reconstruct data-flow information. + Map>> dataFlowInform = new HashMap<>(); + for (Node root: controlFlowGraph.getPushCallGraph().getRootNodes()) { + annotateDataFlowAttributes(root, dataFlowInform, new ArrayList<>()); + removeRedundantAttributes(root, dataFlowInform); + } + for (Node root: controlFlowGraph.getPullCallGraph().getRootNodes()) { + annotateDataFlowAttributes(root, dataFlowInform, new ArrayList<>()); + removeRedundantAttributes(root, dataFlowInform); + } + // For each of other components. + Map componentMap = new HashMap<>(); for (Node componentNode: components) { // Declare this component. String componentName = langSpec.toComponentName(((ObjectNode) componentNode).getName()); TypeDeclaration component = langSpec.newTypeDeclaration(componentName); + componentMap.put(componentNode, component); - // Declare the constructor and the fields to refer to other resources (to the callee components). + // Declare the constructor and the fields to refer to the callee components. List depends = new ArrayList<>(); - MethodDeclaration constructor = declareConstructorAndFieldsToCalleeComponents((ObjectNode) componentNode, component, depends, langSpec); - - // Update the main component for this component. - updateMainComponent(model, mainComponent, mainConstructor, componentNode, depends, langSpec); + MethodDeclaration constructor = declareConstructorAndFieldsToCalleeComponents((ObjectNode) componentNode, component, depends, langSpec); if (componentNode instanceof StatefulObjectNode) { // For this resource. @@ -237,21 +253,15 @@ component.addField(stateField); } - // Declare the getter method in this resource to obtain the state. - MethodDeclaration getter = declareGetterMethod(resourceNode, component, resStateType, langSpec); - // Declare the accessor method in the main component to call the getter method. declareAccessorInMainComponent(mainComponent, resId, langSpec); // Declare the fields to refer to reference resources. - declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends, langSpec); - - // Declare cache fields and update methods in this resource. - List updates = declareCacheFieldsAndUpdateMethods(resourceNode, component, langSpec); - - // Declare input methods in this component and the main component. - List inputs = declareInputMethodsInThisAndMainComponents(resourceNode, component, mainComponent, model, langSpec); + declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends, langSpec); } + + // Update the main component for this component. + updateMainComponent(model, mainComponent, mainConstructor, componentNode, depends, langSpec); if (constructor.getParameters() == null) { component.removeMethod(constructor); } @@ -260,9 +270,499 @@ CompilationUnit cu = langSpec.newCompilationUnit(component); codes.add(cu); } + + // Declare and Fill the getter method to return the resource state. + for (Node node: controlFlowGraph.getPushCallGraph().getNodes()) { + TypeDeclaration component = componentMap.get(node); + if (node instanceof StatefulObjectNode) { + ResourceNode resourceNode = ((StatefulObjectNode) node).getResource(); + Type resStateType = resourceNode.getIdentifierTemplate().getResourceStateType(); + if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { + // Declare the getter method in this resource to obtain the state. + MethodDeclaration getter = langSpec.newMethodDeclaration(getterOfResourceState, resStateType); + component.addMethod(getter); + fillGetterMethodToReturnStateField(getter, resourceNode.getIdentifierTemplate().getResourceStateType(), langSpec); // return this.value; + } + } + } + + for (Node node: controlFlowGraph.getPullCallGraph().getNodes()) { + String nodeName = ((ObjectNode) node).getName(); + if (componentMap.get(node) == null) { + for (Node node2: componentMap.keySet()) { + if (((ObjectNode) node2).getName().equals(nodeName)) { + componentMap.put(node, componentMap.get(node2)); // Since nodes shared by PUSH and PULL call graphs are duplicated. + break; + } + } + } + } + + // Declare other getter methods. + for (Node root: controlFlowGraph.getPullCallGraph().getRootNodes()) { + MethodDeclaration getter = declareAndFillGetterMethods(root, null, dataFlowInform, componentMap, langSpec); + } + + // Declare update and input methods. + for (Node root: controlFlowGraph.getPushCallGraph().getRootNodes()) { + MethodDeclaration input = declareAndFillUpdateAndInputMethods(root, null, null, dataFlowInform, componentMap, langSpec); + mainComponent.addMethod(input); + } + } + + private static void annotateDataFlowAttributes(Node node, Map>> dataFlowInform, List path) { + if (node instanceof StatefulObjectNode) { + // Add data-flow attributes to the path to node. + ResourceNode resNode = ((StatefulObjectNode) node).getResource(); + if (resNode.getOutdegree() > 0) { + // 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); + } + List pullSrcs = edgeAttributes.get(PushPullValue.PULL); + if (pullSrcs == null) { + pullSrcs = new ArrayList<>(); + edgeAttributes.put(PushPullValue.PULL, pullSrcs); + } + if (!pullSrcs.contains(resNode)) { + 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); + } + List pushSrcs = edgeAttributes.get(PushPullValue.PUSH); + if (pushSrcs == null) { + pushSrcs = new ArrayList<>(); + edgeAttributes.put(PushPullValue.PUSH, pushSrcs); + } + if (!pushSrcs.contains(srcOfDataFlowNode)) { + pushSrcs.add(srcOfDataFlowNode); + } + } + } + } + // Traverse the call tree. + for (Edge e: node.getOutEdges()) { + path.add(e); + annotateDataFlowAttributes(e.getDestination(), dataFlowInform, path); + path.remove(e); + } } - private static void updateMainComponent(DataTransferModel model, TypeDeclaration mainType, MethodDeclaration mainConstructor, Node componentNode, List depends, ILanguageSpecific langSpec) { + private static void removeRedundantAttributes(Node node, Map>> dataFlowInform) { + // Traverse the call tree. + for (Edge e: node.getOutEdges()) { + // Remove attributes that are common to PUSH and PULL. + List pushFlows = dataFlowInform.get(e).get(PushPullValue.PUSH); + List pullFlows = dataFlowInform.get(e).get(PushPullValue.PULL); + if (pushFlows == null || pullFlows == null) return; + List pushFlowsOrg = new ArrayList<>(pushFlows); + pushFlows.removeAll(pullFlows); + pullFlows.removeAll(pushFlowsOrg); + dataFlowInform.get(e).put(PushPullValue.PUSH, pushFlows); + dataFlowInform.get(e).put(PushPullValue.PULL, pullFlows); + removeRedundantAttributes(e.getDestination(), dataFlowInform); + } + } + + private static MethodDeclaration declareAndFillGetterMethods(Node node, Edge inEdge, + Map>> dataFlowInform, Map componentMap, + ILanguageSpecific langSpec) { + TypeDeclaration component = componentMap.get(node); + List resourcesToReturn = null; + if (inEdge != null) { + resourcesToReturn = dataFlowInform.get(inEdge).get(PushPullValue.PULL); + } + if (node instanceof StatefulObjectNode) { + ResourceNode resourceNode = ((StatefulObjectNode) node).getResource(); + Type resStateType = resourceNode.getIdentifierTemplate().getResourceStateType(); + MethodDeclaration getter = langSpec.newMethodDeclaration(getterOfResourceState, resStateType); + MethodDeclaration getter2 = getMethod(component, getter.getName()); + if (getter2 == null) { + component.addMethod(getter); + } else { + getter = getter2; + } + if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { + if (getter2 == null) { + // Declare the getter method in this resource to obtain the state. + fillGetterMethodToReturnStateField(getter, resourceNode.getIdentifierTemplate().getResourceStateType(), langSpec); // return this.value; + } + } else { + // Invocations to other getter methods when at least one incoming data-flow edges is PULL-style. + boolean isContainedPush = false; + DataTransferChannelGenerator ch = null; + HashMap inputIdentifierToStateAccessor = new HashMap<>(); + for (Edge eIn: resourceNode.getInEdges()) { + DataFlowEdge dIn = (DataFlowEdge) eIn; + if (((PushPullAttribute) dIn.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { + // PUSH transfer + isContainedPush = true; + inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), getPushAccessor()); + } else { + // PULL transfer + for (Edge outEdge: node.getOutEdges()) { + 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; + } + } + ch = dIn.getChannelGenerator(); // Always unique. + } + } + // For reference channel members. + for (ChannelMember c: ch.getReferenceChannelMembers()) { + inputIdentifierToStateAccessor.put(c.getIdentifierTemplate(), getPullAccessor()); // by pull data transfer + } + + // Add a return statement. + try { + for (ChannelMember out: ch.getOutputChannelMembers()) { + if (out.getIdentifierTemplate() == resourceNode.getIdentifierTemplate()) { + String[] sideEffects = new String[] {""}; + if (!isContainedPush) { + // All incoming edges are in PULL-style. + String curState = ch.deriveUpdateExpressionOf(out, getPullAccessor()).toImplementation(sideEffects); + getter.addStatement(sideEffects[0] + langSpec.getReturnStatement(curState) + langSpec.getStatementDelimiter()); + } else { + // At least one incoming edge is in PUSH-style. + String curState = ch.deriveUpdateExpressionOf(out, getPullAccessor(), inputIdentifierToStateAccessor).toImplementation(sideEffects); + getter.addStatement(sideEffects[0] + langSpec.getReturnStatement(curState) + langSpec.getStatementDelimiter()); + } + break; + } + } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + } + if (resourcesToReturn == null || resourcesToReturn.size() == 1) return getter; + } else if (resourcesToReturn == null || resourcesToReturn.size() == 1) { + // Declare and fill a mediate getter method. + String getterMethodName = "get"; + ResourceNode returnedRes = null; + if (resourcesToReturn != null) { + returnedRes = resourcesToReturn.get(0); + } else { + // Unexpected. + } + getterMethodName += langSpec.toComponentName(returnedRes.getIdentifierTemplate().getResourceName()) + "Value"; + MethodDeclaration mediateGetter = langSpec.newMethodDeclaration(getterMethodName, returnedRes.getIdentifierTemplate().getResourceStateType()); + component.addMethod(mediateGetter); + return mediateGetter; + } + // Declare a mediate getter method to return multiple values. + String getterMethodName = "get"; + List compTypes = new ArrayList<>(); + for (ResourceNode rn: resourcesToReturn) { + getterMethodName += langSpec.toComponentName(rn.getIdentifierTemplate().getResourceName()); + IdentifierTemplate rId = rn.getIdentifierTemplate(); + compTypes.add(rId.getResourceStateType()); + } + getterMethodName += "Values"; + Type returnType = TypeInference.createNewTupleType(compTypes, DataConstraintModel.typeTuple); + MethodDeclaration mediateGetter = langSpec.newMethodDeclaration(getterMethodName, returnType); + 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)) { // The case of returnedResoueces are multiple, ToDo. + MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); + params.add(langSpec.getMethodInvocation(dstNode.getName(), nextGetter.getName())); + break; + } + } + } + } + mediateGetter.addStatement( + langSpec.getReturnStatement(langSpec.getConstructorInvocation(returnType.getImplementationTypeName(), params)) + + langSpec.getStatementDelimiter()); + return mediateGetter; + } + + private static MethodDeclaration declareAndFillUpdateAndInputMethods(Node node, Edge inEdge, Node prevResNode, + Map>> dataFlowInform, Map componentMap, ILanguageSpecific langSpec) { + TypeDeclaration component = componentMap.get(node); + if (node instanceof StatefulObjectNode) { + // Declare update or input method in the resource component. + ResourceNode resourceNode = ((StatefulObjectNode) node).getResource(); + MethodDeclaration updateOrInput = null; + if (!(prevResNode instanceof EntryPointObjectNode)) { + updateOrInput = getUpdateMethod(inEdge, component, dataFlowInform, langSpec); + if (updateOrInput != null) return updateOrInput; + // Declare an update method. + updateOrInput = declareUpdateMethod(node, inEdge, component, dataFlowInform, langSpec); + } else { + DataTransferChannelGenerator ch = ((EntryPointObjectNode) prevResNode).getIoChannelGenerator(); + updateOrInput = getInputMethod(resourceNode, ch, component); + if (updateOrInput != null) return updateOrInput; + // Declare an input method. + updateOrInput = declareInputMethod(resourceNode, ch, langSpec); + } + component.addMethod(updateOrInput); + + for (Edge outEdge: node.getOutEdges()) { + Node dstNode = outEdge.getDestination(); + MethodDeclaration calleeMethod = declareAndFillUpdateAndInputMethods(dstNode, outEdge, node, dataFlowInform, componentMap, langSpec); + // Add a statement to call the destination method. + addInvocationInResourceUpdate(node, updateOrInput, calleeMethod, ((ObjectNode) dstNode).getName(), langSpec); + } + return updateOrInput; + } else if (node instanceof EntryPointObjectNode) { + // Declare an input method. + MethodDeclaration input = null; + for (Edge outEdge: node.getOutEdges()) { + Node dstNode = outEdge.getDestination(); + MethodDeclaration calleeMethod = declareAndFillUpdateAndInputMethods(dstNode, outEdge, node, dataFlowInform, componentMap, langSpec); + if (input == null) { + // Declare an input method. + input = langSpec.newMethodDeclaration(calleeMethod.getName(), false, null, new ArrayList<>(calleeMethod.getParameters())); + } + // Add a statement to call the destination method. + addInvocationInMediatorUpdate(input, calleeMethod, ((ObjectNode) dstNode).getName(), dataFlowInform, langSpec); + } + return input; + } else { + // Declare update or input method in the mediate component. + List updateMethods = getUpdateMethods(component); + if (updateMethods.size() > 0) return updateMethods.get(0); + MethodDeclaration updateOrInput = null; + if (!(prevResNode instanceof EntryPointObjectNode)) { + // Declare an update method. + updateOrInput = declareUpdateMethod(node, inEdge, component, dataFlowInform, langSpec); + component.addMethod(updateOrInput); + } + 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. + updateOrInput = langSpec.newMethodDeclaration(calleeMethod.getName(), false, null, new ArrayList<>(calleeMethod.getParameters())); + component.addMethod(updateOrInput); + } + // Add a statement to call the destination method. + addInvocationInMediatorUpdate(updateOrInput, calleeMethod, ((ObjectNode) dstNode).getName(), dataFlowInform, langSpec); + } + return updateOrInput; + } + } + + private static MethodDeclaration getUpdateMethod(Edge inEdge, TypeDeclaration component, + Map>> dataFlowInform, ILanguageSpecific langSpec) { + List passedResoueces = dataFlowInform.get(inEdge).get(PushPullValue.PUSH); + String methodName = updateMethodName; + for (ResourceNode rn: passedResoueces) { + IdentifierTemplate rId = rn.getIdentifierTemplate(); + methodName += langSpec.toComponentName(rId.getResourceName()); + } + return getMethod(component, methodName); + } + + private static MethodDeclaration declareUpdateMethod(Node node, Edge inEdge, TypeDeclaration component, + Map>> dataFlowInform, ILanguageSpecific langSpec) { + // Declare an update method in the component. + ArrayList vars = new ArrayList<>(); + List passedResoueces = dataFlowInform.get(inEdge).get(PushPullValue.PUSH); + Set passedIds = new HashSet<>(); + String methodName = updateMethodName; + for (ResourceNode rn: passedResoueces) { + IdentifierTemplate rId = rn.getIdentifierTemplate(); + passedIds.add(rId); + methodName += langSpec.toComponentName(rId.getResourceName()); + vars.add(langSpec.newVariableDeclaration(rId.getResourceStateType(), rId.getResourceName())); + } + MethodDeclaration update = langSpec.newMethodDeclaration(methodName, false, null, vars); + + if (node instanceof StatefulObjectNode) { + // Add a statement to update the state field + ResourceNode resourceNode = ((StatefulObjectNode) node).getResource(); + if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { + try { + for (Edge e: resourceNode.getInEdges()) { + DataFlowEdge re = (DataFlowEdge) e; + for (ChannelMember in: re.getChannelGenerator().getInputChannelMembers()) { + if (passedIds.contains(in.getIdentifierTemplate())) { + for (ChannelMember out: re.getChannelGenerator().getOutputChannelMembers()) { + if (out.getIdentifierTemplate() == resourceNode.getIdentifierTemplate()) { + Expression updateExp = re.getChannelGenerator().deriveUpdateExpressionOf(out, getPushAccessor()); + String[] sideEffects = new String[] {""}; + String curState = updateExp.toImplementation(sideEffects); + String updateStatement; + if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + updateStatement = sideEffects[0]; + } else { + updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + curState + langSpec.getStatementDelimiter(); // this.value = ... + } + update.addFirstStatement(updateStatement); + break; + } + } + } + } + } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e1) { + e1.printStackTrace(); + } + } + + // Declare the field to cache the state of the source resource in the type of the destination resource. + if (node.getIndegree() > 1) { + // If incoming edges are multiple + for (IdentifierTemplate srcRes: passedIds) { + String srcResName = srcRes.getResourceName(); + if (langSpec.declareField()) { + // Declare the cache field. + FieldDeclaration cacheField = langSpec.newFieldDeclaration( + srcRes.getResourceStateType(), + srcResName, + langSpec.getFieldInitializer(srcRes.getResourceStateType(), srcRes.getInitialValue())); + component.addField(cacheField); + + } + // Update the cache field. + String cashStatement = langSpec.getFieldAccessor(srcResName) + langSpec.getAssignment() + srcResName + langSpec.getStatementDelimiter(); + update.addFirstStatement(cashStatement); + } + } + } + return update; + } + + + private static MethodDeclaration getInputMethod(ResourceNode resourceNode, DataTransferChannelGenerator ch, TypeDeclaration component) { + MethodDeclaration input = null; + for (ChannelMember out : ch.getOutputChannelMembers()) { + if (out.getIdentifierTemplate().equals(resourceNode.getIdentifierTemplate())) { + Expression message = out.getStateTransition().getMessageExpression(); + if (message instanceof Term) { + input = getMethod(component, ((Term) message).getSymbol().getImplName()); + } else if (message instanceof Variable) { + // Declare an input method in this component. + input = getMethod(component, ((Variable) message).getName()); + } + break; + } + } + return input; + } + + private static MethodDeclaration declareInputMethod(ResourceNode resourceNode, DataTransferChannelGenerator ch, ILanguageSpecific langSpec) { + MethodDeclaration input = null; + for (ChannelMember out : ch.getOutputChannelMembers()) { + if (out.getIdentifierTemplate().equals(resourceNode.getIdentifierTemplate())) { + Expression message = out.getStateTransition().getMessageExpression(); + if (message instanceof Term) { + // Declare an input method in this component. + ArrayList params = new ArrayList<>(); + for (Variable var: message.getVariables().values()) { + params.add(langSpec.newVariableDeclaration(var.getType(), var.getName())); + } + input = langSpec.newMethodDeclaration(((Term) message).getSymbol().getImplName(), false, null, params); + } else if (message instanceof Variable) { + // Declare an input method in this component. + input = langSpec.newMethodDeclaration(((Variable) message).getName(), null); + } + + if (input != null) { + // Add a statement to update the state field to the input method. + try { + String[] sideEffects = new String[] {""}; + Expression updateExp; + updateExp = ch.deriveUpdateExpressionOf(out, getPullAccessor()); + String newState = updateExp.toImplementation(sideEffects); + String updateStatement; + if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { + updateStatement = sideEffects[0]; + } else { + updateStatement = sideEffects[0] + langSpec.getFieldAccessor(fieldOfResourceState) + langSpec.getAssignment() + newState + langSpec.getStatementDelimiter(); + } + input.addFirstStatement(updateStatement); + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + } + break; + } + } + return input; + } + + private static void addInvocationInResourceUpdate(Node node, MethodDeclaration resourceUpdateMethod, MethodDeclaration calleeMethod, String dstNodeName, ILanguageSpecific langSpec) { + List params = new ArrayList<>(); + params.add(langSpec.getFieldAccessor(fieldOfResourceState)); + for (VariableDeclaration v: calleeMethod.getParameters()) { + if (!((ObjectNode) node).getName().equals(v.getName())) { + params.add(v.getName()); + } + } +// for (ChannelMember rc: re.getChannelGenerator().getReferenceChannelMembers()) { +// // to get the value of reference member. +// IdentifierTemplate ref = rc.getIdentifierTemplate(); +// if (referredSet == null) { +// referredSet = new HashSet<>(); +// referredResources.put(update, referredSet); +// } +// if (ref != resourceNode.getIdentifierTemplate()) { +// String refVarName = ref.getResourceName(); +// if (!referredSet.contains(ref)) { +// referredSet.add(ref); +// Expression refGetter = langSpec.getPullAccessor().getCurrentStateAccessorFor(ref, ((ResourceNode) dOut.getSource()).getIdentifierTemplate()); +// String[] sideEffects = new String[] {""}; +// String refExp = refGetter.toImplementation(sideEffects); +// String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); +// resourceUpdateMethod.addFirstStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); +// } +// params.add(refVarName); +// } +// } + resourceUpdateMethod.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNodeName), + calleeMethod.getName(), + params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); + + } + + + private static void addInvocationInMediatorUpdate(MethodDeclaration resourceUpdateMethod, MethodDeclaration calleeMethod, String dstNodeName, Map>> dataFlowInform, ILanguageSpecific langSpec) { + Map> referredResources = new HashMap<>(); + List params = new ArrayList<>(); + for (VariableDeclaration v: calleeMethod.getParameters()) { + params.add(v.getName()); + } + resourceUpdateMethod.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNodeName), + calleeMethod.getName(), + params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); + + } + + private static void updateMainComponent(DataTransferModel model, TypeDeclaration mainType, MethodDeclaration mainConstructor, Node componentNode, + final List depends, ILanguageSpecific langSpec) { // Declare the field to refer to each object in the main type. ResourceNode resNode = null; String nodeName = null; @@ -381,25 +881,7 @@ component.addMethod(getter); if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { - // returns the state field when all incoming data-flow edges are PUSH-style. - if (langSpec.isValueType(resStateType)) { - getter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState)) + langSpec.getStatementDelimiter()); // return value; - } else { - // copy the current state to be returned as a 'value' - String implTypeName = resStateType.getImplementationTypeName(); -// String interfaceTypeName = resourceType.getInterfaceTypeName(); -// String concreteTypeName; -// if (interfaceTypeName.contains("<")) { -// String typeName = implTypeName.substring(0, implTypeName.indexOf("<")); -//// String generics = interfaceTypeName.substring(interfaceTypeName.indexOf("<") + 1, interfaceTypeName.lastIndexOf(">")); -// concreteTypeName = typeName + "<>"; -// } else { -// concreteTypeName = implTypeName; -// } - List parameters = new ArrayList<>(); - parameters.add(langSpec.getFieldAccessor(fieldOfResourceState)); - getter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters)) + langSpec.getStatementDelimiter()); // return new Resource(value); - } + fillGetterMethodToReturnStateField(getter, resStateType, langSpec); } else { // invocations to other getter methods when at least one incoming data-flow edges is PULL-style. boolean isContainedPush = false; @@ -410,16 +892,16 @@ if (((PushPullAttribute) dIn.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { // PUSH transfer isContainedPush = true; - inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), langSpec.getPushAccessor()); + inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), getPushAccessor()); } else { // PULL transfer - inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), langSpec.getPullAccessor()); + inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), getPullAccessor()); ch = dIn.getChannelGenerator(); } } // for reference channel members. for (ChannelMember c: ch.getReferenceChannelMembers()) { - inputIdentifierToStateAccessor.put(c.getIdentifierTemplate(), langSpec.getPullAccessor()); // by pull data transfer + inputIdentifierToStateAccessor.put(c.getIdentifierTemplate(), getPullAccessor()); // by pull data transfer } // generate a return statement. @@ -429,11 +911,11 @@ String[] sideEffects = new String[] {""}; if (!isContainedPush) { // All incoming edges are in PULL-style. - String curState = ch.deriveUpdateExpressionOf(out, langSpec.getPullAccessor()).toImplementation(sideEffects); + String curState = ch.deriveUpdateExpressionOf(out, getPullAccessor()).toImplementation(sideEffects); getter.addStatement(sideEffects[0] + langSpec.getReturnStatement(curState) + langSpec.getStatementDelimiter()); } else { // At least one incoming edge is in PUSH-style. - String curState = ch.deriveUpdateExpressionOf(out, langSpec.getPullAccessor(), inputIdentifierToStateAccessor).toImplementation(sideEffects); + String curState = ch.deriveUpdateExpressionOf(out, getPullAccessor(), inputIdentifierToStateAccessor).toImplementation(sideEffects); getter.addStatement(sideEffects[0] + langSpec.getReturnStatement(curState) + langSpec.getStatementDelimiter()); } break; @@ -448,6 +930,28 @@ return getter; } + private static void fillGetterMethodToReturnStateField(MethodDeclaration getter, Type resStateType, ILanguageSpecific langSpec) { + // returns the state field when all incoming data-flow edges are PUSH-style. + if (langSpec.isValueType(resStateType)) { + getter.addStatement(langSpec.getReturnStatement(langSpec.getFieldAccessor(fieldOfResourceState)) + langSpec.getStatementDelimiter()); // return value; + } else { + // copy the current state to be returned as a 'value' + String implTypeName = resStateType.getImplementationTypeName(); +// String interfaceTypeName = resourceType.getInterfaceTypeName(); +// String concreteTypeName; +// if (interfaceTypeName.contains("<")) { +// String typeName = implTypeName.substring(0, implTypeName.indexOf("<")); +//// String generics = interfaceTypeName.substring(interfaceTypeName.indexOf("<") + 1, interfaceTypeName.lastIndexOf(">")); +// concreteTypeName = typeName + "<>"; +// } else { +// concreteTypeName = implTypeName; +// } + List parameters = new ArrayList<>(); + parameters.add(langSpec.getFieldAccessor(fieldOfResourceState)); + getter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters)) + langSpec.getStatementDelimiter()); // return new Resource(value); + } + } + private static void declareAccessorInMainComponent(TypeDeclaration mainComponent, IdentifierTemplate accessResId, ILanguageSpecific langSpec) { MethodDeclaration getter = new MethodDeclaration("get" + langSpec.toComponentName(accessResId.getResourceName()), accessResId.getResourceStateType()); Block block = new Block(); @@ -457,7 +961,7 @@ } private static void declareFieldsToReferenceResources(DataTransferModel model, ResourceNode resourceNode, TypeDeclaration component, MethodDeclaration constructor, - List depends, ILanguageSpecific langSpec) { + final List depends, ILanguageSpecific langSpec) { Set refs = new HashSet<>(); for (ChannelGenerator ch : model.getChannelGenerators()) { DataTransferChannelGenerator c = (DataTransferChannelGenerator) ch; @@ -506,7 +1010,7 @@ try { for (ChannelMember out: re.getChannelGenerator().getOutputChannelMembers()) { if (out.getIdentifierTemplate() == resourceNode.getIdentifierTemplate()) { - Expression updateExp = re.getChannelGenerator().deriveUpdateExpressionOf(out, langSpec.getPushAccessor()); + Expression updateExp = re.getChannelGenerator().deriveUpdateExpressionOf(out, getPushAccessor()); String[] sideEffects = new String[] {""}; String curState = updateExp.toImplementation(sideEffects); String updateStatement; @@ -566,7 +1070,7 @@ String refVarName = ref.getResourceName(); if (!referredSet.contains(ref)) { referredSet.add(ref); - Expression refGetter = langSpec.getPullAccessor().getCurrentStateAccessorFor(ref, ((ResourceNode) dOut.getSource()).getIdentifierTemplate()); + Expression refGetter = getPullAccessor().getCurrentStateAccessorFor(ref, ((ResourceNode) dOut.getSource()).getIdentifierTemplate()); String[] sideEffects = new String[] {""}; String refExp = refGetter.toImplementation(sideEffects); String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); @@ -656,7 +1160,7 @@ try { String[] sideEffects = new String[] {""}; Expression updateExp; - updateExp = ((DataTransferChannelGenerator) ch).deriveUpdateExpressionOf(out, langSpec.getPullAccessor()); + updateExp = ((DataTransferChannelGenerator) ch).deriveUpdateExpressionOf(out, getPullAccessor()); String newState = updateExp.toImplementation(sideEffects); String updateStatement; if (updateExp instanceof Term && ((Term) updateExp).getSymbol().isImplWithSideEffect()) { @@ -690,7 +1194,7 @@ String refVarName = ref.getResourceName(); if (!referredSet.contains(ref)) { referredSet.add(ref); - Expression refGetter = langSpec.getPullAccessor().getCurrentStateAccessorFor(ref, ((ResourceNode) dOut.getSource()).getIdentifierTemplate()); + Expression refGetter = getPullAccessor().getCurrentStateAccessorFor(ref, ((ResourceNode) dOut.getSource()).getIdentifierTemplate()); String[] sideEffects = new String[] {""}; String refExp = refGetter.toImplementation(sideEffects); String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); @@ -717,4 +1221,96 @@ } return null; } + + private static List getGetterMethods(TypeDeclaration component) { + List getters = new ArrayList<>(); + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().startsWith("get")) { + getters.add(m); + } + } + return getters; + } + + private static List getUpdateMethods(TypeDeclaration component) { + List updates = new ArrayList<>(); + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().startsWith(updateMethodName)) { + updates.add(m); + } + } + return updates; + } + + public static IResourceStateAccessor getPushAccessor() { + 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 + return new Parameter(target.getResourceName(), + target.getResourceStateType() != null ? target.getResourceStateType() + : DataConstraintModel.typeInt); + } + + @Override + public Expression getNextStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { + return new Parameter(target.getResourceName(), + target.getResourceStateType() != null ? target.getResourceStateType() + : DataConstraintModel.typeInt); + } + }; + } + + public static IResourceStateAccessor getPullAccessor() { + 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) { + Term getter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); + getter.addChild(new Field(target.getResourceName(), target.getResourceStateType())); + return getter; + } + }; + } + + public static IResourceStateAccessor getPullAccessor(final String receiverName, final String getterOfResourceState) { + 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(receiverName, target.getResourceStateType())); + return getter; + } + + @Override + public Expression getNextStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { + Term getter = new Term(new Symbol(getterOfResourceState, 1, Symbol.Type.METHOD)); + getter.addChild(new Field(receiverName, target.getResourceStateType())); + return getter; + } + }; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java index 3b4f817..0325db8 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java @@ -24,6 +24,7 @@ String getFieldInitializer(Type type, Expression initialValue); boolean declareField(); String getFieldAccessor(String fieldName); + String getMethodInvocation(String methodName); String getMethodInvocation(String receivertName, String methodName); String getMethodInvocation(String receivertName, String methodName, List parameters); String getConstructorInvocation(String componentName, List parameters); @@ -33,6 +34,4 @@ String getAssignment(); String getStatementDelimiter(); boolean isValueType(Type resStateType); - IResourceStateAccessor getPushAccessor(); - IResourceStateAccessor getPullAccessor(); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java index ac4715c..dd8a032 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java @@ -21,6 +21,7 @@ public class JavaSpecific implements ILanguageSpecific { public static final Type typeVoid = new Type("Void", "void"); + public static final String self = "this"; @Override public CompilationUnit newCompilationUnit(TypeDeclaration component) { @@ -93,7 +94,12 @@ @Override public String getFieldAccessor(String fieldName) { - return "this." + fieldName; + return self + "." + fieldName; + } + + @Override + public String getMethodInvocation(String methodName) { + return self + "." + methodName + "()"; } @Override @@ -171,54 +177,4 @@ return false; } - @Override - public IResourceStateAccessor getPushAccessor() { - return new IResourceStateAccessor() { - @Override - public Expression getCurrentStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { - if (target.equals(from)) { - return new Field(CodeGenerator.fieldOfResourceState, - target.getResourceStateType() != null ? target.getResourceStateType() - : DataConstraintModel.typeInt); - } - // for reference channel member - return new Parameter(target.getResourceName(), - target.getResourceStateType() != null ? target.getResourceStateType() - : DataConstraintModel.typeInt); - } - - @Override - public Expression getNextStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { - return new Parameter(target.getResourceName(), - target.getResourceStateType() != null ? target.getResourceStateType() - : DataConstraintModel.typeInt); - } - }; - } - - @Override - public IResourceStateAccessor getPullAccessor() { - return new IResourceStateAccessor() { - @Override - public Expression getCurrentStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { - if (target.equals(from)) { - return new Field(CodeGenerator.fieldOfResourceState, - target.getResourceStateType() != null ? target.getResourceStateType() - : DataConstraintModel.typeInt); - } - // for reference channel member - Term getter = new Term(new Symbol(CodeGenerator.getterOfResourceState, 1, Symbol.Type.METHOD)); - getter.addChild(new Field(target.getResourceName(), target.getResourceStateType())); - return getter; - } - - @Override - public Expression getNextStateAccessorFor(IdentifierTemplate target, IdentifierTemplate from) { - Term getter = new Term(new Symbol(CodeGenerator.getterOfResourceState, 1, Symbol.Type.METHOD)); - getter.addChild(new Field(target.getResourceName(), target.getResourceStateType())); - return getter; - } - }; - } - } diff --git a/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/CallGraph.java b/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/CallGraph.java index 954c688..685cc85 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/CallGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/CallGraph.java @@ -1,7 +1,9 @@ package models.controlFlowModel; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import models.DirectedGraph; import models.Node; @@ -52,5 +54,13 @@ public StatefulObjectNode getStatefulObjectNode(ResourceNode resNode) { return statefulObjMap.get(resNode); - } + } + + public Set getRootNodes() { + Set roots = new HashSet<>(getNodes()); + for (Node n: getNodes()) { + roots.removeAll(n.getSuccessors()); + } + return roots; + } }