diff --git a/AlgebraicDataflowArchitectureModel/models/Clock.dtram b/AlgebraicDataflowArchitectureModel/models/Clock.dtram index 380ceca..f619eaf 100644 --- a/AlgebraicDataflowArchitectureModel/models/Clock.dtram +++ b/AlgebraicDataflowArchitectureModel/models/Clock.dtram @@ -1,18 +1,18 @@ model { channel CIO1 { - out min(m, tick) == mod(m + 1, 60) + out min(m: Int, tick) == mod(m + 1, 60) } channel HourUpdate { - in hour(h, update(h')) == h' - out hour_hand(h_ang, update(h')) == h' / 6 * PI + in hour(h: Int, update(h2)) == h2 + out hour_hand(h_ang: Float, update(h2)) == h2 / 6 * PI } channel MinUpdate { - in min(m, update(m')) == m' - out min_hand(m_ang, update(m')) == m' / 30 * PI + in min(m, update(m2)) == m2 + out min_hand(m_ang: Float, update(m2)) == m2 / 30 * PI } channel Clock { - in min(m, update(m')) == m' - out hour(h, update(m')) == if(eq(m', 0), mod(h + 1, 24), h) + in min(m, update(m2)) == m2 + out hour(h, update(m2)) == if(eq(m2, 0), mod(h + 1, 24), h) } } geometry { 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/application/actions/JavaPrototypeGenerateAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java index 92b552b..a56f615 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java @@ -14,6 +14,8 @@ import application.editor.Editor; import code.ast.*; import generators.CodeGenerator; +import generators.CodeGeneratorFromControlFlowGraph; +import generators.CodeGeneratorFromDataFlowGraph; import generators.DataTransferMethodAnalyzer; import generators.JavaCodeGenerator; import generators.JavaMethodBodyGenerator; @@ -65,9 +67,9 @@ } ControlFlowGraph controlFlowGraph = editor.getControlFlowGraph(); if (controlFlowGraph != null) { - editor.setCodes(CodeGenerator.doGenerate(model, controlFlowGraph, new JavaSpecific())); + editor.setCodes(new CodeGeneratorFromControlFlowGraph().generateCode(model, controlFlowGraph, new JavaSpecific())); } else { - editor.setCodes(CodeGenerator.doGenerate(model, dataFlowgraph, new JavaSpecific())); + editor.setCodes(new CodeGeneratorFromDataFlowGraph().generateCode(model, dataFlowgraph, new JavaSpecific())); } ModelExtension.recoverModel(model); for (CompilationUnit file : editor.getCodes()) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 6b1890c..78af141 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; @@ -12,22 +13,21 @@ import code.ast.FieldDeclaration; import code.ast.MethodDeclaration; import code.ast.TypeDeclaration; -import code.ast.VariableDeclaration; import models.Edge; import models.Node; import models.algebra.Expression; -import models.algebra.InvalidMessage; -import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.Field; +import models.algebra.Parameter; +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.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.DataTransferChannelGenerator; @@ -35,9 +35,7 @@ import models.dataFlowModel.IFlowGraph; import models.dataFlowModel.PushPullAttribute; import models.dataFlowModel.PushPullValue; -import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; import models.dataFlowModel.ResourceNode; -import models.dataFlowModel.StoreAttribute; import models.dataFlowModel.DataTransferChannelGenerator.IResourceStateAccessor; /** @@ -46,7 +44,7 @@ * @author Nitta * */ -public class CodeGenerator { +public abstract class CodeGenerator { public static final String fieldOfResourceState = "value"; public static final String getterOfResourceState = "getValue"; public static final String updateMethodName = "update"; @@ -72,8 +70,10 @@ * @param langSpec specified language * @return source codes */ - static public ArrayList doGenerate(DataTransferModel model, IFlowGraph flowGraph, ILanguageSpecific langSpec) { + public ArrayList generateCode(DataTransferModel model, IFlowGraph flowGraph, ILanguageSpecific langSpec) { ArrayList codes = new ArrayList<>(); + + // Sort the all components. ArrayList components = determineComponentOrder(flowGraph); // Add the main component. @@ -85,77 +85,15 @@ CompilationUnit mainCU = langSpec.newCompilationUnit(mainComponent); codes.add(mainCU); - // For each of other components. - for (Node componentNode: components) { - // Declare this component. - String componentName = null; - if (componentNode instanceof ResourceNode) { - componentName = langSpec.toComponentName(((ResourceNode) componentNode).getIdentifierTemplate().getResourceName()); - } else if (componentNode instanceof ObjectNode) { - componentName = langSpec.toComponentName(((ObjectNode) componentNode).getName()); - } - TypeDeclaration component = langSpec.newTypeDeclaration(componentName); - - // Declare the constructor and the fields to refer to other resources (to the callee components). - MethodDeclaration constructor = null; - List depends = new ArrayList<>(); - if (componentNode instanceof ResourceNode) { - // For data-flow graph - constructor = declareConstructorAndFieldsToReferToResources((ResourceNode) componentNode, component, depends, langSpec); - } else if (componentNode instanceof ObjectNode) { - // For control-flow graph - constructor = declareConstructorAndFieldsToCalleeComponents((ObjectNode) componentNode, component, depends, langSpec); - } - - // Update the main component for this component. - updateMainComponent(model, mainComponent, mainConstructor, componentNode, depends, langSpec); - - if (componentNode instanceof ResourceNode || componentNode instanceof StatefulObjectNode) { - // For this resource. - ResourceNode resourceNode = null; - if (componentNode instanceof ResourceNode) { - // For data-flow graph - resourceNode = (ResourceNode) componentNode; - } else if (componentNode instanceof StatefulObjectNode) { - // For control-flow graph - resourceNode = ((StatefulObjectNode) componentNode).getResource(); - } - IdentifierTemplate resId = resourceNode.getIdentifierTemplate(); - Type resStateType = resId.getResourceStateType(); - - // Declare the field in this resource to store the state. - if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { - FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, resId.getInitialValue())); - 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); - } - if (constructor.getParameters() == null) { - component.removeMethod(constructor); - } - - // Add compilation unit for this component. - CompilationUnit cu = langSpec.newCompilationUnit(component); - codes.add(cu); - } + // Generate the other components. + generateCodeFromFlowGraph(model, flowGraph, components, mainComponent, mainConstructor, codes, langSpec); return codes; } + public abstract void generateCodeFromFlowGraph(DataTransferModel model, IFlowGraph flowGraph, ArrayList components, + TypeDeclaration mainComponent, MethodDeclaration mainConstructor, ArrayList codes, ILanguageSpecific langSpec); + private static ArrayList determineComponentOrder(IFlowGraph graph) { ArrayList objects = new ArrayList<>(); Set visited = new HashSet<>(); @@ -174,7 +112,17 @@ // a caller is before the callee for (Edge e: curNode.getInEdges()) { if (!(e.getSource() instanceof EntryPointObjectNode)) { - topologicalSort(allNodes, e.getSource(), visited, orderedList); + if (!(e instanceof DataFlowEdge) || ((PushPullAttribute)((DataFlowEdge) e).getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { + topologicalSort(allNodes, e.getSource(), visited, orderedList); + } + } + } + if (curNode instanceof ResourceNode) { + for (Edge e: curNode.getOutEdges()) { + DataFlowEdge de = (DataFlowEdge) e; + if (((PushPullAttribute) de.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { + topologicalSort(allNodes, e.getDestination(), visited, orderedList); + } } } // For reference resources. @@ -207,7 +155,8 @@ orderedList.add(0, curNode); } - private static void updateMainComponent(DataTransferModel model, TypeDeclaration mainType, MethodDeclaration mainConstructor, Node componentNode, List depends, ILanguageSpecific langSpec) { + protected 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; @@ -257,53 +206,7 @@ mainConstructorBody.addStatement(langSpec.getFieldAccessor(nodeName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(componentName, parameters) + langSpec.getStatementDelimiter()); } - private static MethodDeclaration declareConstructorAndFieldsToReferToResources(ResourceNode resourceNode, TypeDeclaration component, - List depends, ILanguageSpecific langSpec) { - // Declare a constructor in each component. - MethodDeclaration constructor = component.createConstructor(); - Block block = new Block(); - constructor.setBody(block); - - // Declare fields in each component. (for data-flow graph) - for (Edge e: resourceNode.getOutEdges()) { - if (((PushPullAttribute) ((DataFlowEdge) e).getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - // for PUSH transfer - addReference(component, constructor, e.getDestination(), langSpec); - IdentifierTemplate dstId = ((ResourceNode) e.getDestination()).getIdentifierTemplate(); - if (!depends.contains(dstId)) depends.add(dstId); - } - } - for (Edge e: resourceNode.getInEdges()) { - if (((PushPullAttribute) ((DataFlowEdge) e).getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { - // for PULL transfer - addReference(component, constructor, e.getSource(), langSpec); - IdentifierTemplate srcId = ((ResourceNode) e.getSource()).getIdentifierTemplate(); - if (!depends.contains(srcId)) depends.add(srcId); - } - } - return constructor; - } - - private static MethodDeclaration declareConstructorAndFieldsToCalleeComponents(ObjectNode componentNode, TypeDeclaration component, - List depends, ILanguageSpecific langSpec) { - // Declare a constructor in each component. - MethodDeclaration constructor = component.createConstructor(); - Block block = new Block(); - constructor.setBody(block); - - // Declare fields in each component. (for control-flow graph) - for (Edge e: componentNode.getOutEdges()) { - ObjectNode dstNode = (ObjectNode) e.getDestination(); - addReference(component, constructor, dstNode, langSpec); - if (dstNode instanceof StatefulObjectNode) { - IdentifierTemplate dstId = ((StatefulObjectNode) dstNode).getResource().getIdentifierTemplate(); - if (!depends.contains(dstId)) depends.add(dstId); - } - } - return constructor; - } - - private static void addReference(TypeDeclaration component, MethodDeclaration constructor, Node dstNode, ILanguageSpecific langSpec) { + protected void addReference(TypeDeclaration component, MethodDeclaration constructor, Node dstNode, ILanguageSpecific langSpec) { String dstNodeName = null; if (dstNode instanceof ResourceNode) { dstNodeName = ((ResourceNode) dstNode).getIdentifierTemplate().getResourceName(); @@ -320,18 +223,13 @@ constructor.getBody().addStatement(langSpec.getFieldAccessor(dstNodeName) + langSpec.getAssignment() + dstNodeName + langSpec.getStatementDelimiter()); } - private static MethodDeclaration declareGetterMethod(ResourceNode resourceNode, TypeDeclaration component, Type resStateType, ILanguageSpecific langSpec) { - // Declare the getter method of the resource state. - MethodDeclaration getter = langSpec.newMethodDeclaration(getterOfResourceState, resStateType); - 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(); + protected 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("<")) { @@ -341,59 +239,13 @@ // } 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); - } - } 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(), langSpec.getPushAccessor()); - } else { - // PULL transfer - inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), langSpec.getPullAccessor()); - ch = dIn.getChannelGenerator(); - } - } - // for reference channel members. - for (ChannelMember c: ch.getReferenceChannelMembers()) { - inputIdentifierToStateAccessor.put(c.getIdentifierTemplate(), langSpec.getPullAccessor()); // by pull data transfer - } - - // generate 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, langSpec.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); - getter.addStatement(sideEffects[0] + langSpec.getReturnStatement(curState) + langSpec.getStatementDelimiter()); - } - break; - } - } - } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork - | InvalidMessage | UnificationFailed | ValueUndefined e) { - e.printStackTrace(); - } + List parameters = new ArrayList<>(); + parameters.add(langSpec.getFieldAccessor(fieldOfResourceState)); + getter.addStatement(langSpec.getReturnStatement(langSpec.getConstructorInvocation(implTypeName, parameters)) + langSpec.getStatementDelimiter()); // return new Resource(value); } - - return getter; } - private static void declareAccessorInMainComponent(TypeDeclaration mainComponent, IdentifierTemplate accessResId, ILanguageSpecific langSpec) { + protected void declareAccessorInMainComponent(TypeDeclaration mainComponent, IdentifierTemplate accessResId, ILanguageSpecific langSpec) { MethodDeclaration getter = new MethodDeclaration("get" + langSpec.toComponentName(accessResId.getResourceName()), accessResId.getResourceStateType()); Block block = new Block(); block.addStatement(langSpec.getReturnStatement(langSpec.getMethodInvocation(accessResId.getResourceName(), getterOfResourceState)) + langSpec.getStatementDelimiter()); @@ -401,8 +253,8 @@ mainComponent.addMethod(getter); } - private static void declareFieldsToReferenceResources(DataTransferModel model, ResourceNode resourceNode, TypeDeclaration component, MethodDeclaration constructor, - List depends, ILanguageSpecific langSpec) { + protected void declareFieldsToReferenceResources(DataTransferModel model, ResourceNode resourceNode, TypeDeclaration component, MethodDeclaration constructor, + final List depends, ILanguageSpecific langSpec) { Set refs = new HashSet<>(); for (ChannelGenerator ch : model.getChannelGenerators()) { DataTransferChannelGenerator c = (DataTransferChannelGenerator) ch; @@ -420,246 +272,86 @@ } } - private static List declareCacheFieldsAndUpdateMethods(ResourceNode resourceNode, TypeDeclaration component, ILanguageSpecific langSpec) { - // Declare cash fields and update methods in the component. - String resComponentName = langSpec.toComponentName(resourceNode.getIdentifierTemplate().getResourceName()); - List updateMethods = new ArrayList<>(); - for (Edge e: resourceNode.getInEdges()) { - DataFlowEdge re = (DataFlowEdge) e; - IdentifierTemplate srcRes = ((ResourceNode) re.getSource()).getIdentifierTemplate(); - String srcResName = srcRes.getResourceName(); - String srcResComponentName = langSpec.toComponentName(srcResName); - if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - // for push data transfer - - // Declare an update method in the type of the destination resource. - ArrayList vars = new ArrayList<>(); - vars.add(langSpec.newVariableDeclaration(srcRes.getResourceStateType(), srcRes.getResourceName())); - // For the refs. - DataTransferChannelGenerator ch = (DataTransferChannelGenerator) re.getChannelGenerator(); - for (IdentifierTemplate ref: ch.getReferenceIdentifierTemplates()) { - if (ref != resourceNode.getIdentifierTemplate()) { - vars.add(langSpec.newVariableDeclaration(ref.getResourceStateType(), ref.getResourceName())); - } + protected 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); + } + + protected 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()); } - MethodDeclaration update = langSpec.newMethodDeclaration(updateMethodName + srcResComponentName, false, null, vars); - component.addMethod(update); - updateMethods.add(update); - - // Add a statement to update the state field - if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { - try { - for (ChannelMember out: re.getChannelGenerator().getOutputChannelMembers()) { - if (out.getIdentifierTemplate() == resourceNode.getIdentifierTemplate()) { - Expression updateExp = re.getChannelGenerator().deriveUpdateExpressionOf(out, langSpec.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 = ... - } - if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { - 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 (resourceNode.getIndegree() > 1) { - // If incoming edges are multiple - if (langSpec.declareField()) { - // Declare the cache field. - FieldDeclaration cacheField = langSpec.newFieldDeclaration( - srcRes.getResourceStateType(), - srcRes.getResourceName(), - langSpec.getFieldInitializer(srcRes.getResourceStateType(), srcRes.getInitialValue())); - component.addField(cacheField); - - } - // Update the cache field. - String cashStatement = langSpec.getFieldAccessor(srcResName) + langSpec.getAssignment() + srcResName + langSpec.getStatementDelimiter(); - if (update.getBody() == null || !update.getBody().getStatements().contains(cashStatement)) { - update.addFirstStatement(cashStatement); - } - } - - // Add an invocation to another update method (for a chain of update method invocations). - for (Edge eOut: resourceNode.getOutEdges()) { - DataFlowEdge dOut = (DataFlowEdge) eOut; - if (((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - // PUSH transfer - Map> referredResources = new HashMap<>(); - List params = new ArrayList<>(); - params.add(langSpec.getFieldAccessor(fieldOfResourceState)); - Set referredSet = referredResources.get(update); - 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(); - update.addFirstStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); - } - params.add(refVarName); - } - } - update.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(((ResourceNode) dOut.getDestination()).getIdentifierTemplate().getResourceName()), - updateMethodName + resComponentName, - params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); - } - } + break; } } - return updateMethods; + return input; } - - private static List declareInputMethodsInThisAndMainComponents(ResourceNode resourceNode, TypeDeclaration component, - TypeDeclaration mainComponent, DataTransferModel model, ILanguageSpecific langSpec) { - // Declare input methods. - String resName = resourceNode.getIdentifierTemplate().getResourceName(); - String resComponentName = langSpec.toComponentName(resName); - List inputMethods = new ArrayList<>(); - for (ChannelGenerator ch : model.getIOChannelGenerators()) { - for (ChannelMember out : ((DataTransferChannelGenerator) ch).getOutputChannelMembers()) { - if (out.getIdentifierTemplate().equals(resourceNode.getIdentifierTemplate())) { - Expression message = out.getStateTransition().getMessageExpression(); - MethodDeclaration input = null; - MethodDeclaration mainInput = null; - 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); - component.addMethod(input); - inputMethods.add(input); - - // Declare the accessor in the main component to call the input method. - String str = ((Term) message).getSymbol().getImplName(); - mainInput = getMethod(mainComponent, str); - if (mainInput == null) { - mainInput = langSpec.newMethodDeclaration(str, false, null, params); - mainComponent.addMethod(mainInput); - } else { - // Add type to a parameter without type. - for (VariableDeclaration param: mainInput.getParameters()) { - if (param.getType() == null) { - for (VariableDeclaration p: params) { - if (param.getName().equals(p.getName()) && p.getType() != null) { - param.setType(p.getType()); - } - } - } - } - } - } else if (message instanceof Variable) { - // Declare an input method in this component. - input = langSpec.newMethodDeclaration(((Variable) message).getName(), null); - component.addMethod(input); - inputMethods.add(input); - String str = ((Variable) message).getName(); - - // Declare the accessor in the main component to call the input method. - mainInput = getMethod(mainComponent, str); - if (mainInput == null) { - mainInput = langSpec.newMethodDeclaration(str, null); - mainComponent.addMethod(mainInput); - } - } - - // Add an invocation to the accessor method. - if (mainInput != null) { - List args = new ArrayList<>(); - if (message instanceof Term) { - for (Variable var: message.getVariables().values()) { - args.add(var.getName()); - } - } - mainInput.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(resName), input.getName(), args) + langSpec.getStatementDelimiter()); - } - - if (input != null) { - // Add a statement to update the state field to the input method. - try { - String[] sideEffects = new String[] {""}; - Expression updateExp; - updateExp = ((DataTransferChannelGenerator) ch).deriveUpdateExpressionOf(out, langSpec.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(); - } - - // Add an invocation to an update method (for a chain of update method invocations). - for (Edge eOut: resourceNode.getOutEdges()) { - DataFlowEdge dOut = (DataFlowEdge) eOut; - if (((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { - // PUSH transfer - Map> referredResources = new HashMap<>(); - List params = new ArrayList<>(); - params.add(langSpec.getFieldAccessor(fieldOfResourceState)); - Set referredSet = referredResources.get(input); - for (ChannelMember rc: ((DataTransferChannelGenerator) ch).getReferenceChannelMembers()) { - // to get the value of reference member. - IdentifierTemplate ref = rc.getIdentifierTemplate(); - if (referredSet == null) { - referredSet = new HashSet<>(); - referredResources.put(input, 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(); - input.addFirstStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); - } - params.add(refVarName); - } - } - input.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(((ResourceNode) dOut.getDestination()).getIdentifierTemplate().getResourceName()), - updateMethodName + resComponentName, - params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); - } - } - } - } - } - } - return inputMethods; - } - - private static MethodDeclaration getMethod(TypeDeclaration component, String methodName) { + + protected MethodDeclaration getMethod(TypeDeclaration component, String methodName) { for (MethodDeclaration m: component.getMethods()) { if (m.getName().equals(methodName)) return m; } return null; } + + protected 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); + } + }; + } + + protected 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; + } + }; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromControlFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromControlFlowGraph.java new file mode 100644 index 0000000..9fa066a --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromControlFlowGraph.java @@ -0,0 +1,895 @@ +package generators; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import code.ast.Block; +import code.ast.CompilationUnit; +import code.ast.FieldDeclaration; +import code.ast.MethodDeclaration; +import code.ast.TypeDeclaration; +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; +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.ControlFlowGraph; +import models.controlFlowModel.EntryPointObjectNode; +import models.controlFlowModel.ObjectNode; +import models.controlFlowModel.StatefulObjectNode; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.IdentifierTemplate; +import models.dataFlowModel.DataFlowEdge; +import models.dataFlowModel.DataTransferChannelGenerator; +import models.dataFlowModel.DataTransferModel; +import models.dataFlowModel.IFlowGraph; +import models.dataFlowModel.PushPullAttribute; +import models.dataFlowModel.PushPullValue; +import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; +import models.dataFlowModel.ResourceNode; +import models.dataFlowModel.StoreAttribute; +import models.dataFlowModel.DataTransferChannelGenerator.IResourceStateAccessor; + +public class CodeGeneratorFromControlFlowGraph extends CodeGenerator { + + @Override + public void generateCodeFromFlowGraph(DataTransferModel model, IFlowGraph flowGraph, ArrayList components, + TypeDeclaration mainComponent, MethodDeclaration mainConstructor, ArrayList codes, ILanguageSpecific langSpec) { + // Reconstruct data-flow information. + Map>> dataFlowInform = new HashMap<>(); + ControlFlowGraph controlFlowGraph = (ControlFlowGraph) flowGraph; + for (Node root: controlFlowGraph.getPushCallGraph().getRootNodes()) { + Set treeResources = traverseCallTree(root, new HashSet<>()); + annotateDataFlowAttributes(root, dataFlowInform, treeResources, new ArrayList<>()); + removeRedundantAttributes(root, dataFlowInform); + } + for (Node root: controlFlowGraph.getPullCallGraph().getRootNodes()) { + Set treeResources = traverseCallTree(root, new HashSet<>()); + annotateDataFlowAttributes(root, dataFlowInform, treeResources, 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 the callee components. + List depends = new ArrayList<>(); + MethodDeclaration constructor = declareConstructorAndFieldsToCalleeComponents((ObjectNode) componentNode, component, depends, langSpec); + + if (componentNode instanceof StatefulObjectNode) { + // For this resource. + ResourceNode resourceNode = ((StatefulObjectNode) componentNode).getResource(); + IdentifierTemplate resId = resourceNode.getIdentifierTemplate(); + Type resStateType = resId.getResourceStateType(); + + // Declare the field in this resource to store the state. + if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { + FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, resId.getInitialValue())); + component.addField(stateField); + } + + // 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); + } + + // Update the main component for this component. + updateMainComponent(model, mainComponent, mainConstructor, componentNode, depends, langSpec); + if (constructor.getParameters() == null) { + component.removeMethod(constructor); + } + + // Add compilation unit for this component. + 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 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 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. + 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); + } + } + } + for (Edge inE: resNode.getInEdges()) { + // If resNode is a destination of data-flow. + ResourceNode srcOfDataFlowNode = (ResourceNode) inE.getSource(); + 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); + } + } + } + } + // Traverse the call tree. + for (Edge e: node.getOutEdges()) { + path.add(e); + annotateDataFlowAttributes(e.getDestination(), dataFlowInform, resourceNodes, path); + path.remove(e); + } + } + + private void removeRedundantAttributes(Node node, Map>> dataFlowInform) { + // 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) { + pushFlows = new ArrayList<>(); + } + if (pullFlows == null) { + pullFlows = new ArrayList<>(); + } + List pushFlowsOrg = new ArrayList<>(pushFlows); + for (ResourceNode r: pullFlows) { + pushFlows.remove(r); + } + 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); + } + } + + private MethodDeclaration declareConstructorAndFieldsToCalleeComponents(ObjectNode componentNode, TypeDeclaration component, + List depends, ILanguageSpecific langSpec) { + // Declare a constructor in each component. + MethodDeclaration constructor = component.createConstructor(); + Block block = new Block(); + constructor.setBody(block); + + // Declare fields in each component. (for control-flow graph) + for (Edge e: componentNode.getOutEdges()) { + ObjectNode dstNode = (ObjectNode) e.getDestination(); + addReference(component, constructor, dstNode, langSpec); + if (dstNode instanceof StatefulObjectNode) { + IdentifierTemplate dstId = ((StatefulObjectNode) dstNode).getResource().getIdentifierTemplate(); + if (!depends.contains(dstId)) depends.add(dstId); + } + } + return constructor; + } + + + private 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 data transfer + isContainedPush = true; + inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), getPushAccessor()); + } else { + // PULL data transfer + for (Edge outEdge: node.getOutEdges()) { + // For each call edge. + ObjectNode dstNode = (ObjectNode) outEdge.getDestination(); + 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. + } + } + // 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[] {""}; + // The following process is common to the cases of 1) and 2). + // 1) All incoming edges are in PULL-style. + // 2) 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 a mediate getter method to return a single value. + 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); + + // Add a return statement. + if (node.getOutdegree() == 1) { + Edge outEdge = node.getOutEdges().iterator().next(); + ObjectNode dstNode = (ObjectNode) outEdge.getDestination(); + MethodDeclaration nextGetter = declareAndFillGetterMethods(dstNode, outEdge, dataFlowInform, componentMap, langSpec); + mediateGetter.addStatement( + langSpec.getReturnStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNode.getName()), nextGetter.getName())) + + langSpec.getStatementDelimiter()); + } else { + // Unexpected. + } + return mediateGetter; + } + // Declare a mediate getter method to return multiple values. + String getterMethodName = "get"; + for (ResourceNode rn: resourcesToReturn) { + getterMethodName += langSpec.toComponentName(rn.getIdentifierTemplate().getResourceName()); + } + getterMethodName += "Values"; + Type returnType = createReturnType(resourcesToReturn, langSpec); + MethodDeclaration mediateGetter = langSpec.newMethodDeclaration(getterMethodName, returnType); + component.addMethod(mediateGetter); + + // Add a return statement. + 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; + } + } + } + } + mediateGetter.addStatement( + langSpec.getReturnStatement(langSpec.getConstructorInvocation(returnType.getImplementationTypeName(), params)) + + langSpec.getStatementDelimiter()); + } + return mediateGetter; + } + + private MethodDeclaration declareAndFillUpdateAndInputMethods(Node node, Edge inEdge, Node prevResNode, + Map>> dataFlowInform, Map componentMap, ILanguageSpecific langSpec) { + TypeDeclaration component = componentMap.get(node); + List resourcesToReturn = null; + List resourcesToReceive = null; + if (dataFlowInform.get(inEdge) != null) { + resourcesToReturn = dataFlowInform.get(inEdge).get(PushPullValue.PULL); + resourcesToReceive = dataFlowInform.get(inEdge).get(PushPullValue.PUSH); + } + 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) + || (resourcesToReceive != null && resourcesToReceive.size() > 0)) { + 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); + + Map resToVar = new HashMap<>(); + Map> varToRes = new HashMap<>(); + 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. + List returnedResources = dataFlowInform.get(outEdge).get(PushPullValue.PULL); + String varName = addInvocationInResourceUpdate(node, 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()); + } + 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. + if (calleeMethod.getParameters() != null) { + input = langSpec.newMethodDeclaration(calleeMethod.getName(), false, null, new ArrayList<>(calleeMethod.getParameters())); + } else { + input = langSpec.newMethodDeclaration(calleeMethod.getName(), null); + } + } + // Add a statement to call the destination method. + String varName = addInvocationInMediatorUpdate(input, calleeMethod, ((ObjectNode) dstNode).getName(), dataFlowInform.get(outEdge).get(PushPullValue.PULL), 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) + || (resourcesToReceive != null && resourcesToReceive.size() > 0)) { + // Declare an update method. + updateOrInput = declareUpdateMethod(node, inEdge, component, dataFlowInform, langSpec); + component.addMethod(updateOrInput); + } + + 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. + 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); + } + // 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()); + } + } + return updateOrInput; + } + } + + private 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 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 String createReturnValue(List resourcesToReturn, Node node, Type returnType, Map resToVar, Map> varToRes, ILanguageSpecific langSpec) { + List params = new ArrayList<>(); + for (ResourceNode rn: resourcesToReturn) { + IdentifierTemplate rId = rn.getIdentifierTemplate(); + if (rId.getResourceName().equals(((ObjectNode) node).getName())) { + params.add(langSpec.getFieldAccessor(fieldOfResourceState)); + } else { + String varName = resToVar.get(rn); + if (varToRes.get(varName).size() == 1) { + params.add(varName); + } else { + params.add(langSpec.getTupleGet(varName, varToRes.get(varName).indexOf(rn), varToRes.get(varName).size())); + } + } + } + if (params.size() == 1) { + return params.iterator().next(); + } else { + return langSpec.getConstructorInvocation(returnType.getImplementationTypeName(), params); + } + } + + private Type createReturnType(List resourcesToReturn, ILanguageSpecific langSpec) { + if (resourcesToReturn.size() == 1) { + return resourcesToReturn.iterator().next().getIdentifierTemplate().getResourceStateType(); + } + List compTypes = new ArrayList<>(); + for (ResourceNode rn: resourcesToReturn) { + IdentifierTemplate rId = rn.getIdentifierTemplate(); + compTypes.add(rId.getResourceStateType()); + } + Type returnType = langSpec.newTupleType(compTypes); + return returnType; + } + + + private String addInvocationInResourceUpdate(Node node, MethodDeclaration resourceUpdateMethod, MethodDeclaration calleeMethod, String dstNodeName, List returnResources, ILanguageSpecific langSpec) { + List params = new ArrayList<>(); + params.add(langSpec.getFieldAccessor(fieldOfResourceState)); + if (calleeMethod.getParameters() != null) { + 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); +// } +// } + if (calleeMethod.getReturnType() == null || langSpec.isVoidType(calleeMethod.getReturnType()) || returnResources == null) { + resourceUpdateMethod.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNodeName), + calleeMethod.getName(), + params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); + return null; + } else { + String targetVarName = null; + if (returnResources.size() == 1) { + ResourceNode targetNode = returnResources.get(0); + targetVarName = targetNode.getIdentifierTemplate().getResourceName(); + resourceUpdateMethod.addStatement( + langSpec.getVariableDeclaration(calleeMethod.getReturnType().getInterfaceTypeName(), targetVarName) + + langSpec.getAssignment() + + langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNodeName), + calleeMethod.getName(), + params) + langSpec.getStatementDelimiter()); // ResType res = this.dst.updateSrc(value, refParams); + } else { + targetVarName = getMultipleResourcesVarName(returnResources, langSpec); + VariableDeclaration targetVar = langSpec.newVariableDeclaration(calleeMethod.getReturnType(), targetVarName); + List vars = new ArrayList<>(); + for (ResourceNode rn: returnResources) { + IdentifierTemplate rId = rn.getIdentifierTemplate(); + vars.add(langSpec.newVariableDeclaration(rId.getResourceStateType(), rId.getResourceName())); + } + resourceUpdateMethod.addStatement( + langSpec.getDecomposedTuple( + langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNodeName), calleeMethod.getName(), params), + targetVar, // ResType res = this.dst.updateSrc(value, refParams); + vars)); // Type1 res1 = res.getKey(); Type2 res2 = res.getValue(); + } + return targetVarName; + } + } + + private String addInvocationInMediatorUpdate(MethodDeclaration resourceUpdateMethod, MethodDeclaration calleeMethod, String dstNodeName, List returnResources, ILanguageSpecific langSpec) { + List params = new ArrayList<>(); + if (calleeMethod.getParameters() != null) { + for (VariableDeclaration v: calleeMethod.getParameters()) { + params.add(v.getName()); + } + } + if (calleeMethod.getReturnType() == null || langSpec.isVoidType(calleeMethod.getReturnType()) || returnResources == null ) { + resourceUpdateMethod.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNodeName), + calleeMethod.getName(), + params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); + return null; + } else { + String targetVarName = null; + if (returnResources.size() == 1) { + ResourceNode targetNode = returnResources.get(0); + targetVarName = targetNode.getIdentifierTemplate().getResourceName(); + resourceUpdateMethod.addStatement( + langSpec.getVariableDeclaration(calleeMethod.getReturnType().getInterfaceTypeName(), targetVarName) + + langSpec.getAssignment() + + langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNodeName), + calleeMethod.getName(), + params) + langSpec.getStatementDelimiter()); // ResType res = this.dst.updateSrc(value, refParams); + } else { + targetVarName = getMultipleResourcesVarName(returnResources, langSpec); + VariableDeclaration targetVar = langSpec.newVariableDeclaration(calleeMethod.getReturnType(), targetVarName); + List vars = new ArrayList<>(); + for (ResourceNode rn: returnResources) { + IdentifierTemplate rId = rn.getIdentifierTemplate(); + vars.add(langSpec.newVariableDeclaration(rId.getResourceStateType(), rId.getResourceName())); + } + resourceUpdateMethod.addStatement( + langSpec.getDecomposedTuple( + langSpec.getMethodInvocation(langSpec.getFieldAccessor(dstNodeName), calleeMethod.getName(), params), + targetVar, // ResType res = this.dst.updateSrc(value, refParams); + vars)); // Type1 res1 = res.getKey(); Type2 res2 = res.getValue(); + } + return targetVarName; + } + } + + private String getMultipleResourcesVarName(List resources, ILanguageSpecific langSpec) { + String varName = null; + for (ResourceNode rn: resources) { + if (varName == null) { + varName = rn.getIdentifierTemplate().getResourceName(); + } else { + varName += langSpec.toComponentName(rn.getIdentifierTemplate().getResourceName()); + } + } + return varName; + } + + private List getUpdateMethods(TypeDeclaration component) { + List updates = new ArrayList<>(); + for (MethodDeclaration m: component.getMethods()) { + if (m.getName().startsWith(updateMethodName)) { + updates.add(m); + } + } + return updates; + } + + protected 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; + } + }; + } + + protected 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); + } + }; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java new file mode 100644 index 0000000..94fce58 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -0,0 +1,411 @@ +package generators; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import code.ast.Block; +import code.ast.CompilationUnit; +import code.ast.FieldDeclaration; +import code.ast.MethodDeclaration; +import code.ast.TypeDeclaration; +import code.ast.VariableDeclaration; +import models.Edge; +import models.Node; +import models.algebra.Expression; +import models.algebra.InvalidMessage; +import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.Term; +import models.algebra.Type; +import models.algebra.UnificationFailed; +import models.algebra.ValueUndefined; +import models.algebra.Variable; +import models.dataConstraintModel.ChannelGenerator; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.IdentifierTemplate; +import models.dataFlowModel.DataFlowEdge; +import models.dataFlowModel.DataTransferChannelGenerator; +import models.dataFlowModel.DataTransferModel; +import models.dataFlowModel.IFlowGraph; +import models.dataFlowModel.PushPullAttribute; +import models.dataFlowModel.PushPullValue; +import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; +import models.dataFlowModel.ResourceNode; +import models.dataFlowModel.StoreAttribute; +import models.dataFlowModel.DataTransferChannelGenerator.IResourceStateAccessor; + +public class CodeGeneratorFromDataFlowGraph extends CodeGenerator { + + public void generateCodeFromFlowGraph(DataTransferModel model, IFlowGraph flowGraph, ArrayList components, + TypeDeclaration mainComponent, MethodDeclaration mainConstructor, ArrayList codes, ILanguageSpecific langSpec) { + // For each of other components. + for (Node componentNode: components) { + // Declare this resource. + ResourceNode resourceNode = (ResourceNode) componentNode; + String resourceName = langSpec.toComponentName(resourceNode.getIdentifierTemplate().getResourceName()); + TypeDeclaration component = langSpec.newTypeDeclaration(resourceName); + + // Declare the constructor and the fields to refer to other resources. + List depends = new ArrayList<>(); + MethodDeclaration constructor = declareConstructorAndFieldsToReferToResources(resourceNode, component, depends, langSpec); + + // Update the main component for this component. + updateMainComponent(model, mainComponent, mainConstructor, componentNode, depends, langSpec); + + IdentifierTemplate resId = resourceNode.getIdentifierTemplate(); + Type resStateType = resId.getResourceStateType(); + + // Declare the field in this resource to store the state. + if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { + FieldDeclaration stateField = langSpec.newFieldDeclaration(resStateType, fieldOfResourceState, langSpec.getFieldInitializer(resStateType, resId.getInitialValue())); + 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); + + if (constructor.getParameters() == null) { + component.removeMethod(constructor); + } + + // Add compilation unit for this component. + CompilationUnit cu = langSpec.newCompilationUnit(component); + codes.add(cu); + } + } + + private MethodDeclaration declareConstructorAndFieldsToReferToResources(ResourceNode resourceNode, TypeDeclaration component, + List depends, ILanguageSpecific langSpec) { + // Declare a constructor in each component. + MethodDeclaration constructor = component.createConstructor(); + Block block = new Block(); + constructor.setBody(block); + + // Declare fields in each component. (for data-flow graph) + for (Edge e: resourceNode.getOutEdges()) { + if (((PushPullAttribute) ((DataFlowEdge) e).getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { + // for PUSH transfer + addReference(component, constructor, e.getDestination(), langSpec); + IdentifierTemplate dstId = ((ResourceNode) e.getDestination()).getIdentifierTemplate(); + if (!depends.contains(dstId)) depends.add(dstId); + } + } + for (Edge e: resourceNode.getInEdges()) { + if (((PushPullAttribute) ((DataFlowEdge) e).getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { + // for PULL transfer + addReference(component, constructor, e.getSource(), langSpec); + IdentifierTemplate srcId = ((ResourceNode) e.getSource()).getIdentifierTemplate(); + if (!depends.contains(srcId)) depends.add(srcId); + } + } + return constructor; + } + + private MethodDeclaration declareGetterMethod(ResourceNode resourceNode, TypeDeclaration component, Type resStateType, ILanguageSpecific langSpec) { + // Declare the getter method of the resource state. + MethodDeclaration getter = langSpec.newMethodDeclaration(getterOfResourceState, resStateType); + component.addMethod(getter); + + if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { + fillGetterMethodToReturnStateField(getter, resStateType, langSpec); + } 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 + inputIdentifierToStateAccessor.put(((ResourceNode) dIn.getSource()).getIdentifierTemplate(), getPullAccessor()); + ch = dIn.getChannelGenerator(); + } + } + // for reference channel members. + for (ChannelMember c: ch.getReferenceChannelMembers()) { + inputIdentifierToStateAccessor.put(c.getIdentifierTemplate(), getPullAccessor()); // by pull data transfer + } + + // generate 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(); + } + } + + return getter; + } + + private List declareCacheFieldsAndUpdateMethods(ResourceNode resourceNode, TypeDeclaration component, ILanguageSpecific langSpec) { + // Declare cash fields and update methods in the component. + String resComponentName = langSpec.toComponentName(resourceNode.getIdentifierTemplate().getResourceName()); + List updateMethods = new ArrayList<>(); + for (Edge e: resourceNode.getInEdges()) { + DataFlowEdge re = (DataFlowEdge) e; + IdentifierTemplate srcRes = ((ResourceNode) re.getSource()).getIdentifierTemplate(); + String srcResName = srcRes.getResourceName(); + String srcResComponentName = langSpec.toComponentName(srcResName); + if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { + // for push data transfer + + // Declare an update method in the type of the destination resource. + ArrayList vars = new ArrayList<>(); + vars.add(langSpec.newVariableDeclaration(srcRes.getResourceStateType(), srcRes.getResourceName())); + // For the refs. + DataTransferChannelGenerator ch = (DataTransferChannelGenerator) re.getChannelGenerator(); + for (IdentifierTemplate ref: ch.getReferenceIdentifierTemplates()) { + if (ref != resourceNode.getIdentifierTemplate()) { + vars.add(langSpec.newVariableDeclaration(ref.getResourceStateType(), ref.getResourceName())); + } + } + MethodDeclaration update = langSpec.newMethodDeclaration(updateMethodName + srcResComponentName, false, null, vars); + component.addMethod(update); + updateMethods.add(update); + + // Add a statement to update the state field + if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { + try { + 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 = ... + } + if (update.getBody() == null || !update.getBody().getStatements().contains(updateStatement)) { + 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 (resourceNode.getIndegree() > 1) { + // If incoming edges are multiple + if (langSpec.declareField()) { + // Declare the cache field. + FieldDeclaration cacheField = langSpec.newFieldDeclaration( + srcRes.getResourceStateType(), + srcRes.getResourceName(), + langSpec.getFieldInitializer(srcRes.getResourceStateType(), srcRes.getInitialValue())); + component.addField(cacheField); + + } + // Update the cache field. + String cashStatement = langSpec.getFieldAccessor(srcResName) + langSpec.getAssignment() + srcResName + langSpec.getStatementDelimiter(); + if (update.getBody() == null || !update.getBody().getStatements().contains(cashStatement)) { + update.addFirstStatement(cashStatement); + } + } + + // Add an invocation to another update method (for a chain of update method invocations). + for (Edge eOut: resourceNode.getOutEdges()) { + DataFlowEdge dOut = (DataFlowEdge) eOut; + if (((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { + // PUSH transfer + Map> referredResources = new HashMap<>(); + List params = new ArrayList<>(); + params.add(langSpec.getFieldAccessor(fieldOfResourceState)); + Set referredSet = referredResources.get(update); + 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 = getPullAccessor().getCurrentStateAccessorFor(ref, ((ResourceNode) dOut.getSource()).getIdentifierTemplate()); + String[] sideEffects = new String[] {""}; + String refExp = refGetter.toImplementation(sideEffects); + String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); + update.addFirstStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); + } + params.add(refVarName); + } + } + update.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(((ResourceNode) dOut.getDestination()).getIdentifierTemplate().getResourceName()), + updateMethodName + resComponentName, + params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); + } + } + } + } + return updateMethods; + } + + private List declareInputMethodsInThisAndMainComponents(ResourceNode resourceNode, TypeDeclaration component, + TypeDeclaration mainComponent, DataTransferModel model, ILanguageSpecific langSpec) { + // Declare input methods. + String resName = resourceNode.getIdentifierTemplate().getResourceName(); + String resComponentName = langSpec.toComponentName(resName); + List inputMethods = new ArrayList<>(); + for (ChannelGenerator ch : model.getIOChannelGenerators()) { + for (ChannelMember out : ((DataTransferChannelGenerator) ch).getOutputChannelMembers()) { + if (out.getIdentifierTemplate().equals(resourceNode.getIdentifierTemplate())) { + Expression message = out.getStateTransition().getMessageExpression(); + MethodDeclaration input = null; + MethodDeclaration mainInput = null; + 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); + component.addMethod(input); + inputMethods.add(input); + + // Declare the accessor in the main component to call the input method. + String str = ((Term) message).getSymbol().getImplName(); + mainInput = getMethod(mainComponent, str); + if (mainInput == null) { + mainInput = langSpec.newMethodDeclaration(str, false, null, params); + mainComponent.addMethod(mainInput); + } else { + // Add type to a parameter without type. + if (mainInput.getParameters() != null) { + for (VariableDeclaration param: mainInput.getParameters()) { + if (param.getType() == null) { + for (VariableDeclaration p: params) { + if (param.getName().equals(p.getName()) && p.getType() != null) { + param.setType(p.getType()); + } + } + } + } + } + } + } else if (message instanceof Variable) { + // Declare an input method in this component. + input = langSpec.newMethodDeclaration(((Variable) message).getName(), null); + component.addMethod(input); + inputMethods.add(input); + String str = ((Variable) message).getName(); + + // Declare the accessor in the main component to call the input method. + mainInput = getMethod(mainComponent, str); + if (mainInput == null) { + mainInput = langSpec.newMethodDeclaration(str, null); + mainComponent.addMethod(mainInput); + } + } + + // Add an invocation to the accessor method. + if (mainInput != null) { + List args = new ArrayList<>(); + if (message instanceof Term) { + for (Variable var: message.getVariables().values()) { + args.add(var.getName()); + } + } + mainInput.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(resName), input.getName(), args) + langSpec.getStatementDelimiter()); + } + + if (input != null) { + // Add a statement to update the state field to the input method. + try { + String[] sideEffects = new String[] {""}; + Expression updateExp; + updateExp = ((DataTransferChannelGenerator) 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(); + } + + // Add an invocation to an update method (for a chain of update method invocations). + for (Edge eOut: resourceNode.getOutEdges()) { + DataFlowEdge dOut = (DataFlowEdge) eOut; + if (((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH) { + // PUSH transfer + Map> referredResources = new HashMap<>(); + List params = new ArrayList<>(); + params.add(langSpec.getFieldAccessor(fieldOfResourceState)); + Set referredSet = referredResources.get(input); + for (ChannelMember rc: ((DataTransferChannelGenerator) ch).getReferenceChannelMembers()) { + // to get the value of reference member. + IdentifierTemplate ref = rc.getIdentifierTemplate(); + if (referredSet == null) { + referredSet = new HashSet<>(); + referredResources.put(input, referredSet); + } + if (ref != resourceNode.getIdentifierTemplate()) { + String refVarName = ref.getResourceName(); + if (!referredSet.contains(ref)) { + referredSet.add(ref); + Expression refGetter = getPullAccessor().getCurrentStateAccessorFor(ref, ((ResourceNode) dOut.getSource()).getIdentifierTemplate()); + String[] sideEffects = new String[] {""}; + String refExp = refGetter.toImplementation(sideEffects); + String refTypeName = ref.getResourceStateType().getInterfaceTypeName(); + input.addFirstStatement(sideEffects[0] + langSpec.getVariableDeclaration(refTypeName, refVarName) + langSpec.getAssignment() + refExp + langSpec.getStatementDelimiter()); + } + params.add(refVarName); + } + } + input.addStatement(langSpec.getMethodInvocation(langSpec.getFieldAccessor(((ResourceNode) dOut.getDestination()).getIdentifierTemplate().getResourceName()), + updateMethodName + resComponentName, + params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); + } + } + } + } + } + } + return inputMethods; + } +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java index 3b4f817..40d2f25 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/ILanguageSpecific.java @@ -20,19 +20,22 @@ MethodDeclaration newMethodDeclaration(String methodName, boolean isConstructor, Type returnType, ArrayList parameters); FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName); FieldDeclaration newFieldDeclaration(Type fieldType, String fieldName, String fieldInitializer); + Type newTupleType(List compTypes); String getVariableDeclaration(String typeName, String varName); 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); String getReturnStatement(String returnValue); String toComponentName(String name); String getMainComponentName(); + String getTupleGet(String tupleExp, int idx, int length); + String getDecomposedTuple(String tupleExp, VariableDeclaration tupleVar, List vars); String getAssignment(); String getStatementDelimiter(); - boolean isValueType(Type resStateType); - IResourceStateAccessor getPushAccessor(); - IResourceStateAccessor getPullAccessor(); + boolean isValueType(Type type); + boolean isVoidType(Type type); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java index ac4715c..0176b5e 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaSpecific.java @@ -10,17 +10,15 @@ import code.ast.TypeDeclaration; import code.ast.VariableDeclaration; import models.algebra.Expression; -import models.algebra.Field; import models.algebra.Parameter; -import models.algebra.Symbol; import models.algebra.Term; import models.algebra.Type; +import models.algebra.Variable; import models.dataConstraintModel.DataConstraintModel; -import models.dataConstraintModel.IdentifierTemplate; -import models.dataFlowModel.DataTransferChannelGenerator.IResourceStateAccessor; 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) { @@ -65,6 +63,27 @@ return new FieldDeclaration(fieldType, fieldName, fieldInitializer); } + @Override + public Type newTupleType(List componentTypes) { + String implTypeName = "AbstractMap.SimpleEntry<>"; + String interfaceTypeName = "Map.Entry<$x>"; + if (componentTypes.size() >= 2) { + implTypeName = implTypeName.replace("$x", getImplementationTypeName(componentTypes.get(0)) + "$x"); + interfaceTypeName = interfaceTypeName.replace("$x", getInterfaceTypeName(componentTypes.get(0)) + "$x"); + for (Type argType : componentTypes.subList(1, componentTypes.size() - 1)) { + implTypeName = implTypeName.replace("$x", + ", AbstractMap.SimpleEntry<" + getImplementationTypeName(argType) + "$x>"); + interfaceTypeName = interfaceTypeName.replace("$x", + ", Map.Entry<" + getInterfaceTypeName(argType) + "$x>"); + } + implTypeName = implTypeName.replace("$x", + ", " + getImplementationTypeName(componentTypes.get(componentTypes.size() - 1))); + interfaceTypeName = interfaceTypeName.replace("$x", + ", " + getInterfaceTypeName(componentTypes.get(componentTypes.size() - 1))); + } + Type newTupleType = new Type("Tuple", implTypeName, interfaceTypeName, DataConstraintModel.typeTuple); + return newTupleType; + } @Override public String getVariableDeclaration(String typeName, String varName) { @@ -93,7 +112,12 @@ @Override public String getFieldAccessor(String fieldName) { - return "this." + fieldName; + return self + "." + fieldName; + } + + @Override + public String getMethodInvocation(String methodName) { + return self + "." + methodName + "()"; } @Override @@ -158,7 +182,38 @@ public String getStatementDelimiter() { return ";"; } - + + @Override + public String getTupleGet(String tupleExp, int idx, int length) { + Expression t = new Variable(tupleExp, DataConstraintModel.typeTuple); + for (int i = 0; i < idx; i++) { + Term next = new Term(DataConstraintModel.snd); + next.addChild(t); + t = next; + } + if (idx < length - 1) { + Term last = new Term(DataConstraintModel.fst); + last.addChild(t); + t = last; + } + return t.toImplementation(new String[]{}); + } + + @Override + public String getDecomposedTuple(String tupleExp, VariableDeclaration tupleVar, List vars) { + String statements = ""; + statements += getVariableDeclaration(tupleVar.getType().getInterfaceTypeName(), tupleVar.getName()) + + getAssignment() + tupleExp + getStatementDelimiter(); + for (int i = 0; i < vars.size(); i++) { + VariableDeclaration var = vars.get(i); + statements += "\n" + getVariableDeclaration(var.getType().getInterfaceTypeName(), var.getName()) + + getAssignment() + + getTupleGet(tupleVar.getName(), i, vars.size()) + + getStatementDelimiter(); + } + return statements; + } + @Override public boolean isValueType(Type type) { if (type == DataConstraintModel.typeInt @@ -166,59 +221,35 @@ || type == DataConstraintModel.typeFloat || type == DataConstraintModel.typeDouble || type == DataConstraintModel.typeBoolean) { - return true; - } - return false; + return true; + } + 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); - } - }; + public boolean isVoidType(Type type) { + if (type == typeVoid) { + return true; + } + return false; + } + + private String getImplementationTypeName(Type type) { + if (type == null) + return "Object"; + String wrapperType = DataConstraintModel.getWrapperType(type); + if (wrapperType != null) + return wrapperType; + return type.getImplementationTypeName(); } - @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; - } - }; + private String getInterfaceTypeName(Type type) { + if (type == null) + return "Object"; + String wrapperType = DataConstraintModel.getWrapperType(type); + if (wrapperType != null) + return wrapperType; + return type.getInterfaceTypeName(); } - } diff --git a/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/CallGraph.java b/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/CallGraph.java index fbd3356..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; @@ -16,19 +18,22 @@ } public void addNode(Node node) { - super.addNode(node); if (node instanceof ResourceNode) { ResourceNode resNode = (ResourceNode) node; StatefulObjectNode objNode = statefulObjMap.get(resNode); if (objNode == null) { objNode = new StatefulObjectNode(resNode); statefulObjMap.put(resNode, objNode); + super.addNode(objNode); } } else if (node instanceof StatefulObjectNode) { StatefulObjectNode objNode = (StatefulObjectNode) node; if (statefulObjMap.get(objNode.getResource()) == null) { statefulObjMap.put(objNode.getResource(), objNode); + super.addNode(objNode); } + } else { + super.addNode(node); } } @@ -49,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; + } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/ControlFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/ControlFlowGraph.java index 5d4b77e..be1d510 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/ControlFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/models/controlFlowModel/ControlFlowGraph.java @@ -111,7 +111,15 @@ public Set getAllNodes() { Set allNodes = new HashSet<>(); allNodes.addAll(pushCallGraph.getNodes()); - allNodes.addAll(pullCallGraph.getNodes()); + for (Node n: pullCallGraph.getNodes()) { + if (n instanceof StatefulObjectNode) { + if (pushCallGraph.getStatefulObjectNode(((StatefulObjectNode) n).getResource()) == null) { + allNodes.add(n); + } + } else { + allNodes.add(n); + } + } return allNodes; } }