-public class JS /*extends org.ibex.util.BalancedTree*/ implements Serializable {
-
- public static final long serialVersionUID = 572634985343962922L;
- public static boolean checkAssertions = false;
-
- public static final Object METHOD = new Object();
- public final JS unclone() { return _unclone(); }
- public Enumeration keys() throws JSExn { return entries == null ? emptyEnumeration : entries.keys(); }
- public Object get(Object key) throws JSExn { return entries == null ? null : entries.get(key, null); }
- public void put(Object key, Object val) throws JSExn { (entries==null?entries=new Hash():entries).put(key,null,val); }
- public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
- throw new JSExn("attempted to call the null value (method "+method+")");
- }
- public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
- throw new JSExn("you cannot call this object (class=" + this.getClass().getName() +")");
- }
-
- JS _unclone() { return this; }
- public static class Cloneable extends JS {
- public Object jsclone() throws JSExn {
- return new Clone(this);
+public interface JS {
+
+ /** Returns an enumeration of the keys in this object. */
+ public JS.Enumeration keys() throws JSExn;
+
+ /** Return the value associated with the given key. */
+ public JS get(JS key) throws JSExn;
+
+ /** Store a specific value against the given key. */
+ public void put(JS key, JS value) throws JSExn;
+
+ /** Calls a specific method with given arguments on this object.
+ * An exception is thrown if there is no such method or the
+ * arguments are invalid. */
+ public JS call(JS method, JS[] args) throws JSExn;
+
+ /** Returns the names of the formal arguments, if any.
+ * This function must never return a null object. */
+ public String[] getFormalArgs();
+
+ /** Put a value to the given key, calling any write traps that have
+ * been placed on the key.
+ *
+ * This function may block for an indeterminate amount of time.
+ *
+ * Write traps may change the final value before it is put, thus
+ * be careful to read the latest value from this function's return
+ * before doing any more work with it.
+ */
+ public JS putAndTriggerTraps(JS key, JS value) throws JSExn;
+
+ /** Gets the value for a given key, calling any read traps that have
+ * been placed on the key.
+ *
+ * This function may block for an indeterminate amount of time.
+ */
+ public JS getAndTriggerTraps(JS key) throws JSExn;
+
+ /** Calls the write traps placed on a given key with the given value
+ * and returns the result without saving it to this object's key store. */
+ public JS justTriggerTraps(JS key, JS value) throws JSExn;
+
+ public void addTrap(JS key, JS function) throws JSExn;
+ public void delTrap(JS key, JS function) throws JSExn;
+ public Trap getTrap(JS key) throws JSExn;
+
+ // FIXME: consider renaming/removing these
+ public JS unclone();
+ public String coerceToString() throws JSExn;
+
+
+ // Implementations ////////////////////////////////////////////////////////
+
+ /** Provides the lightest possible implementation of JS, throwing
+ * exceptions on every mutable operation. */
+ public static class Immutable implements JS {
+ private static final String[] emptystr = new String[0];
+
+ public JS unclone() { return this; }
+ public JS.Enumeration keys() throws JSExn {
+ throw new JSExn("object has no key set, class ["+ getClass().getName() +"]"); }
+ public JS get(JS key) throws JSExn { return null; }
+ public void put(JS key, JS val) throws JSExn {
+ throw new JSExn("'" + key + "' is read only on class ["+ getClass().getName() +"]"); }
+
+ public JS call(JS method, JS[] args) throws JSExn {
+ if (method == null) throw new JSExn( "object cannot be called, class ["+ getClass().getName() +"]");
+ throw new JSExn("method not found: " + JSU.str(method) + " class="+this.getClass().getName());