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 }