move JS's Hashtable to JS.O
[org.ibex.core.git] / src / org / ibex / js / Interpreter.java
index 0d2c219..d16c582 100644 (file)
@@ -75,7 +75,7 @@ class Interpreter implements ByteCodes, Tokens {
             }
             switch(op) {
             case LITERAL: stack.push(arg); break;
-            case OBJECT: stack.push(new JS()); break;
+            case OBJECT: stack.push(new JS.O()); break;
             case ARRAY: stack.push(new JSArray(JS.toNumber(arg).intValue())); break;
             case DECLARE: scope.declare((String)(arg==null ? stack.peek() : arg)); if(arg != null) stack.push(arg); break;
             case TOPSCOPE: stack.push(scope); break;
@@ -172,26 +172,24 @@ class Interpreter implements ByteCodes, Tokens {
                         pc = ((TryMarker)o).finallyLoc - 1;
                         continue OUTER;
                     } else if (o instanceof CallMarker) {
-                        if (scope instanceof Trap.TrapScope) { // handles return component of a read trap
-                            Trap.TrapScope ts = (Trap.TrapScope)scope;
-                            if (retval != null && retval instanceof Boolean && ((Boolean)retval).booleanValue())
-                                ts.cascadeHappened = true;
-                            if (!ts.cascadeHappened) {
-                                ts.cascadeHappened = true;
-                                Trap t = ts.t.next;
-                                while (t != null && t.f.numFormalArgs == 0) t = t.next;
-                                if (t == null) {
-                                    ((JS)ts.t.trapee).put(ts.t.name, ts.val);
-                                    if (pausecount > initialPauseCount) { pc++; return null; }   // we were paused
-                                } else {
-                                    stack.push(o);
+                        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);
+                            if(cascade) {
+                                Trap t = tm.t.next;
+                                while(t != null && t.readTrap()) t = t.next;
+                                if(t != null) {
+                                    tm.t = t;
+                                    stack.push(tm);
                                     JSArray args = new JSArray();
-                                    args.addElement(ts.val);
+                                    args.addElement(tm.val);
                                     stack.push(args);
                                     f = t.f;
-                                    scope = new Trap.TrapScope(f.parentScope, t, ts.val);
+                                    scope = new JSScope(f.parentScope);
                                     pc = -1;
                                     continue OUTER;
+                                } else {
+                                    tm.trapee.put(tm.key,tm.val);
                                 }
                             }
                         }
@@ -199,6 +197,7 @@ class Interpreter implements ByteCodes, Tokens {
                         pc = ((CallMarker)o).pc - 1;
                         f = (JSFunction)((CallMarker)o).f;
                         stack.push(retval);
+                        if (pausecount > initialPauseCount) { pc++; return null; }   // we were paused
                         continue OUTER;
                     }
                 }
@@ -215,106 +214,109 @@ class Interpreter implements ByteCodes, Tokens {
                     throw je("tried to put a value to the " + key + " property on a " + target.getClass().getName());
                 if (key == null)
                     throw je("tried to assign \"" + (val==null?"(null)":val.toString()) + "\" to the null key");
+                
+                if (target instanceof String || target instanceof Number || target instanceof Boolean) throw new JSExn("can't put values to primitives");
+                if(!(target instanceof JS)) throw new Error("should never happen");
 
                 Trap t = null;
-                if (target instanceof JSScope && key.equals("cascade")) {
-                    Trap.TrapScope ts = null;
-                    JSScope p = (JSScope)target; // search the scope-path for the trap
-                    if (target instanceof Trap.TrapScope) {
-                       ts = (Trap.TrapScope)target;
-                    } else {
-                        while (ts == null && p.getParentScope() != null) {
-                            p = p.getParentScope();
-                            if (p instanceof Trap.TrapScope) ts = (Trap.TrapScope)p;
-                        }
-                    }
-                    if(ts != null) {
-                        t = ts.t.next;
-                        ts.cascadeHappened = true;
-                        while (t != null && t.f.numFormalArgs == 0) t = t.next;
-                        if (t == null) { target = ts.t.trapee; key = ts.t.name; }
+                TrapMarker tm = null;
+                if(target instanceof JSScope && key.equals("cascade")) {
+                    Object o=null;
+                    int i;
+                    for(i=stack.size()-1;i>=0;i--) if((o = stack.elementAt(i)) instanceof CallMarker) break;
+                    if(i==0) throw new Error("didn't find a call marker while doing cascade");
+                    if(o instanceof TrapMarker) {
+                        tm = (TrapMarker) o;
+                        target = tm.trapee;
+                        key = tm.key;
+                        tm.cascadeHappened = true;
+                        t = tm.t;
+                        if(t.readTrap()) throw new JSExn("can't put to cascade in a read trap");
+                        t = t.next;
+                        while(t != null && t.readTrap()) t = t.next;
                     }
                 }
-                if(t == null) {
-                    if (target instanceof JSScope) {
-                        JSScope p = (JSScope)target; // search the scope-path for the trap
-                        t = p.getTrap(key);
-                        while (t == null && p.getParentScope() != null) { p = p.getParentScope(); t = p.getTrap(key); }
-                    } else {
-                        t = ((JS)target).getTrap(key);
-                    }
-                    while (t != null && t.f.numFormalArgs == 0) t = t.next; // find the first write trap
+                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 (t != null) {
-                    stack.push(new CallMarker(this));
-                    if(stack.size() > MAX_STACK_SIZE) throw new JSExn("stack overflow");
+                
+                stack.push(val);
+                
+                if(t != null) {
+                    stack.push(new TrapMarker(this,t,(JS)target,key,val));
                     JSArray args = new JSArray();
                     args.addElement(val);
                     stack.push(args);
                     f = t.f;
-                    scope = new Trap.TrapScope(f.parentScope, t, val);
+                    scope = new JSScope(f.parentScope);
                     pc = -1;
                     break;
+                } else {
+                    ((JS)target).put(key,val);
+                    if (pausecount > initialPauseCount) { pc++; return null; }   // we were paused
+                    break;
                 }
-                ((JS)target).put(key, val);
-                if (pausecount > initialPauseCount) { pc++; return null; }   // we were paused
-                stack.push(val);
-                break;
             }
 
             case GET:
             case GET_PRESERVE: {
-                Object o, v;
+                Object target, key;
                 if (op == GET) {
-                    v = arg == null ? stack.pop() : arg;
-                    o = stack.pop();
+                    key = arg == null ? stack.pop() : arg;
+                    target = stack.pop();
                 } else {
-                    v = stack.pop();
-                    o = stack.peek();
-                    stack.push(v);
+                    key = stack.pop();
+                    target = stack.peek();
+                    stack.push(key);
                 }
                 Object ret = null;
-                if (v == null) throw je("tried to get the null key from " + o);
-                if (o == null) throw je("tried to get property \"" + v + "\" from the null object");
-                if (o instanceof String || o instanceof Number || o instanceof Boolean) {
-                    ret = getFromPrimitive(o,v);
+                if (key == null) throw je("tried to get the null key from " + target);
+                if (target == null) throw je("tried to get property \"" + key + "\" from the null object");
+                if (target instanceof String || target instanceof Number || target instanceof Boolean) {
+                    ret = getFromPrimitive(target,key);
                     stack.push(ret);
                     break;
-                } else if (o instanceof JS) {
-                    Trap t = null;
-                    if (o instanceof Trap.TrapScope && v.equals("cascade")) {
-                        t = ((Trap.TrapScope)o).t.next;
-                        while (t != null && t.f.numFormalArgs != 0) t = t.next;
-                        if (t == null) { v = ((Trap.TrapScope)o).t.name; o = ((Trap.TrapScope)o).t.trapee; }
-
-                    } else if (o instanceof JS) {
-                        if (o instanceof JSScope) {
-                            JSScope p = (JSScope)o; // search the scope-path for the trap
-                            t = p.getTrap(v);
-                            while (t == null && p.getParentScope() != null) { p = p.getParentScope(); t = p.getTrap(v); }
-                        } else {
-                            t = ((JS)o).getTrap(v);
-                        }
-                        while (t != null && t.f.numFormalArgs != 0) t = t.next; // get first read trap
-                    }
-                    if (t != null) {
-                        stack.push(new CallMarker(this));
-                        if(stack.size() > MAX_STACK_SIZE) throw new JSExn("stack overflow");
-                        JSArray args = new JSArray();
-                        stack.push(args);
-                        f = t.f;
-                        scope = new Trap.TrapScope(f.parentScope, t, null);
-                        ((Trap.TrapScope)scope).cascadeHappened = true;
-                        pc = -1;
-                        break;
+                }
+                if(!(target instanceof JS)) throw new Error("should never happen");
+                
+                Trap t = null;
+                TrapMarker tm = null;
+                if(target instanceof JSScope && key.equals("cascade")) {
+                    Object o=null;
+                    int i;
+                    for(i=stack.size()-1;i>=0;i--) if((o = stack.elementAt(i)) instanceof CallMarker) break;
+                    if(i==0) throw new Error("didn't find a call marker while doing cascade");
+                    if(o instanceof TrapMarker) {
+                        tm = (TrapMarker) o;
+                        target = tm.trapee;
+                        key = tm.key;
+                        t = tm.t;
+                        if(t.writeTrap()) throw new JSExn("can't do a write cascade in a read trap");
+                        t = t.next;
+                        while(t != null && t.writeTrap()) t = t.next;
+                        if(t != null) tm.cascadeHappened = true;
                     }
-                    ret = ((JS)o).get(v);
-                    if (ret == JS.METHOD) ret = new Stub((JS)o, v);
-                    if (pausecount > initialPauseCount) { pc++; return null; }   // we were paused
+                }
+                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.writeTrap()) t = t.next;
+                }
+                
+                if(t != null) {
+                    stack.push(new TrapMarker(this,t,(JS)target,key,null));
+                    stack.push(new JSArray());
+                    f = t.f;
+                    scope = new JSScope(f.parentScope);
+                    pc = -1;
+                    break;
+                } else {
+                    ret = ((JS)target).get(key);
+                    if (ret == JS.METHOD) ret = new Stub((JS)target, key);
                     stack.push(ret);
+                    if (pausecount > initialPauseCount) { pc++; return null; }   // we were paused
                     break;
                 }
-                throw je("tried to get property " + v + " from a " + o.getClass().getName());
             }
             
             case CALL: case CALLMETHOD: {
@@ -473,6 +475,7 @@ class Interpreter implements ByteCodes, Tokens {
             }
 
             default: {
+                if(op == BITOR) throw new Error("pc: " + pc + " of " + f);
                 Object right = stack.pop();
                 Object left = stack.pop();
                 switch(op) {
@@ -567,6 +570,21 @@ class Interpreter implements ByteCodes, Tokens {
         public CallMarker(Interpreter cx) { pc = cx.pc + 1; scope = cx.scope; f = cx.f; }
     }
     
+    public static class TrapMarker extends CallMarker {
+        Trap t;
+        JS trapee;
+        Object key;
+        Object val;
+        boolean cascadeHappened;
+        public TrapMarker(Interpreter cx, Trap t, JS trapee, Object key, Object val) {
+            super(cx);
+            this.t = t;
+            this.trapee = trapee;
+            this.key = key;
+            this.val = val;
+        }
+    }
+    
     public static class CatchMarker { }
     private static CatchMarker catchMarker = new CatchMarker();