001    /**
002     * @author paulk, Jul 22, 2002
003     */
004    
005    package toolbus.process;
006    
007    import java.util.ArrayList;
008    import java.util.List;
009    import java.util.Stack;
010    
011    import toolbus.AtomList;
012    import toolbus.State;
013    import toolbus.StateElement;
014    import toolbus.TBTermFactory;
015    import toolbus.atom.Tau;
016    import toolbus.environment.Environment;
017    import toolbus.exceptions.NoSuchProcessDefinitionException;
018    import toolbus.exceptions.ToolBusException;
019    import toolbus.exceptions.ToolBusExecutionException;
020    import toolbus.parsercup.PositionInformation;
021    import toolbus.process.debug.ExecutionResult;
022    import aterm.ATerm;
023    import aterm.ATermAppl;
024    import aterm.ATermList;
025    
026    /**
027     * ProcessCall implements a call to a process P(f1, f2, ...). There are two main cases: (1) A static
028     * process call: the current environment does not contain a declaration for a string variable P and
029     * the name of the process is P. Its declaration is taken and the call is replaced statically by the
030     * corresponding process expression. (2) A dynamic process call: the current environment *does*
031     * contain a declaration for a string variable P and the name of the process is the *string value*
032     * of that variable. The declaration correspodning to that value is taken and the call is replaced
033     * dynamically by the corresponding process expression. In the dynamic case, each the call is
034     * encountered during execution it the may thus be expanded into a different process expression. Due
035     * to the possibility of dynamic calls, a process call is a StateElement and exists during
036     * execution.
037     */
038    public class ProcessCall extends ProcessExpression implements StateElement{
039            private String name;
040            
041            protected final ATermList originalActuals;
042            protected ATermList actuals;
043            
044            private ATermList formals;
045            
046            private Environment env;
047            
048            private ProcessDefinition definition = null;
049            
050            protected ProcessExpression PE;
051            
052            protected ProcessInstance processInstance;
053            
054            private boolean evalArgs = true;
055            
056            private final State firstState;
057            
058            private boolean executing = false;
059            
060            private boolean activated = false;
061            
062            public ProcessCall(String name, ATermList actuals, TBTermFactory tbfactory, PositionInformation posInfo){
063                    super(tbfactory, posInfo);
064                    this.name = name;
065                    this.originalActuals = actuals;
066                    this.actuals = actuals;
067                    
068                    firstState = new State();
069                    firstState.addElement(this);
070            }
071            
072            public ProcessCall(ATerm call, TBTermFactory tbfactory, PositionInformation posInfo){
073                    this(((ATermAppl) call).getName(), ((ATermAppl) call).getArguments(), tbfactory, posInfo);
074            }
075            
076            public ProcessCall(String name, ATermList actuals, boolean evalArgs, TBTermFactory tbfactory, PositionInformation posInfo){
077                    this(name, actuals, tbfactory, posInfo);
078                    this.evalArgs = evalArgs;
079            }
080            
081            public void setEvalArgs(boolean b){
082                    evalArgs = b;
083            }
084            
085            protected ProcessExpression copy(){
086                    return new ProcessCall(name, actuals, evalArgs, tbfactory, getPosInfo());
087            }
088            
089            protected void computeFirst(){
090                    // System.err.println("ProcessCall.computeFirst: " + firstState);
091                    setFirst(firstState);
092            }
093            
094            protected void replaceFormals(Environment e) throws ToolBusException{
095                    //System.err.println("ProcessCall.replaceFormals(" + name + "): " + env);
096                    env = e.copy();
097                    
098                    actuals = (ATermList) tbfactory.replaceFormals(originalActuals, env);
099            }
100            
101            protected void compile(ProcessInstance P, Stack<String> calls, State follows) throws ToolBusException{
102                    processInstance = P;
103                    setFollow(follows);
104                    
105                    if(calls.contains(name)) throw new ToolBusExecutionException("Recursive call of "+name, getPosInfo());
106                    
107                    try{
108                            definition = processInstance.getToolBus().getProcessDefinition(name, originalActuals.getLength());
109                    }catch(NoSuchProcessDefinitionException nspdex){
110                            throw new ToolBusExecutionException(nspdex.getMessage(), getPosInfo());
111                    }
112                    
113                    // System.err.println("name = " + name);
114                    // System.err.println("definition = " + definition);
115                    
116                    actuals = (ATermList) tbfactory.replaceFormals(originalActuals, env);
117                    PE = definition.getProcessExpression(actuals);
118                    
119                    // System.err.println("ProcessCall.compile(" + name + ", " + processInstance + "," + PE + ")");
120                    formals = definition.getFormals();
121                    
122                    env.introduceBindings(formals, actuals, evalArgs);
123                    actuals = (ATermList) tbfactory.replaceFormals(actuals, env);
124                    
125                    // System.err.println("ProcessCall.compile(" + name + "): " + env);
126                    // System.err.println("actuals = " + actuals);
127                    PE.computeFirst();
128                    PE.replaceFormals(env);
129                    
130                    calls.push(name);
131                    PE.compile(processInstance, calls, firstState);
132                    calls.pop();
133                    
134                    // env.removeBindings(formals);
135                    // System.err.println(name + " expanded as:\n" + PE);
136            }
137            
138            public AtomList getAtoms(){
139                    AtomList r;
140                    if(PE != null){
141                            r = PE.getAtoms();
142                    }else{
143                            r = new AtomList();
144                    }
145                    // System.err.println(name + ".getAtoms => " + r);
146                    return r;
147            }
148            
149            public String getName(){
150                    return name;
151            }
152            
153            public String toString(){
154                    return "ProcessCall(" + name + ", " + originalActuals + ")";
155            }
156            
157            
158            // Implementation of the StateElement interface
159            
160            public boolean contains(StateElement a){
161                    return PE.getFirst().contains(a);
162            }
163            
164            public ProcessInstance getProcess(){
165                    return processInstance;
166            }
167            
168            public void setTest(ATerm test, Environment env) throws ToolBusException{
169                    PE.getFirst().setTest(test, env);
170            }
171            
172            public List<ATerm> getTests(){
173                    return new ArrayList<ATerm>(0);
174            }
175            
176            public boolean isEnabled(){
177                    return activated;
178            }
179            
180            public State gotoNextStateAndActivate(){
181                    if(!(activated || executing)){
182                            State follow = getFollow();
183                            follow.activate();
184                            return follow;
185                    }
186                    executing = true;
187                    return PE.getFirst().gotoNextStateAndActivate();
188            }
189            
190            public State gotoNextStateAndActivate(StateElement se){
191                    if(!(activated || executing)){
192                            State follow = getFollow();
193                            follow.activate();
194                            return follow;
195                    }
196                    executing = true;
197                    return PE.getFirst().gotoNextStateAndActivate(se);
198            }
199            
200            public void activate(){
201                    if(activated && executing) return;
202                    
203                    activated = true;
204                    PE.getFirst().activate();
205            }
206            
207            public boolean execute() throws ToolBusException{
208                    // System.err.println("ProcessCall.execute: [" + getProcess().getProcessName() + "]" + this);
209                    // System.err.println("activated = " + activated + "; executing = " + executing + "; first = " + PE.getFirst());
210                    if(isEnabled()){
211                            if(!executing){
212                                    if(PE.getFirst().size() == 0){
213                                            // System.err.println("case size = 0");
214                                            executing = true;
215                                            // System.err.println("ProcessCall [" + getProcess().getProcessName() + "] enter");
216                                            return true;
217                                    }
218                                    // System.err.println("case size != 0");
219                                    executing = PE.getFirst().execute();
220                                    // System.err.println("executing => " + executing);
221                                    // if(executing)System.err.println("ProcessCall [" + getProcess().getProcessName() + "] enter");
222                                    return executing;
223                            }
224                            // System.err.println("execute: moving on to: " + follows);
225                            // System.err.println("ProcessCall [" + getProcess().getProcessName() + "] leave");
226                            activated = executing = false;
227                            return true;
228                    }
229                    return false;
230            }
231            
232            public ProcessInstance[] debugExecute() throws ToolBusException{
233                    if(isEnabled()){
234                            if(!executing){
235                                    if(PE.getFirst().size() == 0){
236                                            executing = true;
237                                            return new ProcessInstance[0];
238                                    }
239                                    ExecutionResult er = PE.getFirst().debugExecute();
240                                    if(er != null){
241                                            executing = true;
242                                            return er.partners;
243                                    }
244                                    executing = false;
245                                    return null;
246                            }
247                            activated = executing = false;
248                            return new ProcessInstance[0];
249                    }
250                    return null;
251            }
252            
253            /**
254             * Returns the last, by this process call, executed state element.
255             * (This method is used for debugging only).
256             * @return The last, by this process call, executed state element; may be null if this process call isn't currently executing.
257             */
258            public StateElement getExecutedStateElement(){
259                    if(!executing) return new Tau(tbfactory, null); // Pretend nothing happened if the call was just completed.
260                    
261                    StateElement executedStateElement = PE.getFirst().getLastExecutedStateElement();
262                    while(executedStateElement instanceof ProcessCall){
263                            executedStateElement = ((ProcessCall) executedStateElement).getExecutedStateElement();
264                    }
265                    return executedStateElement;
266            }
267    }