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 }