package ecologylab.collections; import java.util.HashMap; import java.util.Map; import ecologylab.generic.Debug; /** * A lexical Scope of bindings from names to values. Lexical Scopes can be nested. However, bind * operations are only performed on the current Scope. Lookup operations chain through parents, as * necessary, when a binding is not found locally. */ public class Scope<T> extends HashMap<String, T> { protected Map<String, T> parent; /** * Create a Scope with no parent, using default HashMap size and loadFactor. */ public Scope() { } /** * Create a lexical Scope, chained to a parent Scope for resolving lookup/get. Use the default * HashMap size and loadFactor. * * @param parent */ public Scope(Map<String, T> parent) { this.parent = parent; } /** * Create a Scope with no parent, using the specified HashMap size and default loadFactor. * * @param size */ public Scope(int size) { super(size); } /** * Create a lexical Scope, chained to a parent Scope for resolving lookup/get. Use the specified * HashMap size and default loadFactor. * * @param size */ public Scope(Map<String, T> parent, int size) { super(size); this.parent = parent; } /** * Create a Scope with no parent, using the specified HashMap size and loadFactor. * * @param size * @param loadFactor */ public Scope(int size, float loadFactor) { super(size, loadFactor); } /** * Create a lexical Scope, chained to a parent Scope for resolving lookup/get. Use the specified * HashMap size and loadFactor. * * @param parent * @param size * @param loadFactor */ public Scope(Map<String, T> parent, int size, float loadFactor) { super(size, loadFactor); this.parent = parent; } /** * Lookup an object in this. * * @param name * * @return The object associated with this name, found in the registry, or null if there is none. */ @Override public T get(Object name) { T result = super.get(name); Map<String, T> operativeParent = parent; return (result != null) ? result : ((operativeParent != null) ? operativeParent.get(name) : null); } /** * Enable this Scope to inherit bindings from a parent, by setting the parent instance variable in * this. * * @param newParent */ public void setParent(Map<String, T> newParent) { Map<String, T> thisParent = this.parent; if (thisParent != null) Debug.warning(this, "Setting parent to " + newParent + " but it was already " + thisParent); this.parent = newParent; } /** * The chained parent Map used for resolving lookup/get operations, if they cannot be resolved in * this. * * @return The parent instance variable in this. */ public Map<String, T> operativeParent() { return this.parent; } @Override public String toString() { String parentMsg = (parent == null) ? "" : "\n\t -> " + parent.toString(); return sizeMsg() + parentMsg; } public String sizeMsg() { return "[Scope] w " + size() + " elements. "; } /** * * @return A String with all the name value pairs in this, for debugging. */ public String dump() { StringBuilder result = new StringBuilder(); result.append("DUMP"); dump(result, "\t"); return result.toString(); } private void dump(StringBuilder result, String prefix) { result.append('\n').append(prefix).append(sizeMsg()); dumpThis(result, prefix); if (parent != null) ((Scope) parent).dump(result, prefix + "\t"); } public void dumpThis(StringBuilder result, String prefix) { for (String key : this.keySet()) { result.append(prefix).append(key).append("\t: ").append(get(key)).append('\n'); } } private static final long serialVersionUID = 5840169416933494011L; }