diff --git a/AlgebraicDataflowArchitectureModel/models/TravelDistance.model b/AlgebraicDataflowArchitectureModel/models/TravelDistance.model new file mode 100644 index 0000000..a0c8fe2 --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/TravelDistance.model @@ -0,0 +1,13 @@ +channel CX { + out pos_x(prev_x: Double, setX(cur_x: Double)) == cur_x +} + +channel CY { + out pos_y(prev_y: Double, setY(cur_y: Double)) == cur_y +} + +channel C { + in pos_x(prev_x, move(dx, dy)) == prev_x + dx + in pos_y(prev_y, move(dx, dy)) == prev_y + dy + out dist(prev_d, move(dx, dy)) == prev_d + sqrt(dx * dx + dy * dy) +} diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 4ccaf6d..b91cf6e 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -329,8 +329,8 @@ target.getResourceStateType() != null ? target.getResourceStateType() : DataConstraintModel.typeInt); } - // for reference channel member - return new Parameter(target.getResourceName(), + // use the cached value as the current state + return new Field(target.getResourceName(), target.getResourceStateType() != null ? target.getResourceStateType() : DataConstraintModel.typeInt); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromControlFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromControlFlowGraph.java index 1b449d4..ecf958d 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromControlFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromControlFlowGraph.java @@ -585,26 +585,27 @@ // Declare an update method in the component. ArrayList vars = new ArrayList<>(); List passedResoueces = dataFlowInform.get(inEdge).get(PushPullValue.PUSH); - Set passedIds = new HashSet<>(); + Set passedResPaths = new HashSet<>(); String methodName = updateMethodName; for (ResourceNode rn: passedResoueces) { - ResourcePath rId = rn.getResource(); - passedIds.add(rId); - methodName += langSpec.toComponentName(rId.getResourceName()); - vars.add(langSpec.newVariableDeclaration(rId.getResourceStateType(), rId.getResourceName())); + ResourcePath resPath = rn.getResource(); + passedResPaths.add(resPath); + methodName += langSpec.toComponentName(resPath.getResourceName()); + vars.add(langSpec.newVariableDeclaration(resPath.getResourceStateType(), resPath.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(); + ChannelMember inMember = null; if (((StoreAttribute) resourceNode.getAttribute()).isStored()) { try { boolean stateUpdateAdded = false; for (Edge e: resourceNode.getInEdges()) { DataFlowEdge re = (DataFlowEdge) e; for (ChannelMember in: re.getChannel().getInputChannelMembers()) { - if (passedIds.contains(in.getResource())) { + if (passedResPaths.contains(in.getResource())) { for (ChannelMember out: re.getChannel().getOutputChannelMembers()) { if (out.getResource().equals(resourceNode.getResource())) { Expression updateExp = re.getChannel().deriveUpdateExpressionOf(out, getPushAccessor()); @@ -618,6 +619,7 @@ } update.addFirstStatement(updateStatement); stateUpdateAdded = true; + inMember = in; break; } } @@ -633,9 +635,10 @@ } // 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 (ResourcePath srcRes: passedIds) { + if (node.getIndegree() > 1 || + (node.getIndegree() == 1 && inMember != null && inMember.getStateTransition().isRightPartial())) { + // If incoming edges are multiple, or the current state of an input member is needed. + for (ResourcePath srcRes: passedResPaths) { String srcResName = srcRes.getResourceName(); if (langSpec.declareField()) { // Declare the cache field. @@ -647,8 +650,8 @@ } // Update the cache field. - String cashStatement = langSpec.getFieldAccessor(srcResName) + langSpec.getAssignment() + srcResName + langSpec.getStatementDelimiter(); - update.addFirstStatement(cashStatement); + String cacheStatement = langSpec.getFieldAccessor(srcResName) + langSpec.getAssignment() + srcResName + langSpec.getStatementDelimiter(); + update.addStatement(cacheStatement); } } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index ce5ab0c..187e2e2 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -225,8 +225,9 @@ } // 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 (resourceNode.getIndegree() > 1 + || (resourceNode.getIndegree() == 1 && ch.getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { + // If incoming edges are multiple, or the current state of an input member is needed. if (langSpec.declareField()) { // Declare the cache field. FieldDeclaration cacheField = langSpec.newFieldDeclaration( @@ -237,9 +238,9 @@ } // 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); + String cacheStatement = langSpec.getFieldAccessor(srcResName) + langSpec.getAssignment() + srcResName + langSpec.getStatementDelimiter(); + if (update.getBody() == null || !update.getBody().getStatements().contains(cacheStatement)) { + update.addStatement(cacheStatement); } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java index 34590cf..6e63cee 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java @@ -102,8 +102,9 @@ fieldInitializer += resName.toLowerCase() + ","; f = true; } else { - if (rn.getIndegree() > 1) { - // Declare a field to cash the state of the source resource in the type of the destination resource. + if (rn.getIndegree() > 1 + || (rn.getIndegree() == 1 && re.getChannel().getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { + // Declare a field to cache the state of the source resource in the type of the destination resource. ResourcePath cashResId = ((ResourceNode) re.getSource()).getResource(); type.addField(new FieldDeclaration( cashResId.getResourceStateType(), ((ResourceNode) re.getSource()).getResource().getResourceName(), getInitializer(cashResId))); @@ -438,8 +439,8 @@ target.getResourceStateType() != null ? target.getResourceStateType() : DataConstraintModel.typeInt); } - // for reference channel member - return new Parameter(target.getResourceName(), + // use the cached value as the current state + return new Field(target.getResourceName(), target.getResourceStateType() != null ? target.getResourceStateType() : DataConstraintModel.typeInt); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index 1e8aec5..3f8696c 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -78,11 +78,12 @@ update.addFirstStatement(updateStatement); } } - if (dst.getIndegree() > 1) { - // update a cash of src side resource (when incoming edges are multiple) - String cashStatement = "this." + srcResourceName + " = " + srcResourceName + ";"; - if (update.getBody() == null || !update.getBody().getStatements().contains(cashStatement)) { - update.addFirstStatement(cashStatement); + if (dst.getIndegree() > 1 + || (dst.getIndegree() == 1 && d.getChannel().getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { + // update a cache of src side resource (when incoming edges are multiple) + String cacheStatement = "this." + srcResourceName + " = " + srcResourceName + ";"; + if (update.getBody() == null || !update.getBody().getStatements().contains(cacheStatement)) { + update.addStatement(cacheStatement); } } MethodDeclaration getter = getGetterMethod(dstType); diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java index d191a18..98bf8eb 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java @@ -119,12 +119,15 @@ } } } - if (rn.getInEdges().size() > 1) { - // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. - update.addAnnotation(new Annotation("Path", "\"/" + srcName + "\"")); - // Declare a field to cash the state of the source resource in the type of the destination resource. - ResourcePath cashResId = ((ResourceNode) re.getSource()).getResource(); - type.addField(new FieldDeclaration(cashResId.getResourceStateType(), srcName, getInitializer(cashResId))); + if (rn.getInEdges().size() > 1 + || (rn.getIndegree() == 1 && re.getChannel().getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { + // Declare a field to cache the state of the source resource in the type of the destination resource. + ResourcePath cacheRes = ((ResourceNode) re.getSource()).getResource(); + type.addField(new FieldDeclaration(cacheRes.getResourceStateType(), srcName, getInitializer(cacheRes))); + if (rn.getIndegree() > 1) { + // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. + update.addAnnotation(new Annotation("Path", "\"/" + srcName + "\"")); + } } type.addMethod(update); } @@ -322,7 +325,10 @@ target.getResourceStateType() != null ? target.getResourceStateType() : DataConstraintModel.typeInt); } - return null; + // use the cached value as the current state + return new Field(target.getResourceName(), + target.getResourceStateType() != null ? target.getResourceStateType() + : DataConstraintModel.typeInt); } @Override diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index 9ad2995..d4bdbf2 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -99,11 +99,12 @@ update.addFirstStatement(updateStatement); } } - if (dst.getIndegree() > 1) { + if (dst.getIndegree() > 1 + || (dst.getIndegree() == 1 && d.getChannel().getInputChannelMembers().iterator().next().getStateTransition().isRightPartial())) { // update a cash of src side resource (when incoming edges are multiple) String cashStatement = "this." + srcResourceName + " = " + srcResourceName + ";"; if (update.getBody() == null || !update.getBody().getStatements().contains(cashStatement)) { - update.addFirstStatement(cashStatement); + update.addStatement(cashStatement); } } // to convert a json param to a tuple, pair or map object. diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java index 25b47be..5c731bc 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java @@ -44,11 +44,22 @@ } public boolean isRightUnary() { - for (Position pos : curStateExpression.getVariables().keySet()) { - if (nextStateExpression.contains(curStateExpression.getVariables().get(pos))) return false; + for (Variable var: curStateExpression.getVariables().values()) { + if (nextStateExpression.contains(var)) return false; } return true; } + + public boolean isRightPartial() { + for (Variable var: curStateExpression.getVariables().values()) { + if (messageExpression.contains(var)) return true; + } + if (isRightUnary()) return false; + for (Variable var: messageExpression.getVariables().values()) { + if (nextStateExpression.contains(var)) return true; + } + return false; + } public Expression deriveMessageConstraintFor(Expression curStateValue, Expression nextStateValue) throws InvalidMessage, ResolvingMultipleDefinitionIsFutureWork { HashMap> bindings = new HashMap<>();