+
+ public static class NotPauseableException extends Exception { NotPauseableException() { } }
+
+ /** returns a callback which will restart the context; expects a value to be pushed onto the stack when unpaused */
+ public static UnpauseCallback pause() throws NotPauseableException {
+ Interpreter i = Interpreter.current();
+ if (i.pausecount == -1) throw new NotPauseableException();
+ i.pausecount++;
+ return new JS.UnpauseCallback(i);
+ }
+
+ public static class UnpauseCallback implements Scheduler.Task {
+ Interpreter i;
+ UnpauseCallback(Interpreter i) { this.i = i; }
+ public void perform() throws JSExn { unpause(null); }
+ public void unpause(Object o) throws JSExn {
+ // FIXME: if o instanceof JSExn, throw it into the JSworld
+ i.stack.push(o);
+ i.resume();
+ }
+ }
+
+
+
+ // Static Helper Methods ///////////////////////////////////////////////////////////////////////////////////
+
+ /** coerce an object to a Boolean */
+ public static boolean toBoolean(Object o) {
+ if (o == null) return false;
+ if (o instanceof Boolean) return ((Boolean)o).booleanValue();
+ if (o instanceof Long) return ((Long)o).longValue() != 0;
+ if (o instanceof Integer) return ((Integer)o).intValue() != 0;
+ if (o instanceof Number) {
+ double d = ((Number) o).doubleValue();
+ // NOTE: d == d is a test for NaN. It should be faster than Double.isNaN()
+ return d != 0.0 && d == d;
+ }
+ if (o instanceof String) return ((String)o).length() != 0;
+ return true;
+ }
+
+ /** coerce an object to a Long */
+ public static long toLong(Object o) { return toNumber(o).longValue(); }
+
+ /** coerce an object to an Int */
+ public static int toInt(Object o) { return toNumber(o).intValue(); }
+
+ /** coerce an object to a Double */
+ public static double toDouble(Object o) { return toNumber(o).doubleValue(); }
+
+ /** coerce an object to a Number */
+ public static Number toNumber(Object o) {
+ if (o == null) return ZERO;
+ if (o instanceof Number) return ((Number)o);
+
+ // 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 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");
+ }
+
+ /** coerce an object to a String */
+ public static String toString(Object o) {
+ 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 Double || o instanceof Float) {
+ double d = ((Number)o).doubleValue();
+ if((int)d == d) return Integer.toString((int)d);
+ return o.toString();
+ }
+ return o.toString();
+ }
+
+
+ // Instance Methods ////////////////////////////////////////////////////////////////////
+
+ public static final Integer ZERO = new Integer(0);