more trap cleanup, properly handle JS.Clones
authorbrian <brian@brianweb.net>
Wed, 7 Jul 2004 06:18:52 +0000 (06:18 +0000)
committerbrian <brian@brianweb.net>
Wed, 7 Jul 2004 06:18:52 +0000 (06:18 +0000)
darcs-hash:20040707061852-24bed-96f9c4cfe82803fc415617a9bbc811784b383de9.gz

src/org/ibex/js/Interpreter.java
src/org/ibex/js/JS.java
src/org/ibex/js/JSScope.java
src/org/ibex/js/Test.java
src/org/ibex/js/Trap.java

index 6fc452b..15d42be 100644 (file)
@@ -170,26 +170,28 @@ class Interpreter implements ByteCodes, Tokens {
                     } else if (o instanceof CallMarker) {
                         if (o instanceof TrapMarker) { // handles return component of a read trap
                             TrapMarker tm = (TrapMarker) o;
-                            boolean cascade = tm.t.writeTrap() && !tm.cascadeHappened && !JS.toBoolean(retval);
+                            boolean cascade = tm.t.isWriteTrap() && !tm.cascadeHappened && !JS.toBoolean(retval);
                             if(cascade) {
-                                Trap t = tm.t.next;
-                                while(t != null && t.readTrap()) t = t.next;
+                                Trap t = tm.t.nextWriteTrap();
+                                if(t == null && tm.target instanceof JS.Clone) {
+                                    tm.target = ((JS.Clone)tm.target).clonee;
+                                    t = tm.target.getTrap(tm.key);
+                                    if(t != null) t = t.writeTrap();
+                                }
                                 if(t != null) {
-                                    tm.t = t;
-                                    stack.push(tm);
-                                    stack.push(new JSArgs(tm.val,t.f));
-                                    f = t.f;
-                                    scope = new JSScope(f.parentScope);
-                                    pc = -1;
+                                    tm.t = t; // we reuse the old trap marker
+                                    setupTrap(t,tm.val,tm);
+                                    pc--; // we increment it on the next iter
                                     continue OUTER;
                                 } else {
-                                    tm.trapee.put(tm.key,tm.val);
+                                    tm.target.put(tm.key,tm.val);
                                 }
                             }
                         }
-                        scope = ((CallMarker)o).scope;
-                        pc = ((CallMarker)o).pc - 1;
-                        f = (JSFunction)((CallMarker)o).f;
+                        CallMarker cm = (CallMarker) o;
+                        scope = cm.scope;
+                        pc = cm.pc - 1;
+                        f = cm.f;
                         stack.push(retval);
                         if (pausecount > initialPauseCount) { pc++; return null; }   // we were paused
                         if(f == null) return retval;
@@ -212,28 +214,29 @@ class Interpreter implements ByteCodes, Tokens {
                     CallMarker o = stack.findCall();
                     if(o instanceof TrapMarker) {
                         tm = (TrapMarker) o;
-                        target = tm.trapee;
+                        target = tm.target;
                         key = tm.key;
                         tm.cascadeHappened = true;
                         t = tm.t;
-                        if(t.readTrap()) throw new JSExn("can't do a write cascade in a read trap");
-                        t = t.next;
-                        while(t != null && t.readTrap()) t = t.next;
+                        if(t.isReadTrap()) throw new JSExn("can't do a write cascade in a read trap");
+                        t = t.nextWriteTrap();
                     }
                 }
-                if(tm == null) { // didn't find a trap marker, try to find a trap
-                    t = target instanceof JSScope ? t = ((JSScope)target).top().getTrap(key) : ((JS)target).getTrap(key);
-                    while(t != null && t.readTrap()) t = t.next;
+                if(tm == null) { // not cascading
+                    t = target instanceof JSScope ? t = ((JSScope)target).top().getTrap(key) : target.getTrap(key);
+                    if(t != null) t = t.writeTrap();
+                }
+                if(t == null && target instanceof JS.Clone) {
+                    target = ((JS.Clone)target).clonee;
+                    t = target.getTrap(key);
+                    if(t != null) t = t.writeTrap();
                 }
 
                 stack.push(val);
                 
                 if(t != null) {
-                    stack.push(new TrapMarker(this,t,target,key,val));
-                    stack.push(new JSArgs(val,t.f));
-                    f = t.f;
-                    scope = new TrapScope(f.parentScope,target,f,key);
-                    pc = -1;
+                    setupTrap(t,val,new TrapMarker(this,t,target,key,val));
+                    pc--; // we increment later
                     break;
                 } else {
                     target.put(key,val);
@@ -263,26 +266,26 @@ class Interpreter implements ByteCodes, Tokens {
                     CallMarker o = stack.findCall();
                     if(o instanceof TrapMarker) {
                         tm = (TrapMarker) o;
-                        target = tm.trapee;
+                        target = tm.target;
                         key = tm.key;
                         t = tm.t;
-                        if(t.writeTrap()) throw new JSExn("can't do a read cascade in a write trap");
-                        t = t.next;
-                        while(t != null && t.writeTrap()) t = t.next;
-                        if(t != null) tm.cascadeHappened = true;
+                        if(t.isWriteTrap()) throw new JSExn("can't do a read cascade in a write trap");
+                        t = t.nextReadTrap();
                     }
                 }
-                if(tm == null) { // didn't find a trap marker, try to find a trap
+                if(tm == null) { // not cascading
                     t = target instanceof JSScope ? t = ((JSScope)target).top().getTrap(key) : ((JS)target).getTrap(key);
-                    while(t != null && t.writeTrap()) t = t.next;
+                    if(t != null) t = t.readTrap();
+                }
+                if(t == null && target instanceof JS.Clone) {
+                    target = ((JS.Clone)target).clonee;
+                    t = target.getTrap(key);
+                    if(t != null) t = t.readTrap();
                 }
                 
                 if(t != null) {
-                    stack.push(new TrapMarker(this,t,(JS)target,key,null));
-                    stack.push(new JSArgs(t.f));
-                    f = t.f;
-                    scope = new TrapScope(f.parentScope,target,f,key);
-                    pc = -1;
+                    setupTrap(t,null,new TrapMarker(this,t,target,key,null));
+                    pc--; // we increment later
                     break;
                 } else {
                     ret = target.get(key);
@@ -513,6 +516,13 @@ class Interpreter implements ByteCodes, Tokens {
         throw e;
     }
 
+    void setupTrap(Trap t, JS val, CallMarker cm) throws JSExn {
+        stack.push(cm);
+        stack.push(t.isWriteTrap() ? new JSArgs(val,t.f) : new JSArgs(t.f));
+        f = t.f;
+        scope = new TrapScope(t.f.parentScope,t.target,t.f,t.key);
+        pc = 0;
+    }
 
 
     // Markers //////////////////////////////////////////////////////////////////////
@@ -534,14 +544,14 @@ class Interpreter implements ByteCodes, Tokens {
     
     static class TrapMarker extends CallMarker {
         Trap t;
-        final JS trapee;
+        JS target;
         final JS key;
         final JS val;
         boolean cascadeHappened;
-        public TrapMarker(Interpreter cx, Trap t, JS trapee, JS key, JS val) {
+        public TrapMarker(Interpreter cx, Trap t, JS target, JS key, JS val) {
             super(cx);
             this.t = t;
-            this.trapee = trapee;
+            this.target = target;
             this.key = key;
             this.val = val;
         }
index a81c419..c13d2a0 100644 (file)
@@ -44,7 +44,7 @@ public abstract class JS {
     String debugToString() { return "[class=" + getClass().getName() + "]"; }
     boolean jsequals(JS o) { return this == o; }
     
-    public static class O extends JS {
+    public static class O extends JS implements Cloneable {
         private Hash entries;
         
         public Enumeration keys() throws JSExn { return entries == null ? (Enumeration)EMPTY_ENUMERATION : (Enumeration)new JavaEnumeration(null,entries.keys()); }
@@ -85,7 +85,7 @@ public abstract class JS {
     
     public interface Cloneable { }
     
-    public static class Clone extends JS.O implements Cloneable {
+    public static class Clone extends JS.O {
         protected final JS clonee;
         JS _unclone() { return clonee.unclone(); }
         public JS getClonee() { return clonee; }
@@ -95,8 +95,8 @@ public abstract class JS {
         }
         public boolean jsequals(JS o) { return unclone().jsequals(o.unclone()); }
         public Enumeration keys() throws JSExn { return clonee.keys(); }
-        public JS get(JS key) throws JSExn { return clonee.get(key); }
-        public void put(JS key, JS val) throws JSExn { clonee.put(key, val); }
+        public JS get(JS key) throws JSExn { return clonee.getAndTriggerTraps(key); }
+        public void put(JS key, JS val) throws JSExn { clonee.putAndTriggerTraps(key, val); }
         public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
             return clonee.callMethod(method, a0, a1, a2, rest, nargs);
         }
@@ -300,15 +300,17 @@ public abstract class JS {
     /** performs a put, triggering traps if present; traps are run in an unpauseable interpreter */
     public void putAndTriggerTraps(JS key, JS value) throws JSExn {
         Trap t = getTrap(key);
-        if (t != null) t.invoke(value);
-        else put(key, value);
+        throw new Error("FIXME");
+        /*if (t != null) t.invoke(value);
+        elese put(key, value);*/
     }
 
     /** performs a get, triggering traps if present; traps are run in an unpauseable interpreter */
     public JS getAndTriggerTraps(JS key) throws JSExn {
         Trap t = getTrap(key);
-        if (t != null) return t.invoke();
-        else return get(key);
+        throw new Error("FIXME");
+        /*if (t != null) return t.invoke();
+        else return get(key);*/
     }
 
     /** adds a trap, avoiding duplicates */
@@ -323,7 +325,7 @@ public abstract class JS {
     final void delTrap(JS key, JSFunction f) throws JSExn {
         Trap t = (Trap)getTrap(key);
         if (t == null) return;
-        if (t.f == f) { putTrap(t.name, t.next); return; }
+        if (t.f == f) { putTrap(t.target, t.next); return; }
         for(; t.next != null; t = t.next) if (t.next.f == f) { t.next = t.next.next; return; }
     }
 
index f7c6355..f7d3d6d 100644 (file)
@@ -2,7 +2,6 @@
 package org.ibex.js; 
 
 // FIXME: should allow parentScope to be a JS, not a JSScope
-// FIXME: Index local vars by number and lookup in an array
 /** Implementation of a JavaScript Scope */
 // HACK: JSScope doesn't really need the BT, this is just for Box.java 
 public class JSScope extends JS.BT { 
index 8e4be33..478ef8e 100644 (file)
@@ -31,6 +31,7 @@ public class Test extends JS {
     public JS get(JS key) throws JSExn {
         if(!JS.isString(key)) return null;
         if("print".equals(JS.toString(key))) return METHOD;
+        if("clone".equals(JS.toString(key))) return METHOD;
         if("bgget".equals(JS.toString(key))) {
             action = "bgget";
             try {
@@ -51,8 +52,12 @@ public class Test extends JS {
             } catch(NotPauseableException e) {
                 throw new Error("should never happen");
             }
-        return;
-        }        
+            return;
+        }   
+        if("exit".equals(JS.toString(key))) {
+            System.exit(JS.toInt(val));
+            return;
+        }
         super.put(key,val);
     }
     
@@ -62,6 +67,7 @@ public class Test extends JS {
             System.out.println(JS.debugToString(a0));
             return null;
         }
+        if("clone".equals(JS.toString(method))) return a0 == null ? null : a0.jsclone();
         return null;
     }
 }
index 67d0238..580ed69 100644 (file)
@@ -7,43 +7,22 @@ package org.ibex.js;
  *  linked list stack, with the most recently placed trap at the head
  *  of the list.
  */
-class Trap {
+final class Trap {
 
-    JS trapee = null;          ///< the box on which this trap was placed
-    JS name = null;        ///< the property that the trap was placed on
+    final JS target;          ///< the box on which this trap was placed
+    final JS key;             ///< the property that the trap was placed on
 
-    JSFunction f = null;       ///< the function for this trap
-    Trap next = null;          ///< the next trap down the trap stack
+    final JSFunction f;       ///< the function for this trap
+    Trap next;                ///< the next trap down the trap stack
 
     Trap(JS b, JS n, JSFunction f, Trap nx) {
-        trapee = b; name = n; this.f = f; this.next = nx;
+        target = b; key = n; this.f = f; this.next = nx;
     }
-
-    static final JSFunction putInvoker = new JSFunction("putInvoker", 0, null);
-    static final JSFunction getInvoker = new JSFunction("getInvoker", 0, null);
-
-    static {
-        putInvoker.add(1, ByteCodes.PUT, null);
-        putInvoker.add(2, Tokens.RETURN, null);
-        getInvoker.add(1, ByteCodes.GET, null);
-        getInvoker.add(2, Tokens.RETURN, null);
-    }
-    
-    boolean readTrap() { return f.numFormalArgs == 0; }
-    boolean writeTrap() { return f.numFormalArgs != 0; }
     
-    void invoke(JS value) throws JSExn {
-        Interpreter i = new Interpreter(putInvoker, false, null);
-        i.stack.push(trapee);
-        i.stack.push(name);
-        i.stack.push(value);
-        i.resume();
-    }
-
-    JS invoke() throws JSExn {
-        Interpreter i = new Interpreter(getInvoker, false, null);
-        i.stack.push(trapee);
-        i.stack.push(name);
-        return i.resume();
-    }
+    boolean isReadTrap()  { return f.numFormalArgs == 0; }
+    boolean isWriteTrap() { return f.numFormalArgs != 0; }
+    Trap readTrap()  { Trap t = this; while(t!=null && t.isWriteTrap()) t = t.next; return t; }
+    Trap writeTrap() { Trap t = this; while(t!=null && t.isReadTrap())  t = t.next; return t; }
+    Trap nextReadTrap()  { return next == null ? null : next.readTrap();  }
+    Trap nextWriteTrap() { return next == null ? null : next.writeTrap(); }
 }