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 }