diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java index ddd22e4..4083dce 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java @@ -59,8 +59,8 @@ } else { JavaCodeGenerator.resetMainTypeName(); // use the default main type's name. } -// editor.setCodes(JavaMethodBodyGenerator.doGenerate(graph, model, JavaCodeGenerator.doGenerate(graph, model))); - editor.setCodes(new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new JavaSpecific())); + editor.setCodes(JavaMethodBodyGenerator.doGenerate(graph, model, JavaCodeGenerator.doGenerate(graph, model))); +// editor.setCodes(new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new JavaSpecific())); ModelExtension.recoverModel(model); for (CompilationUnit file : editor.getCodes()) { System.out.println(file); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 0e03b38..0d8b08f 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -256,17 +256,11 @@ mainConstructorBody.addStatement(langSpec.getFieldAccessor(nodeName) + langSpec.getAssignment() + langSpec.getConstructorInvocation(componentName, parameters) + langSpec.getStatementDelimiter()); } - protected void addReference(TypeDeclaration component, MethodDeclaration constructor, Node dstNode, ILanguageSpecific langSpec) { - ResourcePath dstRes = null; - String dstComponentName = null; - if (dstNode instanceof ResourceNode) { - dstRes = ((ResourceNode) dstNode).getOutSideResource(); - if (generatesComponent(dstRes.getResourceHierarchy())) { - dstComponentName = getComponentName(((ResourceNode) dstNode).getResourceHierarchy(), langSpec); - } else { - dstComponentName = getComponentName(((ResourceNode) dstNode).getResourceHierarchy().getParent(), langSpec); - } + protected ResourcePath addReference(TypeDeclaration component, MethodDeclaration constructor, ResourcePath dstRes, ILanguageSpecific langSpec) { + if (!generatesComponent(dstRes.getResourceHierarchy())) { + dstRes = dstRes.getParent(); } + String dstComponentName = getComponentName(dstRes.getResourceHierarchy(), langSpec); if (dstComponentName != null) { String dstNodeName = langSpec.toVariableName(dstComponentName); if (langSpec.declareField()) { @@ -277,6 +271,7 @@ constructor.addParameter(langSpec.newVariableDeclaration(new Type(dstComponentName, dstComponentName), dstNodeName)); constructor.getBody().addStatement(langSpec.getFieldAccessor(dstNodeName) + langSpec.getAssignment() + dstNodeName + langSpec.getStatementDelimiter()); } + return dstRes; } protected void fillStateGetterMethod(MethodDeclaration stateGetter, ResourceHierarchy resourceHierarchy, Type resStateType, ILanguageSpecific langSpec) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index 00b9406..0399394 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -6,6 +6,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import code.ast.Block; @@ -158,12 +159,27 @@ break; } } + // Check if the output resource is outside of the channel scope. + boolean outsideOutputResource = false; + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(resourceNode.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } if (((PushPullAttribute) ((DataFlowEdge) resToCh).getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { for (Edge chToRes: resToCh.getDestination().getOutEdges()) { // for PUSH transfer - addReference(component, constructor, chToRes.getDestination(), langSpec); - ResourcePath dstRes = ((ResourceNode) chToRes.getDestination()).getOutSideResource(); - if (!depends.contains(dstRes)) depends.add(dstRes); + if (chToRes.getDestination() instanceof ResourceNode) { + ResourcePath dstRes = addReference(component, constructor, ((ResourceNode) chToRes.getDestination()).getOutSideResource(), langSpec); + if (outsideOutputResource) { + if (dstRes != null && dstRes.getParent() != null) { + // Reference to root resource. + addReference(component, constructor, dstRes.getRoot(), langSpec); + } + } + if (!depends.contains(dstRes)) depends.add(dstRes); + } } } } @@ -171,7 +187,7 @@ for (Edge resToCh: chToRes.getSource().getInEdges()) { ResourcePath srcRes = ((ResourceNode) resToCh.getSource()).getOutSideResource(); DataTransferChannel ch = ((ChannelNode) resToCh.getDestination()).getChannel(); - // Check if the input and output resources are outside of the channel scope. + // Check if the input resource is outside of the channel scope. boolean outsideInputResource = false; for (ChannelMember cm: ch.getInputChannelMembers()) { if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && cm.isOutside()) { @@ -179,6 +195,7 @@ break; } } + // Check if the output resource is outside of the channel scope. boolean outsideOutputResource = false; for (ChannelMember cm: ch.getOutputChannelMembers()) { if (cm.getResource().getResourceHierarchy().equals(resourceNode.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) { @@ -188,7 +205,13 @@ } if ((((PushPullAttribute) ((DataFlowEdge) resToCh).getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { // for PULL transfer - addReference(component, constructor, resToCh.getSource(), langSpec); + srcRes = addReference(component, constructor, ((ResourceNode) resToCh.getSource()).getOutSideResource(), langSpec); + if (outsideInputResource) { + if (srcRes != null & srcRes.getParent() != null) { + // Reference to root resource. + addReference(component, constructor, srcRes.getRoot(), langSpec); + } + } if (!depends.contains(srcRes)) depends.add(srcRes); } } @@ -244,13 +267,18 @@ if (outsideOutputResource) { // Declare a field in the parent component to refer to the destination resource of push transfer. String dstResName = null; - if (generatesComponent(dstRes.getResourceHierarchy())) { - dstResName = getComponentName(dstRes.getResourceHierarchy(), langSpec); - } else { - dstResName = getComponentName(dstRes.getResourceHierarchy().getParent(), langSpec); + if (!generatesComponent(dstRes.getResourceHierarchy())) { + dstRes = dstRes.getParent(); } + dstResName = getComponentName(dstRes.getResourceHierarchy(), langSpec); FieldDeclaration refFieldForPush = langSpec.newFieldDeclaration(new Type(dstResName, dstResName), langSpec.toVariableName(dstResName)); fields.add(new AbstractMap.SimpleEntry(resourceNode.getParent().getResourceHierarchy(), refFieldForPush)); + if (dstRes.getParent() != null) { + // Reference to root resource. + String dstRootResName = getComponentName(dstRes.getRoot().getResourceHierarchy(), langSpec); + FieldDeclaration refRootFieldForPush = langSpec.newFieldDeclaration(new Type(dstRootResName, dstRootResName), langSpec.toVariableName(dstRootResName)); + fields.add(new AbstractMap.SimpleEntry(resourceNode.getParent().getResourceHierarchy(), refRootFieldForPush)); + } } } } @@ -270,13 +298,18 @@ if (outsideInputResource) { // Declare a field in the parent component to refer to the source resource of pull transfer. String srcResName = null; - if (generatesComponent(srcRes.getResourceHierarchy())) { - srcResName = getComponentName(srcRes.getResourceHierarchy(), langSpec); - } else { - srcResName = getComponentName(srcRes.getResourceHierarchy().getParent(), langSpec); + if (!generatesComponent(srcRes.getResourceHierarchy())) { + srcRes = srcRes.getParent(); } + srcResName = getComponentName(srcRes.getResourceHierarchy(), langSpec); FieldDeclaration refFieldForPull = langSpec.newFieldDeclaration(new Type(srcResName, srcResName), langSpec.toVariableName(srcResName)); fields.add(new AbstractMap.SimpleEntry(resourceNode.getParent().getResourceHierarchy(), refFieldForPull)); + if (srcRes.getParent() != null) { + // Reference to root resource. + String srcRootResName = getComponentName(srcRes.getRoot().getResourceHierarchy(), langSpec); + FieldDeclaration refRootFieldForPull = langSpec.newFieldDeclaration(new Type(srcRootResName, srcRootResName), langSpec.toVariableName(srcRootResName)); + fields.add(new AbstractMap.SimpleEntry(resourceNode.getParent().getResourceHierarchy(), refRootFieldForPull)); + } noPullTransfer = false; } } @@ -497,16 +530,58 @@ } } + Set outsideInputMembers = new HashSet<>(); + for (ChannelMember cm: ch.getInputChannelMembers()) { + if (cm.isOutside()) { + outsideInputMembers.add(cm); + } + } + if (outsideInputMembers.size() > 0) { + Map>> resourcePaths = null; + for (ChannelMember out: ch.getOutputChannelMembers()) { + if (resourceNode.getInSideResources().contains(out.getResource())) { + try { + resourcePaths = ch.fillOutsideResourcePaths(out, getPullAccessor()); + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + break; + } + } + if (resourcePaths != null && resourcePaths.size() > 0) { + for (ChannelMember outsideMember: outsideInputMembers) { + for (ChannelMember dependingMember: resourcePaths.get(outsideMember).getValue()) { + if (dependingMember.getResource().equals(srcRes)) { + // An outside input resource path depends on srcRes. + ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); + String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); + Expression outsideExp = getPullAccessor().getDirectStateAccessorFor(outsidePath, null); + if (generatesComponent(outsidePath.getResourceHierarchy())) { + outsideExp = ((Term) outsideExp).getChild(0); + } + String[] sideEffects = new String[] {""}; + String outsideAccessor = outsideExp.toImplementation(sideEffects); + update.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. + } + } + } + } + } + // Add an invocation to another update method (for a chain of update method invocations). for (Edge resToCh2: resourceNode.getOutEdges()) { DataFlowEdge dOut = (DataFlowEdge) resToCh2; DataTransferChannel ch2 = ((ChannelNode) resToCh2.getDestination()).getChannel(); // Check if the input resource is outside of the channel scope. boolean outsideInputResource2 = false; + Set outsideInputMembers2 = new HashSet<>(); for (ChannelMember cm: ch2.getInputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(resourceNode.getResourceHierarchy()) && cm.isOutside()) { - outsideInputResource2 = true; // Regarded as pull transfer. - break; + if (cm.isOutside()) { + outsideInputMembers2.add(cm); + if (cm.getResource().getResourceHierarchy().equals(resourceNode.getResourceHierarchy())) { + outsideInputResource2 = true; // Regarded as pull transfer. + } } } if (((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource2) { @@ -548,6 +623,46 @@ params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); } } + if (outsideInputMembers2.size() > 0) { + if (!generatesComponent(resourceNode.getResourceHierarchy())) { + ResourcePath srcRes2 = resourceNode.getOutSideResource(); + for (ChannelMember out: ch2.getOutputChannelMembers()) { + if (!generatesComponent(out.getResource().getResourceHierarchy())) { + ResourcePath dstRes2 = out.getResource(); + if (srcRes2.getParent().equals(dstRes2.getParent())) { + Map>> resourcePaths = null; + try { + resourcePaths = ch2.fillOutsideResourcePaths(out, getPullAccessor()); + if (resourcePaths != null && resourcePaths.size() > 0) { + for (ChannelMember outsideMember: outsideInputMembers2) { + for (ChannelMember dependingMember: resourcePaths.get(outsideMember).getValue()) { + if (dependingMember.getResource().equals(srcRes2)) { + // An outside input resource path depends on srcRes. + ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); + if (!generatesComponent(outsidePath.getResourceHierarchy())) { + outsidePath = outsidePath.getParent(); + } + String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); + Expression outsideExp = getPullAccessor().getDirectStateAccessorFor(outsidePath, null); + if (generatesComponent(outsidePath.getResourceHierarchy())) { + outsideExp = ((Term) outsideExp).getChild(0); + } + String[] sideEffects = new String[] {""}; + String outsideAccessor = outsideExp.toImplementation(sideEffects); + update.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. + } + } + } + } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + } + } + } + } + } } } } @@ -761,10 +876,13 @@ DataFlowEdge dOut = (DataFlowEdge) resToCh; DataTransferChannel ch2 = ((ChannelNode) resToCh.getDestination()).getChannel(); boolean outsideInputResource2 = false; + Set outsideInputMembers2 = new HashSet<>(); for (ChannelMember cm: ch2.getInputChannelMembers()) { - if (cm.getResource().getResourceHierarchy().equals(resourceNode.getResourceHierarchy()) && cm.isOutside()) { - outsideInputResource2 = true; // Regarded as pull transfer. - break; + if (cm.isOutside()) { + outsideInputMembers2.add(cm); + if (cm.getResource().getResourceHierarchy().equals(resourceNode.getResourceHierarchy())) { + outsideInputResource2 = true; // Regarded as pull transfer. + } } } if (((PushPullAttribute) dOut.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource2) { @@ -806,6 +924,46 @@ params) + langSpec.getStatementDelimiter()); // this.dst.updateSrc(value, refParams); } } + if (outsideInputMembers2.size() > 0) { + if (!generatesComponent(resourceNode.getResourceHierarchy())) { + ResourcePath srcRes2 = resourceNode.getOutSideResource(); + for (ChannelMember out2: ch2.getOutputChannelMembers()) { + if (!generatesComponent(out2.getResource().getResourceHierarchy())) { + ResourcePath dstRes2 = out2.getResource(); + if (srcRes2.getParent().equals(dstRes2.getParent())) { + Map>> resourcePaths = null; + try { + resourcePaths = ch2.fillOutsideResourcePaths(out2, getPullAccessor()); + if (resourcePaths != null && resourcePaths.size() > 0) { + for (ChannelMember outsideMember: outsideInputMembers2) { + for (ChannelMember dependingMember: resourcePaths.get(outsideMember).getValue()) { + if (dependingMember.getResource().equals(srcRes2)) { + // An outside input resource path depends on srcRes. + ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); + if (!generatesComponent(outsidePath.getResourceHierarchy())) { + outsidePath = outsidePath.getParent(); + } + String outsideResName = langSpec.toVariableName(getComponentName(outsidePath.getResourceHierarchy(), langSpec)); + Expression outsideExp = getPullAccessor().getDirectStateAccessorFor(outsidePath, null); + if (generatesComponent(outsidePath.getResourceHierarchy())) { + outsideExp = ((Term) outsideExp).getChild(0); + } + String[] sideEffects = new String[] {""}; + String outsideAccessor = outsideExp.toImplementation(sideEffects); + input.addStatement(langSpec.getFieldAccessor(outsideResName) + langSpec.getAssignment() + outsideAccessor + langSpec.getStatementDelimiter()); // change the reference field. + } + } + } + } + } catch (ParameterizedIdentifierIsFutureWork | ResolvingMultipleDefinitionIsFutureWork + | InvalidMessage | UnificationFailed | ValueUndefined e) { + e.printStackTrace(); + } + } + } + } + } + } } } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java index b9cf60e..3b7f58c 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java @@ -232,20 +232,36 @@ break; } } + // Check if the output resource is outside of the channel scope. + boolean outsideOutputResource = false; + for (ChannelMember cm: ch.getOutputChannelMembers()) { + if (cm.getResource().getResourceHierarchy().equals(rn.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) { + outsideOutputResource = true; // Regarded as push transfer. + break; + } + } if (((PushPullAttribute) re.getAttribute()).getOptions().get(0) == PushPullValue.PUSH && !outsideInputResource) { // Declare a field to refer to the destination resource of push transfer. for (Edge chToRes: re.getDestination().getOutEdges()) { ResourcePath dstRes = ((ResourceNode) chToRes.getDestination()).getOutSideResource(); - String dstResName = null; - if (generatesComponent(dstRes.getResourceHierarchy())) { - dstResName = getComponentName(dstRes.getResourceHierarchy()); - } else { - dstResName = getComponentName(dstRes.getResourceHierarchy().getParent()); + if (!generatesComponent(dstRes.getResourceHierarchy())) { + dstRes = dstRes.getParent(); } + String dstResName = getComponentName(dstRes.getResourceHierarchy()); depends.add(dstRes); component.addField(new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName))); constructor.addParameter(new VariableDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName))); block.addStatement("this." + toVariableName(dstResName) + " = " + toVariableName(dstResName) + ";"); + if (outsideOutputResource) { + if (dstRes.getParent() != null) { + // Reference to root resource. + ResourcePath dstRootRes = dstRes.getRoot(); + String dstRootResName = getComponentName(dstRootRes.getResourceHierarchy()); + component.addField(new FieldDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName))); + constructor.addParameter(new VariableDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName))); + block.addStatement("this." + toVariableName(dstRootResName) + " = " + toVariableName(dstRootResName) + ";"); + } + } } } } @@ -254,7 +270,7 @@ DataFlowEdge re = (DataFlowEdge) resToCh; ResourcePath srcRes = ((ResourceNode) re.getSource()).getOutSideResource(); DataTransferChannel ch = ((ChannelNode) re.getDestination()).getChannel(); - // Check if the input and output resources are outside of the channel scope. + // Check if the input resource is outside of the channel scope. boolean outsideInputResource = false; for (ChannelMember cm: ch.getInputChannelMembers()) { if (cm.getResource().getResourceHierarchy().equals(srcRes.getResourceHierarchy()) && cm.isOutside()) { @@ -262,6 +278,7 @@ break; } } + // Check if the output resource is outside of the channel scope. boolean outsideOutputResource = false; for (ChannelMember cm: ch.getOutputChannelMembers()) { if (cm.getResource().getResourceHierarchy().equals(rn.getOutSideResource().getResourceHierarchy()) && cm.isOutside()) { @@ -270,17 +287,29 @@ } } String srcResName = null; + ResourcePath srcRes2 = srcRes; if (generatesComponent(srcRes.getResourceHierarchy())) { srcResName = getComponentName(srcRes.getResourceHierarchy()); } else { - srcResName = getComponentName(srcRes.getResourceHierarchy().getParent()); + srcRes2 = srcRes.getParent(); + srcResName = getComponentName(srcRes2.getResourceHierarchy()); } if ((((PushPullAttribute) re.getAttribute()).getOptions().get(0) != PushPullValue.PUSH && !outsideOutputResource) || outsideInputResource) { // Declare a field to refer to the source resource of pull transfer. - depends.add(srcRes); + depends.add(srcRes2); component.addField(new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName))); constructor.addParameter(new VariableDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName))); block.addStatement("this." + toVariableName(srcResName) + " = " + toVariableName(srcResName) + ";"); + if (outsideInputResource) { + if (srcRes2.getParent() != null) { + // Reference to root resource. + ResourcePath srcRootRes = srcRes2.getRoot(); + String srcRootResName = getComponentName(srcRootRes.getResourceHierarchy()); + component.addField(new FieldDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName))); + constructor.addParameter(new VariableDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName))); + block.addStatement("this." + toVariableName(srcRootResName) + " = " + toVariableName(srcRootResName) + ";"); + } + } } else { // Declare an update method in the type of the destination resource. ArrayList vars = new ArrayList<>(); @@ -389,16 +418,21 @@ break; } } - if (outsideOutputResource) { + if (outsideOutputResource) { // This logic may be incorrect. (ToDo) // Declare a field in the parent component to refer to the destination resource of push transfer. - String dstResName = null; - if (generatesComponent(dstRes.getResourceHierarchy())) { - dstResName = getComponentName(dstRes.getResourceHierarchy()); - } else { - dstResName = getComponentName(dstRes.getResourceHierarchy().getParent()); + if (!generatesComponent(dstRes.getResourceHierarchy())) { + dstRes = dstRes.getParent(); } + String dstResName = getComponentName(dstRes.getResourceHierarchy()); FieldDeclaration refFieldForPush = new FieldDeclaration(new Type(dstResName, dstResName), toVariableName(dstResName)); fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), refFieldForPush)); + if (dstRes.getParent() != null) { + // Reference to root resource. + ResourcePath dstRootRes = dstRes.getRoot(); + String dstRootResName = getComponentName(dstRootRes.getResourceHierarchy()); + FieldDeclaration refRootFieldForPush = new FieldDeclaration(new Type(dstRootResName, dstRootResName), toVariableName(dstRootResName)); + fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), refRootFieldForPush)); + } } } } @@ -414,16 +448,21 @@ break; } } - if (outsideInputResource) { + if (outsideInputResource) { // This logic may be incorrect. (ToDo) // Declare a field in the parent component to refer to the source resource of pull transfer. - String srcResName = null; - if (generatesComponent(srcRes.getResourceHierarchy())) { - srcResName = getComponentName(srcRes.getResourceHierarchy()); - } else { - srcResName = getComponentName(srcRes.getResourceHierarchy().getParent()); + if (!generatesComponent(srcRes.getResourceHierarchy())) { + srcRes = srcRes.getParent(); } + String srcResName = getComponentName(srcRes.getResourceHierarchy()); FieldDeclaration refFieldForPull = new FieldDeclaration(new Type(srcResName, srcResName), toVariableName(srcResName)); fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), refFieldForPull)); + if (srcRes.getParent() != null) { + // Reference to root resource. + ResourcePath srcRootRes = srcRes.getRoot(); + String srcRootResName = getComponentName(srcRootRes.getResourceHierarchy()); + FieldDeclaration refRootFieldForPull = new FieldDeclaration(new Type(srcRootResName, srcRootResName), toVariableName(srcRootResName)); + fields.add(new AbstractMap.SimpleEntry(rn.getParent().getResourceHierarchy(), refRootFieldForPull)); + } noPullTransfer = false; } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index 87791a0..1515354 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.Map.Entry; import code.ast.CompilationUnit; import code.ast.MethodDeclaration; @@ -226,7 +227,7 @@ } if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { boolean isContainedPush = false; - HashMap inputResourceToStateAccessor = new HashMap<>(); + Map inputResourceToStateAccessor = new HashMap<>(); for (Edge chToRes2: dst.getInEdges()) { DataTransferChannel ch2 = ((ChannelNode) chToRes2.getSource()).getChannel(); for (Edge resToCh2: chToRes2.getSource().getInEdges()) { @@ -252,6 +253,7 @@ } String[] sideEffects = new String[] {""}; // generate a return statement. + // An input resource is outside. if (!isContainedPush) { // All incoming edges are in PULL style. String curState = ch.deriveUpdateExpressionOf(out, JavaCodeGenerator.pullAccessor).toImplementation(sideEffects); @@ -262,6 +264,91 @@ getter.addStatement(sideEffects[0] + "return " + curState + ";"); } } + if (outsideInputResource) { + Map>> resourcePaths = ch.fillOutsideResourcePaths(out, JavaCodeGenerator.pullAccessor); + if (resourcePaths != null && resourcePaths.size() > 0) { + for (ChannelMember outsideMember: resourcePaths.keySet()) { + ResourcePath outsidePath = resourcePaths.get(outsideMember).getKey(); + if (!JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { + outsidePath = outsidePath.getParent(); + } + String outsideResName = JavaCodeGenerator.toVariableName(JavaCodeGenerator.getComponentName(outsidePath.getResourceHierarchy())); + Set dependingMembers = resourcePaths.get(outsideMember).getValue(); + for (ChannelMember dependingMember: dependingMembers) { + ResourcePath dependingRes = dependingMember.getResource(); + ResourceNode dependingNode = null; + PushPullAttribute pushPull2 = null; + for (Edge resToCh2: resToCh.getDestination().getInEdges()) { + if (((ResourceNode) resToCh2.getSource()).getOutSideResource().equals(dependingRes)) { + dependingNode = (ResourceNode) resToCh2.getSource(); + pushPull2 = (PushPullAttribute) resToCh.getAttribute(); + } + } + TypeDeclaration dependingComponent = null; + if (JavaCodeGenerator.generatesComponent(dependingRes.getResourceHierarchy())) { + String dependingResourceName = JavaCodeGenerator.getComponentName(dependingRes.getResourceHierarchy()); + dependingComponent = componentMap.get(dependingResourceName); + } else { + String dependingParentResourceName = JavaCodeGenerator.getComponentName(dependingRes.getParent().getResourceHierarchy()); + dependingComponent = componentMap.get(dependingParentResourceName); + } + if (dstComponent == dependingComponent) { + // In the common parent. + if (dependingNode != null) { + // Inspect further dependency. + for (Edge chToRes2: dependingNode.getInEdges()) { + DataTransferChannel ch2 = ((ChannelNode) chToRes2.getSource()).getChannel(); + if (ch2.getInputChannelMembers().size() == 0) { + // In an input method. + MethodDeclaration input = getInputMethod(dependingComponent, ch2.getOutputChannelMembers().iterator().next()); + Expression outsideExp = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(outsidePath, null); + if (JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { + outsideExp = ((Term) outsideExp).getChild(0); + } + String[] sideEffects = new String[] {""}; + String outsideAccessor = outsideExp.toImplementation(sideEffects); + input.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. + } else { + boolean isPush = true; + for (Edge resToCh2: chToRes2.getSource().getInEdges()) { + if (((PushPullAttribute) resToCh2.getAttribute()).getOptions().get(0) != PushPullValue.PUSH) { + isPush = false; + break; + } + } + if (isPush) { + for (Edge resToCh2: chToRes2.getSource().getInEdges()) { + // In an update method. + ResourceNode dependingResSrc = (ResourceNode) resToCh2.getSource(); + MethodDeclaration update = getUpdateMethod(dependingComponent, JavaCodeGenerator.getComponentName(dependingResSrc.getResourceHierarchy())); + Expression outsideExp = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(outsidePath, null); + if (JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { + outsideExp = ((Term) outsideExp).getChild(0); + } + String[] sideEffects = new String[] {""}; + String outsideAccessor = outsideExp.toImplementation(sideEffects); + update.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. + } + } + } + } + } + } else { + if (pushPull2.getOptions().get(0) == PushPullValue.PUSH) { + MethodDeclaration update = getUpdateMethod(dstComponent, JavaCodeGenerator.getComponentName(dependingRes.getResourceHierarchy())); + Expression outsideExp = JavaCodeGenerator.pullAccessor.getDirectStateAccessorFor(outsidePath, null); + if (JavaCodeGenerator.generatesComponent(outsidePath.getResourceHierarchy())) { + outsideExp = ((Term) outsideExp).getChild(0); + } + String[] sideEffects = new String[] {""}; + String outsideAccessor = outsideExp.toImplementation(sideEffects); + update.addStatement("this." + outsideResName + " = " + outsideAccessor + ";"); // change the reference field. + } + } + } + } + } + } } } } @@ -520,13 +607,28 @@ return inputs; } - private static MethodDeclaration getInputMethod(TypeDeclaration component, ChannelMember out) { + private static List getInputMethods(TypeDeclaration component, ResourceHierarchy resource, DataTransferModel model) { + List inputs = new ArrayList<>(); + for (Channel c: model.getIOChannels()) { + DataTransferChannel channel = (DataTransferChannel) c; + // I/O channel + for (ChannelMember out: channel.getOutputChannelMembers()) { + if (resource.equals(out.getResource().getResourceHierarchy())) { + MethodDeclaration input = getInputMethod(component, out); + inputs.add(input); + } + } + } + return inputs; + } + + private static MethodDeclaration getInputMethod(TypeDeclaration component, ChannelMember cm) { MethodDeclaration input = null; - if (out.getStateTransition().getMessageExpression() instanceof Term) { - Term message = (Term) out.getStateTransition().getMessageExpression(); + if (cm.getStateTransition().getMessageExpression() instanceof Term) { + Term message = (Term) cm.getStateTransition().getMessageExpression(); input = getMethod(component, message.getSymbol().getImplName()); - } else if (out.getStateTransition().getMessageExpression() instanceof Variable) { - Variable message = (Variable) out.getStateTransition().getMessageExpression(); + } else if (cm.getStateTransition().getMessageExpression() instanceof Variable) { + Variable message = (Variable) cm.getStateTransition().getMessageExpression(); input = getMethod(component, message.getName()); } return input; diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index 9a01dd3..17710f0 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -6,6 +6,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import algorithms.TypeInference; @@ -341,8 +342,8 @@ } if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { // generate a return statement. - Map resourcePaths = new HashMap<>(); - Expression curExp = ch.deriveUpdateExpressionAndConcreteResourcePathsOf(out, JerseyCodeGenerator.pullAccessor, resourcePaths); // no pull data transfer is included. + Expression curExp = ch.deriveUpdateExpressionOf(out, JerseyCodeGenerator.pullAccessor); // no pull data transfer is included. + Map>> resourcePaths = ch.fillOutsideResourcePaths(out, JerseyCodeGenerator.pullAccessor); String[] sideEffects = new String[] {""}; String curState = curExp.toImplementation(sideEffects); getter.addStatement(sideEffects[0] + "return " + curState + ";"); @@ -352,9 +353,9 @@ Type refResourceType = c.getResource().getResourceStateType(); generatePullDataTransfer(getter, refResourceName, refResourceName, refResourceType); } - for (Map.Entry pathEnt: resourcePaths.entrySet()) { + for (Entry>> pathEnt: resourcePaths.entrySet()) { ChannelMember cm = pathEnt.getKey(); - ResourcePath src2 = pathEnt.getValue(); + ResourcePath src2 = pathEnt.getValue().getKey(); // get outside src resource state by pull data transfer. if (cm.isOutside() || src2.getCommonPrefix(dst.getOutSideResource()) == null) { Type srcResourceType = src2.getResourceStateType(); diff --git a/AlgebraicDataflowArchitectureModel/src/models/algebra/Position.java b/AlgebraicDataflowArchitectureModel/src/models/algebra/Position.java index 0a7c10b..de90a73 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/algebra/Position.java +++ b/AlgebraicDataflowArchitectureModel/src/models/algebra/Position.java @@ -28,6 +28,14 @@ public boolean isEmpty() { return (orders == null || orders.size() == 0); } + + public boolean isAncestorOf(Position another) { + if (another.orders.size() < this.orders.size()) return false; + for (int i = 0; i < orders.size(); i++) { + if (this.orders.get(i) != another.orders.get(i)) return false; + } + return true; + } public Object clone() { return new Position((ArrayList) orders.clone()); diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java index 065525c..0186360 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map.Entry; +import java.util.Set; import models.algebra.Constant; import models.algebra.Expression; @@ -49,7 +50,7 @@ return true; } - public Expression deriveMessageConstraintFor(Expression curStateValue, Expression nextStateValue) throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { + public Expression deriveMessageConstraintFor(Expression curStateValue, Expression nextStateValue, Set substitutedPositions) throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { HashMap> bindings = new HashMap<>(); Expression curStateTerm = getCurStateExpression(); @@ -104,24 +105,10 @@ } Expression messageTerm = getMessageExpression(); - if (!(messageTerm instanceof Term) && !(messageTerm instanceof Variable)) throw new InvalidMessage(); - HashMap messageVars = messageTerm.getVariables(); - for (Variable var: messageVars.values()) { - if (bindings.get(var) != null) { - if (bindings.get(var).size() > 1) throw new ResolvingMultipleDefinitionIsFutureWork(); - if (messageTerm instanceof Term) { - messageTerm = ((Term) messageTerm).substitute(var, bindings.get(var).iterator().next()); - } else if (messageTerm instanceof Variable) { - if (messageTerm.equals(var)) { - return bindings.get(var).iterator().next(); - } - } - } - } - return messageTerm; + return substituteValues(messageTerm, bindings, substitutedPositions); } - public Expression deriveMessageConstraintFor(Expression curStateValue) throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { + public Expression deriveMessageConstraintFor(Expression curStateValue, Set substitutedPositions) throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { HashMap> bindings = new HashMap<>(); Expression curStateTerm = getCurStateExpression(); @@ -144,15 +131,23 @@ } Expression messageTerm = getMessageExpression(); + return substituteValues(messageTerm, bindings, substitutedPositions); + } + + private Expression substituteValues(Expression messageTerm, HashMap> bindings, Set substitutedPositions) + throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { if (!(messageTerm instanceof Term) && !(messageTerm instanceof Variable)) throw new InvalidMessage(); HashMap messageVars = messageTerm.getVariables(); - for (Variable var: messageVars.values()) { + for (Entry varEnt: messageVars.entrySet()) { + Variable var = varEnt.getValue(); if (bindings.get(var) != null) { if (bindings.get(var).size() > 1) throw new ResolvingMultipleDefinitionIsFutureWork(); if (messageTerm instanceof Term) { + substitutedPositions.add(varEnt.getKey()); messageTerm = ((Term) messageTerm).substitute(var, bindings.get(var).iterator().next()); } else if (messageTerm instanceof Variable) { if (messageTerm.equals(var)) { + substitutedPositions.add(new Position()); return bindings.get(var).iterator().next(); } } diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java index 892a2f6..ce8c581 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java @@ -1,5 +1,7 @@ package models.dataFlowModel; +import java.util.AbstractMap; +import java.util.AbstractMap.SimpleEntry; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -210,10 +212,28 @@ throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { return deriveUpdateExpressionOf(targetMember, stateAccessor, null); } + + public Expression deriveUpdateExpressionOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor, Map inputResourceToStateAccessor) + throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { + if (!getOutputChannelMembers().contains(targetMember)) return null; + + // Calculate unified message constraints + Map> substitutedPositionsFromChannels = new HashMap<>(); + Term unifiedMessage = calcUnifiedMessage(targetMember, stateAccessor, inputResourceToStateAccessor, substitutedPositionsFromChannels); + + // Calculate the next state of target resource from the unified message and the current resource state + Expression curOutputStateAccessor = stateAccessor.getCurrentStateAccessorFor(targetMember, targetMember); + if (unifiedMessage == null) { + // for IOChannel + if (targetMember.getStateTransition().getMessageExpression() instanceof Term) { + unifiedMessage = (Term) targetMember.getStateTransition().getMessageExpression(); + } + } + return targetMember.getStateTransition().deriveNextStateExpressionFor(curOutputStateAccessor, unifiedMessage); + } /** - * Derive the state update calculation of the target channel member and the filled outside resource paths with a given resource push/pull state accessor. - * @param targetMember a channel member whose state is to be updated + * Fill outside resource paths with a given resource push/pull state accessor. * @param stateAccessor a push/pull resource state accessor * @param resourcePaths a container to be returned with filled outside resource paths * @return the derived update calculation @@ -223,70 +243,87 @@ * @throws UnificationFailed * @throws ValueUndefined */ - public Expression deriveUpdateExpressionAndConcreteResourcePathsOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor, Map resourcePaths) + public Map>> fillOutsideResourcePaths(ChannelMember targetMember, IResourceStateAccessor stateAccessor) throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { - return deriveUpdateExpressionAndConcreteResourcePathsOf(targetMember, stateAccessor, null, resourcePaths); + return fillOutsideResourcePaths(targetMember, stateAccessor, null); } - public Expression deriveUpdateExpressionOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor, HashMap inputResourceToStateAccessor) + public Map>> fillOutsideResourcePaths(ChannelMember targetMember, IResourceStateAccessor stateAccessor, Map inputResourceToStateAccessor) throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { if (!getOutputChannelMembers().contains(targetMember)) return null; - - // Calculate unified message constraints - Term unifiedMessage = calcUnifiedMessage(targetMember, stateAccessor, inputResourceToStateAccessor); - - // Calculate the next state of target resource from the unified message and the current resource state - Expression curOutputStateAccessor = stateAccessor.getCurrentStateAccessorFor(targetMember, targetMember); - if (unifiedMessage == null) { - // for IOChannel - if (targetMember.getStateTransition().getMessageExpression() instanceof Term) { - unifiedMessage = (Term) targetMember.getStateTransition().getMessageExpression(); - } - } - return targetMember.getStateTransition().deriveNextStateExpressionFor(curOutputStateAccessor, unifiedMessage); - } - - public Expression deriveUpdateExpressionAndConcreteResourcePathsOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor, HashMap inputResourceToStateAccessor, Map resourcePaths) - throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { - if (!getOutputChannelMembers().contains(targetMember)) return null; + Map>> resourcePaths = new HashMap<>(); // Calculate unified message constraints from input and reference state transitions - Term unifiedMessage = calcUnifiedMessage(targetMember, stateAccessor, inputResourceToStateAccessor); + Map> substitutedPositionsFromChannels = new HashMap<>(); + Term unifiedMessage = calcUnifiedMessage(targetMember, stateAccessor, inputResourceToStateAccessor, substitutedPositionsFromChannels); // Fill outside resource paths if (unifiedMessage != null) { for (ChannelMember cm: getInputChannelMembers()) { if (cm.isOutside()) { - resourcePaths.put(cm, fillOutsideResourcePath(cm.getResource(), unifiedMessage, targetMember.getStateTransition().getMessageExpression())); + Set dependingVarPos = new HashSet<>(); + ResourcePath filledResPath = fillOutsideResourcePath(cm.getResource(), unifiedMessage, targetMember.getStateTransition().getMessageExpression(), dependingVarPos); + Set dependingChannelMembers = new HashSet<>(); + for (ChannelMember otherCm: substitutedPositionsFromChannels.keySet()) { + for (Position otherPos: substitutedPositionsFromChannels.get(otherCm)) { + for (Position thisPos: dependingVarPos) { + if (thisPos.isAncestorOf(otherPos)) { + dependingChannelMembers.add(otherCm); + break; + } + } + if (dependingChannelMembers.contains(otherCm)) break; + } + } + resourcePaths.put(cm, new AbstractMap.SimpleEntry(filledResPath, dependingChannelMembers)); } } for (ChannelMember cm: getReferenceChannelMembers()) { if (cm.isOutside()) { - resourcePaths.put(cm, fillOutsideResourcePath(cm.getResource(), unifiedMessage, targetMember.getStateTransition().getMessageExpression())); + Set dependingVarPos = new HashSet<>(); + ResourcePath filledResPath = fillOutsideResourcePath(cm.getResource(), unifiedMessage, targetMember.getStateTransition().getMessageExpression(), dependingVarPos); + Set dependingChannelMembers = new HashSet<>(); + for (ChannelMember otherCm: substitutedPositionsFromChannels.keySet()) { + for (Position otherPos: substitutedPositionsFromChannels.get(otherCm)) { + for (Position thisPos: dependingVarPos) { + if (thisPos.isAncestorOf(otherPos)) { + dependingChannelMembers.add(otherCm); + break; + } + } + if (dependingChannelMembers.contains(otherCm)) break; + } + } + resourcePaths.put(cm, new AbstractMap.SimpleEntry(filledResPath, dependingChannelMembers)); } } for (ChannelMember cm: getOutputChannelMembers()) { if (cm.isOutside()) { - resourcePaths.put(cm, fillOutsideResourcePath(cm.getResource(), unifiedMessage, targetMember.getStateTransition().getMessageExpression())); + Set dependingVarPos = new HashSet<>(); + ResourcePath filledResPath = fillOutsideResourcePath(cm.getResource(), unifiedMessage, targetMember.getStateTransition().getMessageExpression(), dependingVarPos); + Set dependingChannelMembers = new HashSet<>(); + for (ChannelMember otherCm: substitutedPositionsFromChannels.keySet()) { + for (Position otherPos: substitutedPositionsFromChannels.get(otherCm)) { + for (Position thisPos: dependingVarPos) { + if (thisPos.isAncestorOf(otherPos)) { + dependingChannelMembers.add(otherCm); + break; + } + } + if (dependingChannelMembers.contains(otherCm)) break; + } + } + resourcePaths.put(cm, new AbstractMap.SimpleEntry(filledResPath, dependingChannelMembers)); } } } - - // Calculate the next state of target resource from the unified message and the current resource state - Expression curOutputStateAccessor = stateAccessor.getCurrentStateAccessorFor(targetMember, targetMember); - if (unifiedMessage == null) { - // for IOChannel - if (targetMember.getStateTransition().getMessageExpression() instanceof Term) { - unifiedMessage = (Term) targetMember.getStateTransition().getMessageExpression(); - } - } - return targetMember.getStateTransition().deriveNextStateExpressionFor(curOutputStateAccessor, unifiedMessage); + return resourcePaths; } - private Term calcUnifiedMessage(ChannelMember targetMember, IResourceStateAccessor stateAccessor, - HashMap inputResourceToStateAccessor) + private Term calcUnifiedMessage(ChannelMember targetMember, IResourceStateAccessor stateAccessor, + Map inputResourceToStateAccessor, Map> substitutedPositionsFromChannels) throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork, UnificationFailed { - HashSet messageConstraints = new HashSet<>(); + Set messageConstraints = new HashSet<>(); // Calculate message constraints from input state transitions for (ChannelMember inputMember: getInputChannelMembers()) { @@ -299,7 +336,9 @@ curInputStateAccessor = inputResourceToStateAccessor.get(inputMember).getCurrentStateAccessorFor(inputMember, targetMember); nextInputStateAccessor = inputResourceToStateAccessor.get(inputMember).getNextStateAccessorFor(inputMember, targetMember); } - Expression messageConstraintByInput = inputMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor, nextInputStateAccessor); + Set substitutedPositions = new HashSet<>(); + Expression messageConstraintByInput = inputMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor, nextInputStateAccessor, substitutedPositions); + if (substitutedPositions.size() > 0) substitutedPositionsFromChannels.put(inputMember, substitutedPositions); messageConstraints.add((Term) messageConstraintByInput); } @@ -311,7 +350,9 @@ } else { curInputStateAccessor = inputResourceToStateAccessor.get(referenceMember).getCurrentStateAccessorFor(referenceMember, targetMember); } - Expression messageConstraintByReference = referenceMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor); + Set substitutedPositions = new HashSet<>(); + Expression messageConstraintByReference = referenceMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor, substitutedPositions); + if (substitutedPositions.size() > 0) substitutedPositionsFromChannels.put(referenceMember, substitutedPositions); messageConstraints.add((Term) messageConstraintByReference); } @@ -330,19 +371,19 @@ return unifiedMessage; } - private ResourcePath fillOutsideResourcePath(ResourcePath resource, Term unifiedMessage, Expression messageTerm) + private ResourcePath fillOutsideResourcePath(ResourcePath resource, Term unifiedMessage, Expression messageTerm, Set dependingVarPos) throws ResolvingMultipleDefinitionIsFutureWork { ResourcePath filledResourcePath = new ResourcePath(resource); - HashMap bindings = new HashMap<>(); - HashMap messageVars = messageTerm.getVariables(); + Map> bindings = new HashMap<>(); + Map messageVars = messageTerm.getVariables(); for (Entry messageVarEnt: messageVars.entrySet()) { Variable var = messageVarEnt.getValue(); Position varPos = messageVarEnt.getKey(); Expression valueCalc = unifiedMessage.getSubTerm(varPos); if (valueCalc != null) { if (bindings.get(var) != null) throw new ResolvingMultipleDefinitionIsFutureWork(); - bindings.put(var, valueCalc); + bindings.put(var, new AbstractMap.SimpleEntry(varPos, valueCalc)); } } @@ -350,10 +391,15 @@ for (int i = 0; i < filledResourcePath.getPathParams().size(); i++) { Expression pathParam = dstParams.get(i); if (pathParam instanceof Variable) { - dstParams.set(i, bindings.get((Variable) pathParam)); + dstParams.set(i, bindings.get((Variable) pathParam).getValue()); + dependingVarPos.add(bindings.get((Variable) pathParam).getKey()); } else { + Map pathParamVars = ((Term) pathParam).getVariables(); for (Variable var: bindings.keySet()) { - pathParam = ((Term) pathParam).substitute(var, bindings.get(var)); + if (pathParamVars.values().contains(var)) { + pathParam = ((Term) pathParam).substitute(var, bindings.get(var).getValue()); + dependingVarPos.add(bindings.get((Variable) var).getKey()); + } } if (!(pathParam instanceof Constant)) { pathParam = ((Term) pathParam).reduce();