- public Object[] keys() {
- Object[] ret = graftee.keys();
- for(int i=0; i<ret.length; i++) if (replaced_key.equals(ret[i])) return ret;
- Object[] ret2 = new Object[ret.length + 1];
- System.arraycopy(ret, 0, ret2, 0, ret.length);
- ret2[ret2.length - 1] = replaced_key;
- return ret2;
- }
- }
-
- /** anything that is callable with the () operator and wasn't compiled from JS code */
- public static abstract class Callable extends JS.Obj {
- public abstract Object call(JS.Array args) throws JS.Exn;
- }
-
- /** a scope that is populated with js objects and functions normally found in the global scope */
- public static class GlobalScope extends GlobalScopeImpl {
- public GlobalScope() { this(null); }
- public GlobalScope(JS.Scope parent) { super(parent); }
- }
-
- public static class TailCall {
- Function func = null;
- JS.Array args = null;
- public TailCall() { }
- public TailCall set(Function func) { this.func = func; this.args = new JS.Array(); return this; }
- public TailCall set(Function func, JS.Array args) { this.func = func; this.args = args; return this; }
- }
-
- /** encapsulates the state of a JavaScript "thread" (ie stack) */
- public static class Context {
-
-
- // Statics //////////////////////////////////////////////////////////////////////
-
- /**
- * Return this from call/get/put in order to make the interpreter pause. The interpreter will expect a value
- * (the return from the call or the get) to be pushed onto the stack when it is resumed.
- */
- public static Object pause = new Object();
-
- private int getLine_() { return current().f == null ? -1 : (pc < 0 || pc >= f.size) ? -1 : f.line[pc]; }
- public static int getLine() { return current().getLine_(); }
- public static String getSourceName() { return current().f == null ? null : current().f.sourceName; }
-
- /** fetches the currently-executing javascript function */
- public static JS.Context current() { return (JS.Context)threadToContext.get(Thread.currentThread()); }
- private static Hashtable threadToContext = new Hashtable();
-
-
- // Instance members and methods //////////////////////////////////////////////////////////////////////
-
- /** the currently-executing Function */
- Function f = null;
-
- /** the currently-executing scope */
- public Scope scope = null; // FIXME: do we really need this? the function should contain this info
-
- /** the object stack */
- Vec stack = new Vec();
-
- /** the program counter */
- int pc = 0;
-
- public Context(Function function, Scope scope) {
- if (scope == null) scope = new Scope(function.parentScope);
- stack.push(new Function.CallMarker(this));
- stack.push(new JS.Array());
- this.f = function;
- this.scope = scope;
- }
-
- public Object resume() { return resume(null); }
- public Object resume(Object o) {
- Thread t = Thread.currentThread();
- Context old = (Context)threadToContext.get(t);
- try {
- threadToContext.put(t, this);
- stack.push(o);
- return Function.eval(this);
- } finally {
- if (old == null) threadToContext.remove(t);
- else threadToContext.put(t, old);
- }
- }
-
- }
-
- public static void recurse(String indent, String name, Object o) {
- if (!name.equals("")) name += " : ";
-
- if (o == null) {
- Log.logJS(indent + name + "<null>");
-
- } else if (o instanceof JS.Array) {
- Log.logJS(indent + name + "<array>");
- JS.Array na = (JS.Array)o;
- for(int i=0; i<na.length(); i++)
- recurse(indent + " ", i + "", na.elementAt(i));
-
- } else if (o instanceof JS) {
- Log.logJS(indent + name + "<object>");
- JS s = (JS)o;
- Object[] keys = s.keys();
- for(int i=0; i<keys.length; i++)
- if (keys[i] != null)
- recurse(indent + " ", keys[i].toString(),
- (keys[i] instanceof Integer) ?
- s.get(((Integer)keys[i])) : s.get(keys[i].toString()));
-
- } else {
- Log.logJS(indent + name + o);
-
+ public Enumeration keys() {
+ return new Enumeration() {
+ Enumeration graftee_enumeration = graftee.keys();
+ boolean returned_replaced = false;
+ public boolean hasMoreElements() {
+ if (graftee_enumeration.hasMoreElements()) return true;
+ return !returned_replaced;
+ }
+ public Object nextElement() {
+ if (!graftee_enumeration.hasMoreElements()) {
+ if (returned_replaced) throw new NoSuchElementException();
+ returned_replaced = true;
+ return replaced_key;
+ } else {
+ Object ret = graftee_enumeration.nextElement();
+ if (!returned_replaced && ret.equals(replaced_key)) returned_replaced = true;
+ return ret;
+ }
+ }
+ };