001    package toolbus.process;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    import java.util.Random;
006    import java.util.Stack;
007    import toolbus.AtomList;
008    import toolbus.State;
009    import toolbus.StateElement;
010    import toolbus.TBTermFactory;
011    import toolbus.environment.Environment;
012    import toolbus.exceptions.ToolBusException;
013    import toolbus.parsercup.PositionInformation;
014    import toolbus.process.debug.ExecutionResult;
015    import aterm.ATerm;
016    
017    /**
018     * @author paulk, Aug 7, 2002 Merge implements the parallell composition operator || It maintains
019     *         its two arguments and randomly selects in which argument the next atom will be executed.
020     *         When both arguments are exhausted, execution continues with the followSet of the merge.
021     */
022    public class Merge extends ProcessExpression implements StateElement{
023            private final static Random rand = new Random();
024            
025            private final int LEFT = 0;
026            private final int RIGHT = 1;
027            
028            private ProcessInstance processInstance;
029            
030            private final ProcessExpression[] expr;
031            
032            private final State[] state;
033            private final State[] initialState;
034            private final State mergeState;
035            
036            private boolean leftLast = false;
037            
038            public Merge(ProcessExpression left, ProcessExpression right, TBTermFactory tbfactory, PositionInformation posInfo){
039                    super(tbfactory, posInfo);
040                    
041                    state = new State[2];
042                    initialState = new State[2];
043                    
044                    expr = new ProcessExpression[2];
045                    expr[LEFT] = left;
046                    expr[RIGHT] = right;
047                    
048                    mergeState = new State();
049                    mergeState.addElement(this);
050            }
051            
052            protected void computeFirst(){
053                    expr[LEFT].computeFirst();
054                    expr[RIGHT].computeFirst();
055            }
056            
057            protected void compile(ProcessInstance processInstance, Stack<String> calls, State follows) throws ToolBusException{
058                    this.processInstance = processInstance;
059                    
060                    expr[LEFT].compile(processInstance, calls, follows);
061                    initialState[LEFT] = state[LEFT] = expr[LEFT].getFirst();
062                    
063                    expr[RIGHT].compile(processInstance, calls, follows);
064                    initialState[RIGHT] = state[RIGHT] = expr[RIGHT].getFirst();
065                    setFollow(follows);
066            }
067            
068            protected void replaceFormals(Environment env) throws ToolBusException{
069                    expr[LEFT].replaceFormals(env);
070                    expr[RIGHT].replaceFormals(env);
071            }
072            
073            protected ProcessExpression copy(){
074                    return new Merge(expr[LEFT].copy(), expr[RIGHT].copy(), tbfactory, getPosInfo());
075            }
076            
077            public AtomList getAtoms(){
078                    return expr[LEFT].getAtoms().union(expr[RIGHT].getAtoms());
079            }
080            
081            public State getFirst(){
082                    return mergeState;
083            }
084            
085            // Implementation of the StateElement interface
086            
087            public boolean contains(StateElement a){
088                    return state[LEFT].contains(a) || state[RIGHT].contains(a);
089            }
090            
091            public ProcessInstance getProcess(){
092                    return processInstance;
093            }
094            
095            public void setTest(ATerm test, Environment env) throws ToolBusException{
096                    state[LEFT].setTest(test, env);
097                    state[RIGHT].setTest(test, env);
098            }
099            
100            public List<ATerm> getTests(){
101                    return new ArrayList<ATerm>(0);
102            }
103            
104            public boolean isEnabled(){
105                    return state[LEFT].isEnabled() || state[RIGHT].isEnabled();
106            }
107            
108            private void initState(){
109                    state[LEFT] = initialState[LEFT];
110                    state[RIGHT] = initialState[RIGHT];
111            }
112            
113            public State gotoNextStateAndActivate(){
114                    State follow = getFollow();
115                    
116                    // System.err.println("Merge.getNextState: " + leftLast + " ; follow = " + follow);
117                    // System.err.println("state[LEFT] =" + state[LEFT]);
118                    // System.err.println("state[RIGHT] =" + state[RIGHT]);
119                    
120                    if(state[LEFT] == follow || state[RIGHT] == follow){
121                            // TODO put the line below in comment since it will throw an exception and X isn't used.
122                            // int x = 3 / 0;
123                    }
124                    
125                    if(leftLast){
126                            State ns = state[LEFT].gotoNextStateAndActivate();
127                            if(ns == follow){
128                                    State r = state[RIGHT];
129                                    // System.err.println("state[LEFT] == follow");
130                                    // System.err.println("returning " + r);
131                                    initState();
132                                    return r;
133                            }
134                            // System.err.println("returning " + mergeState);
135                            state[LEFT] = ns;
136                            return mergeState;
137                            
138                    }
139                    
140                    State ns = state[RIGHT].gotoNextStateAndActivate();
141                    if(ns == follow){
142                            State l = state[LEFT];
143                            // System.err.println("state[RIGHT] == follow");
144                            // System.err.println("returning " + l);
145                            initState();
146                            return l;
147                    }
148                    
149                    // System.err.println("returning " + mergeState);
150                    state[RIGHT] = ns;
151                    return mergeState;
152            }
153            
154            public State gotoNextStateAndActivate(StateElement se){
155                    State follow = getFollow();
156                    
157                    // System.err.println("Merge.getNextState2: " + leftLast + "; " + se + " ; follow = " +
158                    // follow);
159                    // System.err.println("state[LEFT] =" + state[LEFT]);
160                    // System.err.println("state[RIGHT] =" + state[RIGHT]);
161                    
162                    if(state[LEFT].contains(se)){
163                            State ns = state[LEFT].gotoNextStateAndActivate(se);
164                            if(ns == follow){
165                                    State r = state[RIGHT];
166                                    // System.err.println("state[LEFT] == follow");
167                                    // System.err.println("returning " + r);
168                                    initState();
169                                    return r;
170                            }
171                            
172                            // System.err.println("returning " + mergeState);
173                            state[LEFT] = ns;
174                            return mergeState;
175                    }else if(state[RIGHT].contains(se)){
176                            State ns = state[RIGHT].gotoNextStateAndActivate(se);
177                            if(ns == follow){
178                                    State l = state[LEFT];
179                                    // System.err.println("state[RIGHT] == follow");
180                                    // System.err.println("returning " + l);
181                                    initState();
182                                    return l;
183                            }
184                            
185                            // System.err.println("returning " + mergeState);
186                            state[RIGHT] = ns;
187                            return mergeState;
188                    }else{
189                            System.err.println("Merge.getNextState2 wrong!");
190                            return null;
191                    }
192            }
193            
194            public void activate(){
195                    state[LEFT].activate();
196                    state[RIGHT].activate();
197            }
198            
199            /**
200             * Generate next random boolean.
201             */
202            public static boolean nextBoolean(){
203                    return rand.nextBoolean();
204            }
205            
206            public boolean execute() throws ToolBusException{
207                    int l, r;
208                    if(nextBoolean()){
209                            l = LEFT;
210                            r = RIGHT;
211                    }else{
212                            l = RIGHT;
213                            r = LEFT;
214                    }
215                    
216                    if(state[l].execute()){
217                            leftLast = (l == LEFT);
218                            return true;
219                    }else if(state[r].execute()){
220                            leftLast = (r == LEFT);
221                            return true;
222                    }else return false;
223            }
224            
225            public ProcessInstance[] debugExecute() throws ToolBusException{
226                    int l, r;
227                    if(nextBoolean()){
228                            l = LEFT;
229                            r = RIGHT;
230                    }else{
231                            l = RIGHT;
232                            r = LEFT;
233                    }
234                    
235                    ExecutionResult er; 
236                    if((er = state[l].debugExecute()) != null){
237                            leftLast = (l == LEFT);
238                            return er.partners;
239                    }else if((er = state[r].debugExecute()) != null){
240                            leftLast = (r == LEFT);
241                            return er.partners;
242                    }
243                    
244                    return null;
245            }
246            
247            public String toString(){
248                    return "Merge(" + state[LEFT] + "; " + state[RIGHT] + ")";
249            }
250            
251            /*public void addPartners(AtomSet s) throws ToolBusException{
252                    state[LEFT].addPartners(s);
253                    state[RIGHT].addPartners(s);
254            }*/
255            
256            /*public void delPartners(AtomSet s) throws ToolBusException{
257                    state[LEFT].delPartners(s);
258                    state[RIGHT].delPartners(s);
259            }*/
260    }