diff --git a/AlgebraicDataflowArchitectureModel/models/BagTest.model b/AlgebraicDataflowArchitectureModel/models/BagTest.model new file mode 100644 index 0000000..3a27bfa --- /dev/null +++ b/AlgebraicDataflowArchitectureModel/models/BagTest.model @@ -0,0 +1,8 @@ +channel signUp { + out accounts(acs: Map, signUp(id, name)) = insert(acs, id, {"name": name, "friends": nil}) +} + +channel makeFriend(aid) { + out accounts.{aid}.friends(friends: List, addFreinds(fid)) = append(friends, fid) + out accounts.{fid}.friends(friends: List, addFreinds(fid)) = append(friends, aid) +} \ No newline at end of file diff --git a/AlgebraicDataflowArchitectureModel/src/application/simulator/InputEventCellEditor.java b/AlgebraicDataflowArchitectureModel/src/application/simulator/InputEventCellEditor.java index 41ec4d5..06fe2f8 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/simulator/InputEventCellEditor.java +++ b/AlgebraicDataflowArchitectureModel/src/application/simulator/InputEventCellEditor.java @@ -1,68 +1,53 @@ package application.simulator; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; import java.awt.Rectangle; +import java.util.ArrayList; import java.util.EventObject; import java.util.HashMap; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.Map.Entry; import javax.swing.BorderFactory; import javax.swing.JComboBox; -import javax.swing.JFrame; -import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextArea; -import javax.swing.JTextField; import com.mxgraph.model.mxCell; -import com.mxgraph.model.mxGraphModel; import com.mxgraph.model.mxIGraphModel; import com.mxgraph.swing.mxGraphComponent; import com.mxgraph.swing.view.mxICellEditor; import com.mxgraph.util.mxConstants; import com.mxgraph.util.mxUtils; import com.mxgraph.view.mxCellState; -import com.mxgraph.view.mxGraph; -import com.mxgraph.view.mxGraphView; import application.editor.Editor; -import application.layouts.DAGLayout; +import models.algebra.Constant; import models.algebra.Expression; import models.algebra.InvalidMessage; import models.algebra.ParameterizedIdentifierIsFutureWork; +import models.algebra.Position; import models.algebra.Term; import models.algebra.UnificationFailed; import models.algebra.ValueUndefined; import models.algebra.Variable; import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; -import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.DataFlowGraph; import models.dataFlowModel.DataTransferChannel; import models.dataFlowModel.PushPullAttribute; import models.dataFlowModel.PushPullValue; import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; -import models.visualModel.FormulaChannel; import parser.Parser; import parser.Parser.TokenStream; import parser.exceptions.ExpectedColon; import parser.exceptions.ExpectedDoubleQuotation; import parser.exceptions.ExpectedRightBracket; import parser.exceptions.WrongJsonExpression; -import simulator.ChannelState; +import simulator.Event; import simulator.Resource; import simulator.ResourceIdentifier; import simulator.Simulator; -import simulator.Event; -import simulator.SystemState; public class InputEventCellEditor implements mxICellEditor { public int DEFAULT_MIN_WIDTH = 70; @@ -109,10 +94,10 @@ ArrayList eventChs = new ArrayList<>();//iOchannelList ArrayList messages = new ArrayList<>();//ADLmessage ArrayList eventMessages = new ArrayList<>();//messageList - ResourcePath eventResPath = null; + ArrayList eventResPath = new ArrayList<>(); for (Channel ch: simulator.getModel().getInputChannels()) {//all channel - eventResPath = getSelectableMessages(ch, resId, eventChs, messages, eventMessages, eventResPath); + getSelectableMessages(ch, resId, eventChs, messages, eventMessages, eventResPath); } if(messages.isEmpty()) { @@ -150,7 +135,25 @@ stream.addLine(textArea.getText()); Expression eventMessage = parser.parseTerm(stream,simulator.getModel()); - Event newEvent = new Event(eventChs.get(eventNum), eventMessage, eventResPath, simulator.getCurState().getResource(resId)); + //メッセージもパスパラメータになりえるため、メッセージの変数名と値を紐づける + HashMap bindings = new HashMap<>(); + Expression messageTerm = eventChs.get(eventNum).getOutputChannelMembers().iterator().next().getStateTransition().getMessageExpression(); + HashMap messageVars = messageTerm.getVariables(); + if (eventMessage != null) { + for (Entry messageVarEnt: messageVars.entrySet()) { + Variable var = messageVarEnt.getValue(); + Position varPos = messageVarEnt.getKey(); + Expression valueCalc = eventMessage.getSubTerm(varPos); + if (valueCalc != null) { + if (bindings.get(var) != null) throw new ResolvingMultipleDefinitionIsFutureWork(); + if(valueCalc instanceof Constant) { + bindings.put(var, (Constant)valueCalc); + } + } + } + } + + Event newEvent = new Event(eventChs.get(eventNum), eventMessage, eventResPath, simulator.getCurState().getResource(resId), bindings); simulator.transition(newEvent); // SimulationLayout layout = new SimulationLayout(simulator.getCurState()); @@ -188,14 +191,14 @@ } } - private ResourcePath getSelectableMessages(Channel ch, ResourceIdentifier resId, + private void getSelectableMessages(Channel ch, ResourceIdentifier resId, ArrayList eventChs, ArrayList messages, ArrayList eventMessages, - ResourcePath eventResPath) { + ArrayList eventResPath) { if (((DataTransferChannel)ch).getInputResources().size() == 0) {//ioch Or normalch for (ChannelMember out: ((DataTransferChannel)ch).getOutputChannelMembers()) { ResourcePath resPath = out.getResource(); if (resId.isInstanceOf(resPath)) {//account.uid == acounts.123 - eventResPath = resPath; + eventResPath.add(resPath); eventChs.add(((DataTransferChannel)ch)); String message = null; Expression mesExp = out.getStateTransition().getMessageExpression();//sync(a,b) @@ -209,10 +212,9 @@ } } for (Channel childCh: ch.getChildren()) { - eventResPath = getSelectableMessages(childCh, resId, eventChs, messages, eventMessages, eventResPath); + getSelectableMessages(childCh, resId, eventChs, messages, eventMessages, eventResPath); } } - return eventResPath; } // private mxGraph constructNextSimulateGraph(Set simulateRes, DataTransferModel model,DataFlowGraph dataFlowGraph, mxGraph nextGraph) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java index 997d1f6..cf1145e 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/StateTransition.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -167,7 +168,11 @@ return messageTerm; } - public Expression deriveNextStateExpressionFor(Expression curStateValue, Term concreteMessage) + public Expression deriveNextStateExpressionFor(Expression curStateValue, Term concreteMessage) throws ResolvingMultipleDefinitionIsFutureWork, ValueUndefined { + return deriveNextStateExpressionFor(curStateValue, concreteMessage, null); + } + + public Expression deriveNextStateExpressionFor(Expression curStateValue, Term concreteMessage, Map selectorVariables) throws ResolvingMultipleDefinitionIsFutureWork, ValueUndefined { HashMap bindings = new HashMap<>(); @@ -200,6 +205,12 @@ } } + if(selectorVariables != null) { + for(Variable variable : selectorVariables.keySet()) { + bindings.put(variable, selectorVariables.get(variable)); + } + } + Expression nextStateTerm = getNextStateExpression(); if (nextStateTerm instanceof Variable) { nextStateTerm = bindings.get((Variable) nextStateTerm); diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java index 15e3194..ecc2ba5 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataFlowModel/DataTransferChannel.java @@ -1,13 +1,12 @@ package models.dataFlowModel; import java.util.AbstractMap; -import java.util.AbstractMap.SimpleEntry; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; import models.algebra.Constant; import models.algebra.Expression; @@ -19,7 +18,10 @@ import models.algebra.UnificationFailed; import models.algebra.ValueUndefined; import models.algebra.Variable; -import models.dataConstraintModel.*; +import models.dataConstraintModel.Channel; +import models.dataConstraintModel.ChannelMember; +import models.dataConstraintModel.ResourcePath; +import simulator.Event; public class DataTransferChannel extends Channel { protected Set inputChannelMembers = null; @@ -244,13 +246,13 @@ * @throws UnificationFailed * @throws ValueUndefined */ - public Expression deriveUpdateExpressionOf(ChannelMember targetMember, Term message, IResourceStateAccessor stateAccessor) + public Expression deriveUpdateExpressionOf(ChannelMember targetMember, Term message, IResourceStateAccessor stateAccessor, Event event) throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined { if (!getOutputChannelMembers().contains(targetMember)) return null; // Calculate the next state of target resource from the unified message and the current resource state Expression curOutputStateAccessor = stateAccessor.getCurrentStateAccessorFor(targetMember, targetMember); - return targetMember.getStateTransition().deriveNextStateExpressionFor(curOutputStateAccessor, message); + return targetMember.getStateTransition().deriveNextStateExpressionFor(curOutputStateAccessor, message, event.getSelectorVariables()); } /** diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/Event.java b/AlgebraicDataflowArchitectureModel/src/simulator/Event.java index 58a9df8..ac88b99 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/Event.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/Event.java @@ -14,6 +14,7 @@ import models.algebra.Position; import models.algebra.Term; import models.algebra.UnificationFailed; +import models.algebra.Variable; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; @@ -34,12 +35,56 @@ private Set succEvents = new HashSet<>(); private Map> channelSelectorToInputResourcePathParam = new HashMap<>(); private Map> channelSelectorToOutputResourcePathParam = new HashMap<>(); + private Map selectorVariables = new HashMap<>(); + + public Event(DataTransferChannel channel, Expression message, ArrayList outputResPaths, Resource outputResource, Map bindings) { + this.channel = channel; + this.message = message; + this.isInput = true; + this.outputResources.add(outputResource); + + Map variableSelectors = new HashMap<>(); + for(var variable : bindings.keySet()) { + variableSelectors.put(new Selector(variable), bindings.get(variable)); + } + + connectChannelSelectorAndPathParameters(variableSelectors); + + // Extract channel parameters from the output resource. + List channelSelectors = channel.getAllSelectors(); + for(var outputResPath : outputResPaths) { + for (Selector sel: channelSelectors) { + Integer paramIdx = channelSelectorToOutputResourcePathParam.getOrDefault(sel, new HashMap<>()).get(outputResPath); + if(paramIdx == null) { + continue; + } + Resource ancestor = outputResource; + int idx = outputResPath.getPathParams().size(); + while (ancestor != null) { + if (ancestor.getResourceHierarchy().getNumParameters() > 0) { + idx--; + if (idx == paramIdx) break; + } + ancestor = ancestor.getParent(); + } + if (ancestor!= null) { + channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, ancestor.getParameter())); + selectorVariables.put(new Variable(sel.getExpression().toString()), ancestor.getParameter()); + } + } + } + for (Selector sel : variableSelectors.keySet()) { + channelSelectorAndValues.add(new AbstractMap.SimpleEntry<>(sel, variableSelectors.get(sel))); + } + } + public Event(DataTransferChannel channel, Expression message, ResourcePath outputResPath, Resource outputResource) { this.channel = channel; this.message = message; this.isInput = true; this.outputResources.add(outputResource); + connectChannelSelectorAndPathParameters(); // Extract channel parameters from the output resource. @@ -102,9 +147,18 @@ } this.dependingParameters = dependingVarToVal; } - + private void connectChannelSelectorAndPathParameters() { + connectChannelSelectorAndPathParameters(null); + } + + private void connectChannelSelectorAndPathParameters(Map bindings) { List channelSelectors = channel.getAllSelectors(); + if(bindings != null) { + for(var sel : bindings.keySet()) { + channelSelectors.add(sel); + } + } for (Selector sel: channelSelectors) { for (ResourcePath resPath: channel.getInputResources()) { int paramIdx = resPath.getPathParams().indexOf(sel.getExpression()); @@ -131,6 +185,10 @@ } } + public Map getSelectorVariables() { + return selectorVariables; + } + public DataTransferChannel getChannel() { return channel; } diff --git a/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java b/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java index c61e2ae..ac946e3 100644 --- a/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java +++ b/AlgebraicDataflowArchitectureModel/src/simulator/Simulator.java @@ -1,6 +1,5 @@ package simulator; -import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -15,16 +14,15 @@ import models.algebra.Term; import models.algebra.UnificationFailed; import models.algebra.ValueUndefined; -import models.algebra.Variable; import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; -import models.dataFlowModel.DataTransferModel; -import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; import models.dataFlowModel.DataTransferChannel; import models.dataFlowModel.DataTransferChannel.IResourceStateAccessor; +import models.dataFlowModel.DataTransferModel; +import models.dataFlowModel.ResolvingMultipleDefinitionIsFutureWork; import simulator.Event.IResourceStateValueProvider; import simulator.interfaces.INativeReceiver; @@ -178,7 +176,7 @@ if (!event.isInput()) { nextResState = channel.deriveUpdateExpressionOf(out, resouceStateAccessor).getKey(); } else { - nextResState = channel.deriveUpdateExpressionOf(out, (Term) event.getMessage(), resouceStateAccessor); + nextResState = channel.deriveUpdateExpressionOf(out, (Term) event.getMessage(), resouceStateAccessor, event); } ResourceIdentifier outResId = event.getOutputResourceIdentifier(out.getResource()); if (nextResState instanceof Term) {