001 /** 002 * @author paulk 003 */ 004 005 package toolbus.atom; 006 007 import java.util.ArrayList; 008 import java.util.Iterator; 009 import java.util.List; 010 import java.util.Stack; 011 import toolbus.AtomList; 012 import toolbus.Functions; 013 import toolbus.State; 014 import toolbus.StateElement; 015 import toolbus.TBTermFactory; 016 import toolbus.ToolBus; 017 import toolbus.environment.Environment; 018 import toolbus.exceptions.ToolBusException; 019 import toolbus.parsercup.PositionInformation; 020 import toolbus.process.ProcessExpression; 021 import toolbus.process.ProcessInstance; 022 import aterm.AFun; 023 import aterm.ATerm; 024 import aterm.ATermAppl; 025 import aterm.ATermInt; 026 import aterm.ATermList; 027 028 /** 029 * The class Atom forms the basic building block of Tscripts. Instances of Atom 030 * are both the most primitive elements of process expressions and the elements of 031 * the states to which process exprssions are being compiled. 032 * 033 */ 034 035 abstract public class Atom extends ProcessExpression implements StateElement{ 036 private final static String SECS = "sec"; 037 private final static String MSECS = "msec"; 038 039 private final static Ref[] NOATOMARGS = new Ref[0]; 040 041 private ProcessInstance processInstance; // process instance to which the atom belongs 042 private Environment env; // the environment of this atom 043 private List<Test> tests; // optional tests that guard this atom 044 private Ref[] atomArgs = NOATOMARGS; // arguments of the atom 045 private int delay = 0; // time delay before atom can be executed 046 private int timeout = 0; // timeout after which atom can no longer be executed 047 private boolean timeExpr = false; // the actual time expression for delay/timeout 048 private long activateTime; // when this atom was activated 049 private long enabledTime; // When this atom becomes ready for execution 050 private long timeoutTime; // When this atom becomes no longer eligable for execution 051 protected String externalNameAsReceivedByTool; 052 053 public Atom(TBTermFactory tbfactory, PositionInformation posInfo){ 054 super(tbfactory, posInfo); 055 addToFirst(this); 056 externalNameAsReceivedByTool = shortName(); 057 } 058 059 public void destroy(){/* Intended to (optionally) be overwritten in subclasses to enable them to execute cleanup actions if needed. */} 060 061 public void setAtomArgs(Ref[] refs){ 062 atomArgs = refs; 063 } 064 065 public ATerm getAtomArgValue(int i){ 066 return atomArgs[i].value; 067 } 068 069 public void copyAtomAttributes(Atom a){ 070 delay = a.delay; 071 timeout = a.timeout; 072 timeExpr = a.timeExpr; 073 } 074 075 protected void setEnv(Environment env){ 076 this.env = env; 077 } 078 079 public Environment getEnv(){ 080 return env; 081 } 082 083 public void setTest(ATerm test, Environment e) throws ToolBusException{ 084 if(test != null){ 085 //System.err.println(this + "." + "setTest: env " + env.hashCode() + " => " + e.hashCode()); 086 if(tests == null) tests = new ArrayList<Test>(4); 087 Test t = new Test(test, e); 088 //System.out.println("setTest: " + t); 089 this.tests.add(t); 090 } 091 } 092 093 public List<ATerm> getTests(){ 094 if(tests != null){ 095 List<ATerm> testExpressions = new ArrayList<ATerm>(tests.size()); 096 Iterator<Test> testsIterator = tests.iterator(); 097 while(testsIterator.hasNext()){ 098 testExpressions.add(testsIterator.next().testExpr); 099 } 100 return testExpressions; 101 } 102 return new ArrayList<ATerm>(0); 103 } 104 105 public void setDelay(ATerm delay){ 106 if(delay instanceof ATermAppl){ 107 ATermAppl timeExpression = (ATermAppl) delay; 108 AFun timeFun = timeExpression.getAFun(); 109 if(timeFun.getArity() == 1){ 110 String order = timeFun.getName(); 111 ATerm argument = timeExpression.getArgument(0); 112 if(argument instanceof ATermInt){ 113 ATermInt time = (ATermInt) argument; 114 if(order == SECS){ 115 this.delay = time.getInt() * 1000; 116 timeExpr = true; 117 return; 118 }else if(order == MSECS){ 119 this.delay = time.getInt(); 120 timeExpr = true; 121 return; 122 } 123 } 124 } 125 } 126 // If the function didn't return before this point the argument wasn't formatted properly. 127 throw new RuntimeException("Not a time expression: "+delay); 128 } 129 130 public void setAbsoluteDelay(ATermList delay){ 131 // TODO Implement as soon as we know how to do it properly. 132 throw new UnsupportedOperationException("Absolute delays are currently unsupported."); 133 } 134 135 public int getDelay(){ 136 return delay; 137 } 138 139 public void setTimeout(ATerm timeout){ 140 if(timeout instanceof ATermAppl){ 141 ATermAppl timeExpression = (ATermAppl) timeout; 142 AFun timeFun = timeExpression.getAFun(); 143 if(timeFun.getArity() == 1){ 144 String order = timeFun.getName(); 145 ATerm argument = timeExpression.getArgument(0); 146 if(argument instanceof ATermInt){ 147 ATermInt time = (ATermInt) argument; 148 if(order == SECS){ 149 this.timeout = time.getInt() * 1000; 150 timeExpr = true; 151 return; 152 }else if(order == MSECS){ 153 this.timeout = time.getInt(); 154 timeExpr = true; 155 return; 156 } 157 } 158 } 159 } 160 // If the function didn't return before this point the argument wasn't formatted properly. 161 throw new RuntimeException("Not a time expression: "+delay); 162 } 163 164 public void setAbsoluteTimeout(ATermList timeout){ 165 // TODO Implement as soon as we know how to do it properly. 166 throw new UnsupportedOperationException("Absolute timeouts are currently unsupported."); 167 } 168 169 public int getTimeout(){ 170 return timeout; 171 } 172 173 public ToolBus getToolBus(){ 174 return processInstance.getToolBus(); 175 } 176 177 public AtomList getAtoms(){ 178 return new AtomList(this); 179 } 180 181 private String shortName(){ 182 return getClass().getSimpleName(); 183 } 184 185 public String toString(){ 186 /*String pidStr = (processInstance != null) ? "[" + processInstance.getProcessName() + "/" + processInstance.getProcessId() + "]" : ""; 187 String args = "("; 188 String sep = ""; 189 190 for(int i = 0; i < atomArgs.length; i++){ 191 args = args + sep + atomArgs[i]; 192 //args = args + sep + tbfactory.substitute(atomArgs[i].value, env); 193 sep = ", "; 194 } 195 args = args + ")"; 196 String strtest = (tests == null) ? "" : " if " + tests;*/ 197 if(atomArgs.length > 0){ 198 StringBuilder sb = new StringBuilder(); 199 sb.append(shortName()); 200 sb.append('('); 201 sb.append(atomArgs[0].value); 202 int nrOfAtomArgs = atomArgs.length; 203 for(int i = 1; i < nrOfAtomArgs; i++){ 204 sb.append(','); 205 sb.append(atomArgs[i].value); 206 } 207 sb.append(')'); 208 return sb.toString(); 209 } 210 return shortName()/* + pidStr + args + strtest*/; 211 } 212 213 public ATermAppl toATerm(){ 214 int nargs = atomArgs.length; 215 // System.err.println("toATerm: " + externalNameAsReceivedByTool); 216 217 AFun afun = tbfactory.makeAFun(externalNameAsReceivedByTool, nargs, false); 218 ATerm pat[] = new ATerm[nargs]; 219 220 for(int i = 0; i < nargs; i++){ 221 pat[i] = tbfactory.makePattern(atomArgs[i].value); 222 } 223 return tbfactory.makeAppl(afun, pat); 224 } 225 226 public void computeFirst(){/* Overwritten in subclass */} 227 228 public void replaceFormals(Environment e) throws ToolBusException{ 229 this.env = e; 230 //System.err.println("Atom.replaceFormals: " + env); 231 for(int i = 0; i < atomArgs.length; i++){ 232 //System.err.println("atomArg[" + i + "] = " + atomArgs[i] + " ; env = " + env); 233 ATerm arg = tbfactory.replaceFormals(atomArgs[i].value, env); 234 //System.err.println("atomArg[" + i + "] = " + atomArgs[i].value + " => " + arg + "; env = " + env); 235 atomArgs[i].value = arg; 236 } 237 } 238 239 public void compile(ProcessInstance pi, Stack<String> calls, State follow) throws ToolBusException{ 240 this.processInstance = pi; 241 // System.err.println("Atom.compile, prev env = " + env); 242 // this.env = env.copy(); 243 setFollow(follow); 244 // System.err.println("Compiling " + this + ";\n env = " + this.env); 245 // replaceFormals(env); //TODO redundant? 246 } 247 248 // Implementation of the StateElement interface 249 250 public boolean isEnabled() throws ToolBusException{ 251 // System.err.println("Atom.isEnabled: " + this.getProcess().getProcessId() + ": " + this); 252 if(timeExpr){ 253 // System.err.println("Has a TimeExpr; delay = " + delay + "; timeout = " + timeout); 254 long currentTime = getToolBus().getRunTime(); 255 // System.err.println("startTime = " + startTime + "; currentTime = " + currentTime); 256 if(currentTime < enabledTime){ 257 getToolBus().setNextTime(enabledTime); 258 // System.err.println("currentTime < startTime + delay"); 259 /*incr(notEnabled);*/ 260 return false; 261 } 262 if(timeout != 0 && currentTime > timeoutTime){ 263 // System.err.println("currentTime > startTime + timeout"); 264 /*incr(notEnabled);*/ 265 return false; 266 } 267 } 268 if(tests != null){ 269 //System.err.println("Atom.isEnabled: " + this.getProcess().getProcessId() + ": " + this); 270 Iterator<Test> testIterator = tests.iterator(); 271 while(testIterator.hasNext()){ 272 Test t = testIterator.next(); 273 //System.err.print("evaluate: " + t); 274 boolean res = tbfactory.isTrue(Functions.eval(t.testExpr, processInstance, t.testEnv)); 275 //System.err.println(" ==> " + res); 276 if(!res){ 277 /*incr(notEnabled);*/ 278 return false; 279 } 280 } 281 } 282 /*incr(enabled);*/ 283 return true; 284 } 285 286 public boolean contains(StateElement b){ 287 return this == b; 288 } 289 290 public ProcessInstance getProcess(){ 291 return processInstance; 292 } 293 294 public State gotoNextStateAndActivate(){ 295 // System.err.println(this + "getNextState ==> " + getFollow()); 296 State s = getFollow(); 297 s.activate(); 298 return s; 299 } 300 301 public State gotoNextStateAndActivate(StateElement b){ 302 if(this.equals(b)){ 303 State s = getFollow(); 304 s.activate(); 305 return s; 306 } 307 System.err.println("Atom.getNextState2: wrong arg: " + b); // TODO exception 308 return null; 309 } 310 311 public void activate(){ 312 activateTime = getToolBus().getRunTime(); 313 enabledTime = activateTime + delay; 314 timeoutTime = activateTime + timeout; 315 316 // System.err.println("used_vars = " + collected); 317 // System.err.println("Atom.activate: " + this); 318 } 319 320 /** 321 * This class holds static reference to an empty process instance array, which can be used as 322 * return value in the debugExecute method. Using this instead of a newly created array every 323 * time will reduce garbage creation. 324 * 325 * @author Arnold Lankamp 326 */ 327 private static class EmptyProcessInstanceArrayHolder{ 328 public final static ProcessInstance[] ZEROPARTNERS = new ProcessInstance[0]; 329 } 330 331 public ProcessInstance[] debugExecute() throws ToolBusException{ 332 if(execute()) return EmptyProcessInstanceArrayHolder.ZEROPARTNERS; 333 334 return null; 335 } 336 337 /** 338 * This class represents a test associated with an atom. 339 * It carries its own execution environment. 340 */ 341 private static class Test{ 342 public final ATerm testExpr; 343 public final Environment testEnv; 344 345 public Test(ATerm test, Environment env){ 346 testExpr = test; 347 testEnv = env; 348 } 349 public String toString(){ 350 return "Test(" + testExpr + ", " + testEnv + ")"; 351 } 352 } 353 }