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 }