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.TBTermVar;
016 import toolbus.atom.Tau;
017 import toolbus.environment.Environment;
018 import toolbus.exceptions.NoSuchProcessDefinitionException;
019 import toolbus.exceptions.ToolBusException;
020 import toolbus.exceptions.ToolBusExecutionException;
021 import toolbus.parsercup.PositionInformation;
022 import toolbus.process.debug.ExecutionResult;
023 import aterm.ATerm;
024 import aterm.ATermAppl;
025 import aterm.ATermList;
026
027 public class DynamicProcessCall extends ProcessExpression implements StateElement{
028 private String name;
029
030 private TBTermVar nameAsVar;
031
032 protected final ATermList originalActuals;
033 protected ATermList actuals;
034
035 private ATermList formals;
036
037 private Environment env;
038
039 private ProcessDefinition definition = null; // May remain null for dynamic calls to non-existing processes
040
041 protected ProcessExpression PE;
042
043 protected ProcessInstance processInstance;
044
045 private final State firstState;
046
047 private boolean executing = false;
048
049 private boolean activated = false;
050
051 private Stack<String> calls;
052
053 private ATerm test;
054 private Environment testEnv;
055
056 public DynamicProcessCall(String name, ATermList actuals, TBTermFactory tbfactory, PositionInformation posInfo){
057 super(tbfactory, posInfo);
058 this.name = name;
059 this.originalActuals = actuals;
060 this.actuals = actuals;
061
062 firstState = new State();
063 firstState.addElement(this);
064 }
065
066 protected ProcessExpression copy(){
067 return new DynamicProcessCall(name, actuals, tbfactory, getPosInfo());
068 }
069
070 protected void computeFirst(){
071 // System.err.println("ProcessCall.computeFirst: " + firstState);
072 setFirst(firstState);
073 }
074
075 protected void replaceFormals(Environment e) throws ToolBusException{
076 //System.err.println("ProcessCall.replaceFormals(" + name + "): " + env);
077 env = e.copy();
078
079 // env = e;
080 actuals = (ATermList) tbfactory.replaceFormals(originalActuals, env);
081 }
082
083 protected void compile(ProcessInstance P, Stack<String> calls, State follows) throws ToolBusException{
084 processInstance = P;
085 this.calls = calls;
086 setFollow(follows);
087 nameAsVar = tbfactory.mkVar(tbfactory.make(name), calls.peek(), tbfactory.StrType);
088
089 definition = null;
090 }
091
092 private void compileStaticOrDynamicCall() throws ToolBusException{
093 if(calls.contains(name)){
094 throw new ToolBusExecutionException("Recursive call of "+name, getPosInfo());
095 }
096
097 definition = processInstance.getToolBus().getProcessDefinition(name, originalActuals.getLength());
098
099 // System.err.println("name = " + name);
100 // System.err.println("definition = " + definition);
101
102 actuals = (ATermList) tbfactory.replaceFormals(originalActuals, env);
103 PE = definition.getProcessExpression(actuals);
104
105 // System.err.println("ProcessCall.compile(" + name + ", " + processInstance + "," + PE + ")");
106 formals = definition.getFormals();
107
108 env.introduceBindings(formals, actuals, true);
109 actuals = (ATermList) tbfactory.replaceFormals(actuals, env);
110
111 // System.err.println("ProcessCall.compile(" + name + "): " + env);
112 // System.err.println("actuals = " + actuals);
113 PE.computeFirst();
114 PE.replaceFormals(env);
115
116 calls.push(name);
117 PE.compile(processInstance, calls, firstState);
118 calls.pop();
119
120 PE.getFirst().setTest(test, testEnv);
121 // env.removeBindings(formals);
122 // System.err.println(name + " expanded as:\n" + PE);
123 }
124
125 private void initDynamicCall() throws ToolBusException{
126 ATermAppl dynprocessname = (ATermAppl) env.getValue(nameAsVar);
127 name = dynprocessname.getName();
128 compileStaticOrDynamicCall();
129 //System.err.println("Dynamic process name " + name + " => " + dynprocessname);
130 }
131
132 private void finishCall(){
133 activated = executing = false;
134 definition = null;
135 AtomList callElements = PE.getAtoms();
136 PE = null;
137 processInstance.deregisterCommunicationAtoms(callElements);
138 }
139
140 public AtomList getAtoms(){
141 AtomList r;
142 if(PE != null){
143 r = PE.getAtoms();
144 }else{
145 r = new AtomList();
146 }
147 // System.err.println(name + ".getAtoms => " + r);
148 return r;
149 }
150
151 public String getName(){
152 return name;
153 }
154
155 public String toString(){
156 return "DynamicProcessCall(" + name + ", " + originalActuals + ")";
157 }
158
159
160 // Implementation of the StateElement interface
161
162 public boolean contains(StateElement a){
163 // if(!isStaticCall){ System.err.println(name + ": contains " + a); }
164
165 return ((definition != null) && activated) ? PE.getFirst().contains(a) : false;
166 }
167
168 public ProcessInstance getProcess(){
169 return processInstance;
170 }
171
172 public void setTest(ATerm test, Environment env) throws ToolBusException{
173 this.test = test;
174 this.testEnv = env;
175 }
176
177 public List<ATerm> getTests(){
178 List<ATerm> testExpressions = new ArrayList<ATerm>(1);
179 if(test != null) testExpressions.add(test);
180 return testExpressions;
181 }
182
183 public boolean isEnabled(){
184 return (activated && definition != null);
185 }
186
187 public State gotoNextStateAndActivate(){
188 if(!(activated || executing)){
189 State follow = getFollow();
190 follow.activate();
191 return follow;
192 }
193 executing = true;
194 return PE.getFirst().gotoNextStateAndActivate();
195 }
196
197 public State gotoNextStateAndActivate(StateElement se){
198 if(!(activated || executing)){
199 State follow = getFollow();
200 follow.activate();
201 return follow;
202 }
203 executing = true;
204 return PE.getFirst().gotoNextStateAndActivate(se);
205 }
206
207 public void activate(){
208 if(activated && executing) return;
209
210 try{
211 initDynamicCall();
212 }catch(NoSuchProcessDefinitionException nspdex){
213 // Ignore this and emulate Delta.
214 activated = false;
215 return;
216 }catch(ToolBusException e){
217 // e.printStackTrace();
218 activated = false;
219 return;
220 }
221
222 activated = true;
223 PE.getFirst().activate();
224 }
225
226 public boolean execute() throws ToolBusException{
227 if(isEnabled()){
228 if(!executing){
229 if(PE.getFirst().size() == 0){
230 // System.err.println("case size = 0");
231 executing = true;
232 return true;
233 }
234 executing = PE.getFirst().execute();
235 return executing;
236 }
237 finishCall();
238 return true;
239 }
240 return false;
241 }
242
243 public ProcessInstance[] debugExecute() throws ToolBusException{
244 if(isEnabled()){
245 if(!executing){
246 if(PE.getFirst().size() == 0){
247 executing = true;
248 return new ProcessInstance[0];
249 }
250 ExecutionResult er = PE.getFirst().debugExecute();
251 if(er != null){
252 executing = true;
253 return er.partners;
254 }
255 executing = false;
256 return null;
257 }
258 finishCall();
259 return new ProcessInstance[0];
260 }
261 return null;
262 }
263
264 /**
265 * Returns the last, by this process call, executed state element.
266 * (This method is used for debugging only).
267 * @return The last, by this process call, executed state element; may be null if this process call isn't currently executing.
268 */
269 public StateElement getExecutedStateElement(){
270 if(!executing) return new Tau(tbfactory, null); // Pretend nothing happened if the call was just completed.
271
272 StateElement executedStateElement = PE.getFirst().getLastExecutedStateElement();
273 while(executedStateElement instanceof ProcessCall){
274 executedStateElement = ((ProcessCall) executedStateElement).getExecutedStateElement();
275 }
276 return executedStateElement;
277 }
278 }