001: // Copyright (c) 1996-2000, 2001 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.mapping;
005:
006: /**
007: * An environment contains (name->value) bindings.
008: * Names are Strings that are compared by ==, not equal.
009: * @author Per Bothner
010: */
011:
012: public class Environment extends NameMap {
013: Binding[] table;
014: int log2Size;
015: private int mask;
016: int num_bindings;
017:
018: private static Environment global;
019:
020: Environment previous;
021:
022: boolean locked;
023:
024: protected TrivialConstraint trivialConstraint = new TrivialConstraint(
025: this );
026: protected UnboundConstraint unboundConstraint = new UnboundConstraint(
027: this );
028: protected ConstantConstraint constantConstraint;
029:
030: /** True if this environment is locked - bindings cannot be added or removed. */
031: public final boolean isLocked() {
032: return locked;
033: }
034:
035: public final void setLocked(boolean locked) {
036: this .locked = locked;
037: }
038:
039: public static Environment user() {
040: return current();
041: }
042:
043: public static Object lookup_global(String name)
044: throws UnboundSymbol {
045: Binding binding = user().lookup(name);
046: if (binding == null)
047: throw new UnboundSymbol(name);
048: return binding.get();
049: }
050:
051: /** Define name (interned) to have a given value. */
052: public static void define_global(String name, Object new_value) {
053: user().defineValue(name, new_value);
054: }
055:
056: public static void defineFunction(String name, Object new_value) {
057: defineFunction(user(), name, new_value);
058: }
059:
060: public static void defineFunction(Environment env, String name,
061: Object new_value) {
062: Binding binding = env.getBinding(name);
063: binding.constraint.setFunctionValue(binding, new_value);
064: }
065:
066: /** Define name (interned) to have a given value. */
067: public static void put_global(String name, Object new_value) {
068: user().put(name, new_value);
069: }
070:
071: /**
072: * @deprecated
073: */
074: public static Environment current() {
075: return getCurrent();
076: }
077:
078: public static Environment getCurrent() {
079: Thread thread = Thread.currentThread();
080: if (thread instanceof Future)
081: return ((Future) thread).environment;
082: return global;
083: }
084:
085: public static void setCurrent(Environment env) {
086: Thread thread = Thread.currentThread();
087: if (thread instanceof Future)
088: ((Future) thread).environment = env;
089: else
090: global = env;
091: }
092:
093: public Environment() {
094: this (64);
095: }
096:
097: public Environment(int capacity) {
098: log2Size = 4;
099: while (capacity > (1 << log2Size))
100: log2Size++;
101: capacity = 1 << log2Size;
102: table = new Binding[capacity];
103: mask = capacity - 1;
104: }
105:
106: public Environment(Environment previous) {
107: this ();
108: this .previous = previous;
109: }
110:
111: public Binding getBinding(String name) {
112: Binding binding = lookup(name);
113: if (binding != null)
114: return binding;
115: /* FIXME
116: int hash = System.identityHashCode(name);
117: int index = Binding.hashSearch(table, log2Size,mask, name, hash);
118: Binding binding = table[index];
119: if (binding != null && binding != Binding.hashDELETED)
120: return binding;
121: if (locked)
122: {
123: if (previous == null)
124: throw new UnboundSymbol(name);
125: return previous.getBinding(name);
126: }
127: */
128: binding = addBinding(name, null);
129: binding.constraint = unboundConstraint;
130: return binding;
131: }
132:
133: public static Binding getCurrentBinding(String name) {
134: return getCurrent().getBinding(name);
135: }
136:
137: /**
138: * Search for a variable binding by name.
139: * @param sym the (interned) name of the binding to search for
140: * @return the value of the binding, or null if not found
141: */
142:
143: public Binding lookup(String name) {
144: return lookup(name, System.identityHashCode(name));
145: }
146:
147: private Binding lookup(String name, int hash) {
148: for (Environment env = this ; env != null; env = env.previous) {
149: int index = Binding.hashSearch(env.table, env.log2Size,
150: env.mask, name, hash);
151: Binding element = env.table[index];
152: if (element != null && element != Binding.hashDELETED)
153: return element;
154: }
155: return null;
156: }
157:
158: /**
159: * Define the value binding for a symbol.
160: */
161: public Binding defineValue(String name, Object value) {
162: Binding binding = getBinding(name);
163: binding.constraint = trivialConstraint;
164: binding.value = value;
165: return binding;
166: }
167:
168: /**
169: * Define the value or function binding for a symbol, as appropriate
170: */
171: public Binding define(String name, Object value) {
172: return defineValue(name, value);
173: }
174:
175: public void addBinding(Binding binding) {
176: // Rehash if over 2/3 full.
177: if (3 * num_bindings >= 2 * table.length)
178: rehash();
179: if (Binding.hashSet(table, log2Size, binding) == null)
180: num_bindings++;
181: }
182:
183: public Binding addBinding(String name, Object value) {
184: Binding binding = new Binding(name);
185: binding.constraint = trivialConstraint;
186: binding.value = value;
187: addBinding(binding);
188: return binding;
189: }
190:
191: void rehash() {
192: int new_capacity = 2 * table.length;
193: Binding[] new_table = new Binding[new_capacity];
194:
195: Binding.hashInsertAll(new_table, log2Size + 1, table, log2Size);
196: table = new_table;
197: log2Size++;
198: mask = (mask << 1) | 1;
199: }
200:
201: public Object remove(String name) {
202: Environment env = this ;
203: for (;; env = env.previous) {
204: if (env == null)
205: return null;
206: if (locked)
207: throw new IllegalStateException(
208: "attempt to remove variable: " + name
209: + " locked environment");
210: Binding[] env_tab = env.table;
211: Named old = Binding.hashDelete(env.table, env.log2Size,
212: name);
213: if (old != null)
214: return old;
215: }
216: }
217:
218: public Object remove(Object name) {
219: return remove((String) name);
220: }
221:
222: public void remove(Binding binding) {
223: String name = binding.getName();
224: if (locked)
225: throw new IllegalStateException(
226: "attempt to remove variable: " + name
227: + " locked environment");
228: Binding.hashDelete(table, log2Size, name);
229: }
230:
231: public final boolean isBound(String name) {
232: return get(name, Binding.UNBOUND) != Binding.UNBOUND;
233: }
234:
235: public Object get(String name, Object defaultValue) {
236: Binding binding = lookup(name);
237: if (binding == null)
238: return defaultValue;
239: return binding.get(defaultValue);
240: }
241:
242: /** Get the function binding for a symbol.
243: * If this Environment is a single-namespace language (such as Scheme).
244: * this is equivalent to getChecked.
245: * @exception gnu.mapping.UnboundSymbol the name has no function binding
246: */
247: public Object getFunction(String name) {
248: return getChecked(name);
249: }
250:
251: public Object put(/* interned */String name, Object value) {
252: Binding binding = lookup(name);
253: if (binding == null) {
254: define(name, value);
255: return null;
256: } else if (!binding.isBound()) {
257: binding.set(value);
258: return null;
259: } else {
260: Object old_value = binding.get();
261: binding.set(value);
262: return old_value;
263: }
264: }
265:
266: public Object put(Object name, Object value) {
267: return put((String) name, value);
268: }
269:
270: /** Set the function binding for a symbol.
271: * If this Environment is a single-namespace language (such as Scheme).
272: * this is equivalent to put.
273: */
274: public void putFunction(String name, Object value) {
275: put(name, value);
276: }
277:
278: /** Does not enumerate inherited Bindings. */
279: public BindingEnumeration enumerateBindings() {
280: return new BindingEnumeration(table, 1 << log2Size);
281: }
282:
283: /** Does enumerate inherited Bindings. */
284: public BindingEnumeration enumerateAllBindings() {
285: return new BindingEnumeration(this );
286: }
287:
288: public String toString() {
289: String name = getName();
290: if (name == null)
291: name = super .toString();
292: return "#<environment " + name + '>';
293: }
294:
295: /**
296: * Evaluate an expression in this Environment.
297: */
298: /*
299: final public Object
300: eval (Expression expr)
301: {
302: return expr.eval (this);
303: }
304: */
305: }
|