* implementing the absolute minimal amount of functionality for an
* Object which can be manipulated by JavaScript code.
*/
-public abstract class JS {
+public class JS {
// Public Helper Methods //////////////////////////////////////////////////////////////////////
// Instance Methods ////////////////////////////////////////////////////////////////////
- public abstract Object get(Object key) throws JS.Exn;
- public void put(Object key, Object val) throws JS.Exn { throw new JS.Exn("you cannot put to this object"); }
+ // this gets around a wierd fluke in the Java type checking rules for ?..:
+ public static final Object T = Boolean.TRUE;
+ public static final Object F = Boolean.FALSE;
+
+ // FEATURE: be smart here; perhaps intern
+ public static final Number N(int i) { return new Integer(i); }
+ public static final Number N(long l) { return new Long(l); }
+ public static final Number N(double d) { return new Double(d); }
+ public static final Boolean B(boolean b) { return b ? Boolean.TRUE : Boolean.FALSE; }
+
+ private static Enumeration emptyEnumeration = new Enumeration() {
+ public boolean hasMoreElements() { return false; }
+ public Object nextElement() { throw new NoSuchElementException(); }
+ };
+
+ private Hash entries = null;
+ public Enumeration keys() { return entries == null ? emptyEnumeration : entries.keys(); }
+ public Object get(Object key) { return entries == null ? null : entries.get(key, null); }
+ public void put(Object key, Object val) { if (entries == null) entries = new Hash(); entries.put(key, null, val); }
- public Enumeration keys() { throw new Error("you cannot apply for..in to a " + this.getClass().getName()); }
+ // note that we don't actually implement trappable... we just provide these for subclasses which choose to
+ public JSTrap getTrap(Object key) { return entries == null ? null : (JSTrap)entries.get(key, JSTrap.class); }
+ public void putTrap(Object key, JSTrap t) { if (entries == null) entries = new Hash(); entries.put(key, JSTrap.class, t); }
public Number coerceToNumber() { throw new JS.Exn("tried to coerce a JavaScript object to a Number"); }
public String coerceToString() { throw new JS.Exn("tried to coerce a JavaScript object to a String"); }
}
/** the result of a graft */
+ // FIXME: uber-broken
public static class Graft extends JSCallable {
private JS graftee;
private Object replaced_key;
public int hashCode() { return graftee.hashCode(); }
public Object get(Object key) { return replaced_key.equals(key) ? replaced_val : graftee.get(key); }
public void put(Object key, Object val) { graftee.put(key, val); }
+ /*
public Object call(Object method, JSArray args) {
if (replaced_key.equals(method)) return ((JSCallable)replaced_val).call(null, args);
else if (graftee instanceof JSCallable) return ((JSCallable)graftee).call(method, args);
else throw new JS.Exn("cannot call this value");
}
+ */
public Number coerceToNumber() { return graftee.coerceToNumber(); }
public String coerceToString() { return graftee.coerceToString(); }
public boolean coerceToBoolean() { return graftee.coerceToBoolean(); }