/** The minimum set of functionality required for objects which are manipulated by JavaScript */
public class JS extends org.xwt.util.BalancedTree {
- // Static Interpreter Control Methods ///////////////////////////////////////////////////////////////
+ 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() +")");
+ }
- /** log a message with the current JavaScript sourceName/line */
- public static void log(Object o, Object message) { log(message); }
- public static void log(Object message) { Log.echo(JS.getSourceName() + ":" + JS.getLine(), message); }
- public static void log(JSExn e) {
- Log.echo(e,"JS Exception: " + e.getObject() + "\n" + e.backtrace());
- Log.echo(e,e);
+ JS _unclone() { return this; }
+ public static class Cloneable extends JS {
+ public Cloneable() { }
+ public Object jsclone() throws JSExn {
+ throw new JSExn("cloning not yet implemented");
+ }
}
- public static int getLine() {
- Interpreter c = Interpreter.current();
- return c == null || c.f == null || c.pc < 0 || c.pc >= c.f.size ? -1 : c.f.line[c.pc];
+ public static class Clone extends JS.Cloneable {
+ protected JS.Cloneable clonee = null;
+ JS _unclone() { return clonee.unclone(); }
+ public JS.Cloneable getClonee() { return clonee; }
+ public Clone(JS.Cloneable clonee) { this.clonee = clonee; }
+ public boolean equals(Object o) {
+ if (!(o instanceof JS)) return false;
+ return unclone() == ((JS)o).unclone();
+ }
+ public Enumeration keys() throws JSExn { return clonee.keys(); }
+ public Object get(Object key) throws JSExn { return clonee.get(key); }
+ public void put(Object key, Object val) throws JSExn { clonee.put(key, val); }
+ public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
+ return clonee.callMethod(method, a0, a1, a2, rest, nargs);
+ }
+ public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
+ return clonee.call(a0, a1, a2, rest, nargs);
+ }
}
- public static String getSourceName() {
- Interpreter c = Interpreter.current();
- return c == null || c.f == null ? null : c.f.sourceName;
- }
+ // Static Interpreter Control Methods ///////////////////////////////////////////////////////////////
+
+ /** log a message with the current JavaScript sourceName/line */
+ public static void log(Object message) { info(message); }
+ public static void debug(Object message) { Log.debug(Interpreter.getSourceName() + ":" + Interpreter.getLine(), message); }
+ public static void info(Object message) { Log.info(Interpreter.getSourceName() + ":" + Interpreter.getLine(), message); }
+ public static void warn(Object message) { Log.warn(Interpreter.getSourceName() + ":" + Interpreter.getLine(), message); }
+ public static void error(Object message) { Log.error(Interpreter.getSourceName() + ":" + Interpreter.getLine(), message); }
public static class NotPauseableException extends Exception { NotPauseableException() { } }
// NOTE: There are about 3 pages of rules in ecma262 about string to number conversions
// We aren't even close to following all those rules. We probably never will be.
- if (o instanceof String)
- try { return N((String)o); } catch (NumberFormatException e) { return N(Double.NaN); }
+ if (o instanceof String) try { return N((String)o); } catch (NumberFormatException e) { return N(Double.NaN); }
if (o instanceof Boolean) return ((Boolean)o).booleanValue() ? N(1) : ZERO;
- if (o instanceof JS) return ((JS)o).coerceToNumber();
throw new Error("toNumber() got object of type " + o.getClass().getName() + " which we don't know how to handle");
}
if(o == null) return "null";
if(o instanceof String) return (String) o;
if(o instanceof Integer || o instanceof Long || o instanceof Boolean) return o.toString();
- if(o instanceof JS) return ((JS)o).coerceToString();
+ if(o instanceof JSArray) return o.toString();
+ if(o instanceof JSDate) return o.toString();
if(o instanceof Double || o instanceof Float) {
double d = ((Number)o).doubleValue();
if((int)d == d) return Integer.toString((int)d);
return o.toString();
}
- return o.toString();
+ throw new RuntimeException("can't coerce that!");
}
-
// Instance Methods ////////////////////////////////////////////////////////////////////
public static final Integer ZERO = new Integer(0);
};
private Hash entries = null;
- public Enumeration keys() throws JSExn {
- return entries == null ? emptyEnumeration : entries.keys();
+
+ public static JS fromReader(String sourceName, int firstLine, Reader sourceCode) throws IOException {
+ return JSFunction._fromReader(sourceName, firstLine, sourceCode);
}
- public Object get(Object key) throws JSExn { return entries == null ? null : entries.get(key, null); }
- public void put(Object key, Object val) throws JSExn {
- if (entries == null) entries = new Hash();
- entries.put(key, null, val);
+
+ // HACK: caller can't know if the argument is a JSFunction or not...
+ public static JS cloneWithNewParentScope(JS j, JSScope s) {
+ return ((JSFunction)j)._cloneWithNewParentScope(s);
}
// Trap support //////////////////////////////////////////////////////////////////////////////
/** override and return true to allow placing traps on this object.
- * if isRead true, this is a read trap, otherwise write trap
- **/
+ * if isRead true, this is a read trap, otherwise write trap
+ **/
protected boolean isTrappable(Object name, boolean isRead) { return true; }
/** performs a put, triggering traps if present; traps are run in an unpauseable interpreter */
}
- // Call Support //////////////////////////////////////////////////////////////////////////////
-
- // return this from get() if the key was actually a method.
- public static final Object METHOD = new Object();
- 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() +")");
- }
-
-
- // Typing Support //////////////////////////////////////////////////////////////////////////////
-
- public Number coerceToNumber() { throw new JSRuntimeExn("tried to coerce a JavaScript object of type " +
- getClass().getName() + " to a Number"); }
- public String coerceToString() { throw new JSRuntimeExn("tried to coerce a JavaScript object of type " +
- getClass().getName() + " to a String"); }
- public boolean coerceToBoolean() { throw new JSRuntimeExn("tried to coerce a JavaScript object of type " +
- getClass().getName() + " to a Boolean"); }
-
- public String typeName() { return "object"; }
-
}