001 /** 002 * @author paulk, Jul 19, 2002 003 */ 004 005 package toolbus.environment; 006 007 import java.util.List; 008 009 import toolbus.Functions; 010 import toolbus.TBTermFactory; 011 import toolbus.TBTermVar; 012 import toolbus.exceptions.ToolBusError; 013 import toolbus.exceptions.ToolBusException; 014 import toolbus.exceptions.ToolBusInternalError; 015 import aterm.ATerm; 016 import aterm.ATermAppl; 017 import aterm.ATermList; 018 019 /** 020 * Environments maintain a relation between variables and their values. 021 */ 022 public class Environment{ 023 private final TBTermFactory tbfactory; 024 private Bindings bindings; 025 026 public Environment(TBTermFactory tbfactory){ 027 bindings = new ListBindings(); 028 this.tbfactory = tbfactory; 029 } 030 031 public Environment copy(){ 032 Environment env = new Environment(tbfactory); 033 env.bindings = bindings.clone(); 034 035 return env; 036 } 037 038 public TBTermFactory getTBTermFactory(){ 039 return tbfactory; 040 } 041 042 public int size(){ 043 return bindings.size(); 044 } 045 046 /** 047 * introduceVars adds a list of variables to the environment. They are initialized to Undefined. 048 * 049 * @param vs 050 * list of variables. 051 */ 052 public void introduceVars(ATermList vs) throws ToolBusInternalError{ 053 ATermList vars = vs; 054 055 // System.err.println(this.hashCode() + " introduceVars: " + vars); 056 while(!vars.isEmpty()){ 057 ATerm t = vars.getFirst(); 058 if(tbfactory.isVar(t)){ 059 TBTermVar var = (TBTermVar) t; 060 bindings.put(var.getVarName(), new Binding(var, tbfactory.Undefined)); 061 }else{ 062 throw new ToolBusInternalError("introduceVar illegal var: " + t); 063 } 064 065 vars = vars.getNext(); 066 } 067 // System.err.println(this.hashCode() + " introduceVars yields:" + this); 068 } 069 070 /** 071 * introduceBinding adds a new variable for the case of formal/actual correspondence in process 072 * calls. Special care is taken for result variables. 073 * 074 * @param formalVar 075 * A formal parameter. 076 * @param actual 077 * An actual value. 078 * @param isFormal 079 * Indicate if the variable is a formal. 080 */ 081 public void introduceBinding(TBTermVar formalVar, ATerm actual, boolean isFormal) throws ToolBusException{ 082 // System.err.println(this.hashCode() + " introduceBinding: " + formalVar + ", " + actual); 083 ATerm a = tbfactory.replaceFormals(actual, this); 084 // System.err.println("actual: " + actual); 085 if(tbfactory.isAnyVar(a)){ 086 TBTermVar actualVar = (TBTermVar) a; 087 if(!Functions.compatibleTypes(formalVar.getVarType(), actualVar.getVarType())){ 088 throw new ToolBusError("incompatible types for " + formalVar + " and " + actualVar + " in " + this); 089 } 090 } 091 if(formalVar.isResultVar() && !tbfactory.isResultVar(a)) throw new ToolBusInternalError("actual: " + a + " should be a result variable"); 092 093 bindings.put(formalVar.getVarName(), new Binding(formalVar, a, isFormal)); 094 // System.err.println("introduceBinding => " + this); 095 } 096 097 public void introduceBinding(TBTermVar formalVar, ATerm actual) throws ToolBusException{ 098 introduceBinding(formalVar, actual, false); 099 } 100 101 /** 102 * introduceBindings adds new (formal.actual) bindings 103 * 104 * @param formals 105 * list of formal parameters. 106 * @param actual 107 * list of actual parameters. 108 * @param isFormal 109 * Indicate if the variables are formals. 110 */ 111 public void introduceBindings(ATermList formals, ATermList actual, boolean isFormal) throws ToolBusException{ 112 ATermList f = formals; 113 ATermList a = actual; 114 115 if(f.getLength() != a.getLength()){ 116 throw new ToolBusInternalError("formal/actuals list have unequal length: " + f + " and " + a); 117 } 118 for(; !f.isEmpty(); f = f.getNext(), a = a.getNext()){ 119 ATerm first = f.getFirst(); 120 if(!tbfactory.isAnyVar(first)){ 121 throw new ToolBusInternalError("illegal formal: " + first); 122 } 123 introduceBinding((TBTermVar) first, a.getFirst(), isFormal); 124 } 125 } 126 127 /** 128 * removeBindings deletes variables introduced by introduceVars and introduceBindings. 129 * 130 * @param formals 131 * variables to be removed. 132 */ 133 public void removeBindings(ATermList formals){ 134 ATermList f = formals; 135 // System.err.println(this.hashCode() + "/" + bindings.hashCode() + " removeBindings: " + 136 // formals); 137 for(; !f.isEmpty(); f = f.getNext()){ 138 ATerm first = f.getFirst(); 139 if(!tbfactory.isAnyVar(first)){ 140 throw new ToolBusInternalError("illegal formal: " + first); 141 } 142 TBTermVar formalVar = (TBTermVar) first; 143 bindings.remove(formalVar.getVarName()); 144 } 145 // System.err.println(this.hashCode() + "/" + bindings.hashCode() + " removeBindings yields: 146 // " + this); 147 } 148 149 /** 150 * assignVar assigns a value to a variable. 151 * 152 * @param v 153 * variable 154 * @param val 155 * value to be assigned to variable 156 */ 157 public void assignVar(TBTermVar v, ATerm val){ 158 TBTermVar var = v; 159 160 // System.err.println("assignVar(" + var + ", " + val + ")"); 161 while(true){ 162 String name = var.getVarName(); 163 Binding b = bindings.get(name); 164 if(b == null){ 165 bindings.put(name, new Binding(var, val)); 166 return; 167 } 168 String bname = b.var.getVarName(); 169 if(name.equals(bname)){ 170 // System.err.println(name + " equals " + bname); 171 if(b.isFormal() && b.var.isResultVar()){ 172 var = (TBTermVar) b.val; // TODO checkit 173 }else{ 174 b.val = val; 175 b.setFormal(false); 176 return; 177 } 178 } 179 } 180 } 181 182 public ATerm getVarType(TBTermVar var) throws ToolBusError{ 183 // System.err.println("getVarType(" + var + ");" + this); 184 String name = var.getVarName(); 185 Binding b = bindings.get(name); 186 187 ATerm res; 188 if(b == null){ 189 // System.err.println("getVarType (b == null) => " + var.getVarType()); 190 res = var.getVarType(); 191 }else if(b.var.getVarName().equals(name)){ 192 // System.err.println("getVarType (equals) => " + b.var.getVarType()); 193 res = b.var.getVarType(); 194 }else{ 195 // System.err.println("getVarType => " + var.getVarType()); 196 res = var.getVarType(); 197 } 198 199 if((res.getType() == ATerm.APPL) && ((ATermAppl) res).getName() == "none"){ 200 throw new ToolBusError("Undeclared variable " + var.getExternalVarName()); 201 } 202 return res; 203 } 204 205 /** 206 * getValue fetches the value of a variable. 207 * 208 * @param var 209 * variable whole value is needed. 210 */ 211 public Binding getBinding(TBTermVar var){ 212 // System.err.println("getBinding(" + var + " in " + this + ")"); 213 String name = var.getVarName(); 214 return bindings.get(name); 215 } 216 217 public List<Binding> getBindingsAsList(){ 218 return bindings.getBindingsAsList(); 219 } 220 221 public boolean isDeclaredAsStringVar(TBTermVar var){ 222 String name = var.getVarName(); 223 Binding b = bindings.get(name); 224 // System.err.println("isDeclaredAsStringVar: " + var + "; " + b + "; " + this); 225 if(b == null){ 226 return false; 227 } 228 return (b.var.getVarType() == tbfactory.StrType); 229 } 230 231 /** 232 * getValue fetches the value of a variable. 233 * 234 * @param v 235 * variable whose value is needed. 236 */ 237 public ATerm getValue(TBTermVar v){ 238 TBTermVar var = v; 239 // System.err.println(this.hashCode() + " getValue(" + var + " in " + this + ")"); 240 241 while(true){ 242 String name = var.getVarName(); 243 Binding b = bindings.get(name); 244 if(b == null){ 245 throw new RuntimeException("variable " + var.getExternalVarName() + " has undefined value"); 246 } 247 if(b.isFormal() && (tbfactory.isAnyVar(b.val))){ 248 var = (TBTermVar) b.val; 249 }else{ 250 return b.val; 251 } 252 } 253 } 254 255 public void setAssignable(TBTermVar var){ 256 Binding b = getBinding(var); 257 if(b != null){ 258 b.setAssignable(true); 259 }else{ 260 throw new ToolBusInternalError("setAssignable: variable " + var.getExternalVarName() + " does not exist!"); 261 } 262 } 263 264 public ATerm replaceFormal(TBTermVar v) throws ToolBusException{ 265 TBTermVar var = v; 266 267 // System.err.println("replaceFormal(" + v + "); " + this); 268 var = var.setVarType(getVarType(var)); 269 Binding b = getBinding(var); 270 // System.err.println(b); 271 if(b == null || b.val == tbfactory.Undefined){ 272 return var; 273 /* throw new ToolBusError("Undeclared variable " + v.getExternalVarName()); */ 274 } 275 if(!b.isFormal()){ 276 // System.err.println("local var:. replaceFormals(" + v + ") => " + v); 277 return var; 278 } 279 280 if(b.isAssignable() || tbfactory.isResultVar(b.val)){ 281 // System.err.println("2. replaceFormal(" + v + ") => " + v); 282 return var; 283 } 284 if(tbfactory.isVar(b.val)){ // TODO: OK? 285 ATerm tmp = tbfactory.replaceFormals(b.val, this); 286 // System.err.println("3. replaceFormal(" + v + ") => " + tmp); 287 return tmp; 288 }else if(tbfactory.isResultVar(b.val)){ // TODO: OK? 289 ATerm tmp = tbfactory.replaceFormals(b.val, this); 290 // System.err.println("3. replaceFormal(" + v + ") => " + tmp); 291 return tmp; 292 }else{ 293 // System.err.println("4. replaceFormal(" + v + ") => " + b.val); 294 return b.val; 295 } 296 297 // System.err.println("5. replaceFormal(" + v + ") => " + v); 298 /* return v; */ 299 } 300 301 public String toString(){ 302 return this.hashCode() + ":" + bindings.toString(); 303 } 304 }