Revision: 4765
          http://sourceforge.net/p/vexi/code/4765
Author:   mkpg2
Date:     2015-02-25 20:11:16 +0000 (Wed, 25 Feb 2015)
Log Message:
-----------
Background thread callback/syncCall.
- allows pausing when call java script to be evaluated from another thread 
 (previously used mechanism was not pausable since it used runInCurrent).
- test for syncCall
Rename methods findXxx -> expectXxx. Better convention.

Modified Paths:
--------------
    branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/VML.java
    
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/VMLBuilder.java
    
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/graphics/Picture.java
    branches/vexi3/org.vexi-core.main/src/main/jpp/org/vexi/core/Vexi.jpp
    branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Fountain.java
    
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Interpreter.java
    branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/JSFunction.java
    branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/JSU.java
    branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Scheduler.java
    branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Thread.java
    
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/parse/Function.java
    branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/RunJS.java
    branches/vexi3/org.vexi-library.js/src/test/java/test/js/TestJS.java

Added Paths:
-----------
    branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/
    
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/AssertionUtil.java
    
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/Scripting.java
    
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/TestJSThreading.java
    branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/script.js

Removed Paths:
-------------
    branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/JSDynProxy.java

Modified: branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/VML.java
===================================================================
--- branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/VML.java      
2015-02-16 09:55:52 UTC (rev 4764)
+++ branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/VML.java      
2015-02-25 20:11:16 UTC (rev 4765)
@@ -198,7 +198,7 @@
             
             
             void apply(JS[] thisHolder, JS[] args, PerInstantiationScope 
idContextParent, PerInstantiationScope idContext) throws JSExn {
-                Main.SCHEDULER.findCurrentInterpreter().enterNonJSCall(this);
+                Main.SCHEDULER.expectCurrentInterpreter().enterNonJSCall(this);
                 try {
                     // REMARK - the preapplies may not have been resolved yet, 
                     // the resolved template is not necessarily the same 
object.
@@ -301,7 +301,7 @@
                         JSU.cloneWithNewGlobalScope((Function)script, 
pis).apply(null, args!=null?args:EMPTY_JS_ARRAY);
                     }
                 } finally {
-                    Main.SCHEDULER.findCurrentInterpreter().exitNonJSCall();
+                    Main.SCHEDULER.expectCurrentInterpreter().exitNonJSCall();
                 }
             }
 

Modified: 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/VMLBuilder.java
===================================================================
--- 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/VMLBuilder.java   
    2015-02-16 09:55:52 UTC (rev 4764)
+++ 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/VMLBuilder.java   
    2015-02-25 20:11:16 UTC (rev 4765)
@@ -216,14 +216,14 @@
                     Function staticScript = parseScript(static_.content, 
static_.contentStart, sourceName());
                     if (t != null) {
                         static_.template = t;
-                        
Main.SCHEDULER.findCurrentInterpreter().enterNonJSCall( static_);
+                        
Main.SCHEDULER.expectCurrentInterpreter().enterNonJSCall( static_);
                         try {
                             if (staticScript != null) {
                                 JS staticScope = static_.new StaticScope();
                                 JSU.cloneWithNewGlobalScope(staticScript, 
staticScope).apply(null, callempty);
                             }
                         } finally {
-                            
Main.SCHEDULER.findCurrentInterpreter().exitNonJSCall();
+                            
Main.SCHEDULER.expectCurrentInterpreter().exitNonJSCall();
                         }
                     } else {
                         Log.warn(LOG_TYPE, "'" +  static_.sourceName + ".t' 
does not declare a template");

Modified: 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/graphics/Picture.java
===================================================================
--- 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/graphics/Picture.java  
    2015-02-16 09:55:52 UTC (rev 4764)
+++ 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/graphics/Picture.java  
    2015-02-25 20:11:16 UTC (rev 4765)
@@ -90,7 +90,7 @@
     }
        
     static public Picture load(JS[] args) throws JSExn {
-       final Scheduler sched = Scheduler.findCurrent();
+       final Scheduler sched = Scheduler.expectCurrent();
        final Thread callback = sched.pauseJSThread("load picture");
        Picture p = Picture.load(args[0], new Callable(){
                public Object run(Object o) throws JSExn {

Modified: branches/vexi3/org.vexi-core.main/src/main/jpp/org/vexi/core/Vexi.jpp
===================================================================
--- branches/vexi3/org.vexi-core.main/src/main/jpp/org/vexi/core/Vexi.jpp       
2015-02-16 09:55:52 UTC (rev 4764)
+++ branches/vexi3/org.vexi-core.main/src/main/jpp/org/vexi/core/Vexi.jpp       
2015-02-25 20:11:16 UTC (rev 4765)
@@ -654,7 +654,7 @@
                 // sanity check so we are not passing nonsensical arguments to 
the scheduler
                 throw new JSExn("Tried to put non-function value of type 
'"+(value==null?"null":value.type())+"' to vexi.thread");
             }
-            Main.SCHEDULER.runInNew(value, null);
+            Main.SCHEDULER.runInNew(value);
             return;
         case "debug":
             Main.debug = JSU.toBoolean(value);

Modified: 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Fountain.java
===================================================================
--- branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Fountain.java  
2015-02-16 09:55:52 UTC (rev 4764)
+++ branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Fountain.java  
2015-02-25 20:11:16 UTC (rev 4765)
@@ -155,7 +155,7 @@
        super.addTrap(key, f);
        // used for call backs when input stream is read, we assume
        // the traps added are callbacks
-       if(scheduler==null) scheduler = Scheduler.findCurrent();
+       if(scheduler==null) scheduler = Scheduler.expectCurrent();
     }
     
     // Perform any caching (Fountain.Multi calls this on its 
@@ -172,7 +172,7 @@
     public JS callMethod(JS this_, JS method, JS[] args) throws JSExn {
        if("info".equals(JSU.toString(method))){
                try {
-                       final Scheduler sched = Scheduler.findCurrent();
+                       final Scheduler sched = Scheduler.expectCurrent();
                        return sched.backgroundCall("get fountain info", new 
Callable<Object, JS>() {
                                public JS run(Object A) throws Exception {
                                        return getInfo();
@@ -417,7 +417,7 @@
     static final int[] ARGTYPES_2fountains = new 
int[]{JSU.FOUNTAIN,JSU.FOUNTAIN};
     static public void pipe(final JS[] args) throws JSExn{
        JSU.checkArgs(args, ARGTYPES_2fountains); 
-               final Scheduler sched = Scheduler.findCurrent();
+               final Scheduler sched = Scheduler.expectCurrent();
                sched.backgroundCall("pipe streams", new Callable<Object, JS>() 
{
                        public JS run(Object A) throws Exception {
                        try {

Modified: 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Interpreter.java
===================================================================
--- 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Interpreter.java   
    2015-02-16 09:55:52 UTC (rev 4764)
+++ 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Interpreter.java   
    2015-02-25 20:11:16 UTC (rev 4765)
@@ -119,7 +119,7 @@
     // FIXME: split this stuff out into a Script instance control object
     //        so it's possible to make JS either single or multi threaded.
     /** this is the only synchronization point we need in order to be 
threadsafe */
-    public synchronized Object run(Object o) throws JSExn {
+    public synchronized JS run(Object o) throws JSExn {
         if (f == null) throw new RuntimeException("function already finished");
         if (scope == null) throw new RuntimeException("scope is null");
         
@@ -136,7 +136,11 @@
     }
     
     public void pause(String forwhat) throws JSExn {
-        if (pausecount == -1 || f == null) throw new JSExn("Cannot "+forwhat+" 
in foreground thread");
+        if (pausecount == -1 || f == null) {           
+               String msg = "Cannot "+forwhat+" in thread '"+thread+"'";
+               if(old!=null) msg+=" (nested execution)";
+               throw new JSExn(msg);
+        }
         pausecount++;
         switch(f.op[pc]) {
             case Tokens.RETURN: case ByteCodes.PUT: get = false; break;
@@ -149,9 +153,7 @@
         return f == null || pc < 0 || pc >= f.size ? -1 : f.line[pc];
     }
 
-    String getSourceName() {
-        return f == null ? null : f.sourceName;
-    } 
+    String getSourceName() { return f == null ? null : f.sourceName; } 
     String getWhere(){ return getSourceName() + ":" + getLine(); }
 
     private JSExn je(String s) { return new JSExn(getWhere() + " " + s); }

Modified: 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/JSFunction.java
===================================================================
--- 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/JSFunction.java    
    2015-02-16 09:55:52 UTC (rev 4764)
+++ 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/JSFunction.java    
    2015-02-25 20:11:16 UTC (rev 4765)
@@ -49,7 +49,7 @@
     public JS apply(JS this_, JS[] args) throws JSExn{
        // UNIDEAL .. we are prevented from yielding after apply is called
        // (until it returns).
-       return Scheduler.findCurrent().runInCurrent(this, this_, args);
+       return Scheduler.expectCurrent().runInCurrent(this, this_, args);
     }
     
     public String[] getFormalArgs() { return f.formalArgs; }

Modified: branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/JSU.java
===================================================================
--- branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/JSU.java       
2015-02-16 09:55:52 UTC (rev 4764)
+++ branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/JSU.java       
2015-02-25 20:11:16 UTC (rev 4765)
@@ -248,7 +248,7 @@
 
     
     static public JS stackframe(int fromtop){
-        Interpreter cx = Scheduler.findCurrent().findCurrentInterpreter();
+        Interpreter cx = Scheduler.expectCurrent().expectCurrentInterpreter();
         // HACKish
         String sfLine = cx.stack.stackframe(fromtop);
         if(sfLine==null){

Modified: 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Scheduler.java
===================================================================
--- branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Scheduler.java 
2015-02-16 09:55:52 UTC (rev 4764)
+++ branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Scheduler.java 
2015-02-25 20:11:16 UTC (rev 4765)
@@ -4,6 +4,8 @@
 
 package org.ibex.js;
 
+import java.util.concurrent.CountDownLatch;
+
 import org.ibex.js.JS.Trap;
 import org.ibex.util.Basket;
 import org.ibex.util.Callable;
@@ -14,7 +16,7 @@
 /** Implements cooperative multitasking */
 public class Scheduler {
     static ThreadLocal threadlocal = new ThreadLocal();
-    static public Scheduler findCurrent() {
+    static public Scheduler expectCurrent() {
         Scheduler r = (Scheduler)threadlocal.get();
         if (r==null) {
             throw new Error("No current scheduler!");
@@ -108,7 +110,7 @@
                     current = (Callable)runnable.remove(true);
                     synchronized (this) {
                         //Log.debug(Scheduler.class, "performing " + current);
-                        current.run(null);
+                       current.run(null);                        
                     }
                     renderAll();
                 /*} catch (Stop e){
@@ -162,8 +164,9 @@
         jsthread = t;
     }
     
-    public void runInNew(JS function, JS[] args) throws JSExn {
-        add(new Thread(this, function, true, args));
+    public void runInNew(JS function) throws JSExn { runInNew(function, null, 
null); }
+    public void runInNew(JS function, JS[] args, Callable<Object, JS> 
callback) throws JSExn {
+        add(new Thread(this, "background", function, args, true, callback));
     }
     
     
@@ -172,11 +175,12 @@
         if (!(t.function() instanceof JSFunction)) {
             return t.function(); 
         }
+        JSFunction trapf = (JSFunction)t.function();
         
         // REMARK - isFirst <-> old == null?
         boolean isFirst = jsthread==null; 
         if (isFirst) {
-            setJSThread(new Thread(this, t.function(), false, null));
+            setJSThread(new Thread(this, "current/trap", trapf, null));
         }
         Interpreter old = jsthread.currentInterpreter;
         jsthread.currentInterpreter = new Interpreter(jsthread, t, null, 
false, null);
@@ -210,7 +214,7 @@
     /** Execute write traps, part 1 */
     public JS runBeforePut(Trap t, JS val, JS trapname) throws JSExn {
         if (jsthread==null) {
-            setJSThread(new Thread(this, t.function(), false, null));
+            setJSThread(new Thread(this, "current/trap/wpause", t.function(), 
null));
         }
         Interpreter I = new Interpreter(jsthread, t, val, true, trapname);
         // REMARK - this thread is unpausable, so setting this static variable
@@ -266,7 +270,7 @@
     /** Execute read traps, part 1 */
     public JS runBeforeGet(Trap t, JS trapname) throws JSExn {
         if (jsthread==null) {
-            setJSThread(new Thread(this, t.function(), false, null));
+            setJSThread(new Thread(this, "current/trap/rpause", t.function(), 
null));
         }
         Interpreter I = new Interpreter(jsthread, t, null, true, trapname);
         // REMARK - this thread is unpausable, so setting this static variable
@@ -304,7 +308,7 @@
         boolean isFirst = jsthread==null; 
         // FEATURE - reuse the thread object
         if (isFirst) {
-            setJSThread(new Thread(this, function, false, args));
+            setJSThread(new Thread(this, "current", function, args));
         }
         Interpreter old = jsthread.currentInterpreter;
         // Always false. Restarting paused nested Interpreters not supported.
@@ -319,6 +323,7 @@
             }
         }
     }
+
     
     /** Creates a thread that doesn't immediately execute JS
        (necessary for non-JS backtracing) */
@@ -327,7 +332,7 @@
             throw new JSExn("Something a miss"); 
         }
         // FEATURE - reuse the thread object
-        setJSThread(new Thread(this, null, false, null));
+        setJSThread(new Thread(this, "non-js", null, null));
         // REMARK - This interpreter is just used for its stack for
         // recording non-JS call entries (Box.apply) for backtracing later
         jsthread.currentInterpreter = new Interpreter(jsthread);
@@ -348,7 +353,7 @@
     
     /** Gets the value for a given key, triggering any read traps for the key. 
*/
     static public JS getAndTriggerTrapsNoScheduler(JS obj, JS key) throws 
JSExn {
-        return Scheduler.findCurrent().getAndTriggerTraps(obj,key);
+        return Scheduler.expectCurrent().getAndTriggerTraps(obj,key);
     }
 
     /** Simulates a put to the given key, triggering any write traps for the 
key
@@ -393,6 +398,12 @@
         return value;
     }
     
+    /** Make a background call from within a currently executing JS thread. It 
will halt execution
+     * and allow other threads to execute, and when the action has been 
completed it will reschedule
+     * execution of the halted thread.
+     * 
+     * @return always null
+     */
     public JS backgroundCall(final String what, final Callable<Object,JS> 
callable) throws JSExn{
         final Callable callback = pauseJSThread(what);
        new java.lang.Thread() {
@@ -409,6 +420,30 @@
        return null; // doesn't matter since we are paused
     }
     
+    public JS syncCall(JS function, JS[] args) throws JSExn, 
InterruptedException{
+       final CountDownLatch latch0 = new CountDownLatch(1); 
+       final Object[] retArr = new Object[1]; 
+       runInNew(function, args, new Callable<Object, JS>() {
+               public JS run(Object ret) throws Exception {
+                       retArr[0] = ret;
+                       latch0.countDown();
+                       return null;
+               }
+               });     
+       
+       latch0.await();
+       Object ret = retArr[0];
+       if(ret==null || ret instanceof JS){
+               return (JS)ret;
+       }else if(ret instanceof JSExn){
+               throw (JSExn)ret;
+       }else{
+               throw new JSExn((Throwable)ret);
+       }
+    }
+    
+    
+    
     public void scheduleJustTriggerTraps(final JS.Obj obj, final JS key, final 
JS value) {
         add(new Callable() {
             public Object run(Object o) throws Exception {
@@ -428,8 +463,8 @@
         });
     }
 
-    final private Basket.Array sleeperThreads = new Basket.Array();
-    final WakeupThread scheduleWakeUp = new WakeupThread(); 
+    static final private Basket.Array sleeperThreads = new Basket.Array();
+    static final WakeupThread scheduleWakeUp = new WakeupThread(); 
     
     /** cause the current (background only) thread to sleep for i ms */
     public void sleep(final int i) throws JSExn {
@@ -438,27 +473,29 @@
         if (i<0) {
             add(callback);
         } else {
-            scheduleWakeUp.insert(i, callback);
+            scheduleWakeUp.insert(this, i, callback);
         }    
     }
 
     /** encapsulates a sleeper thread and its desired wakeup time in 
milliseconds
      * @author Charles Goodwin */
     static final private class SleeperCallback {
+       final Scheduler scheduler;
         final long wakeupms;
         final Callable callback;
-        public SleeperCallback(int afterms, Callable callback) {
-            wakeupms = afterms + System.currentTimeMillis();
+        public SleeperCallback(Scheduler scheduler, int afterms, Callable 
callback) {
+               this.scheduler = scheduler;
+            this.wakeupms = afterms + System.currentTimeMillis();
             this.callback = callback;
         }
     }
 
     /** an internal mechanism for scheduling the wake up of sleeper threads
      * @author Charles Goodwin */
-    final class WakeupThread extends java.lang.Thread {
+    static final class WakeupThread extends java.lang.Thread {
         public WakeupThread() { super("WakeupThread"); start(); }
-        public void insert(int i, Callable callback) {
-            SleeperCallback t = new SleeperCallback(i, callback);
+        public void insert(Scheduler scheduler, int i, Callable callback) {
+            SleeperCallback t = new SleeperCallback(scheduler, i, callback);
             synchronized (this) {
                 // store sleeper threads in order of wake up time
                 for (int j=sleeperThreads.size(); j>=0; j--) {
@@ -495,7 +532,7 @@
                             if (t.wakeupms - System.currentTimeMillis() <= 0) {
                                 // nudge nudge wakey wakey
                                 sleeperThreads.remove(0);
-                                add(t.callback);
+                                t.scheduler.add(t.callback);
                             }
                         }
                     }
@@ -520,7 +557,7 @@
         }
         return jsthread.currentInterpreter;
     }
-    public Interpreter findCurrentInterpreter() {
+    public Interpreter expectCurrentInterpreter() {
         if (jsthread==null) {
             throw new RuntimeException("No current js thread"); 
         }

Modified: 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Thread.java
===================================================================
--- branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Thread.java    
2015-02-16 09:55:52 UTC (rev 4764)
+++ branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Thread.java    
2015-02-25 20:11:16 UTC (rev 4765)
@@ -17,26 +17,29 @@
  */
 
 public class Thread implements Callable {
-       
        //static int id_counter = 0;
        //int id = id_counter++;
 
-       Interpreter currentInterpreter; 
-       private JSFunction f;                   // Root function (id's thread)
-       private JS[] args;                      // Args passed to root function
-       private boolean pauseable;              // Is thread pausable or not.
+       final String type;
+       final private JSFunction f;           // Root function (id's thread)
+       final private JS[] args;              // Args passed to root function
+       final boolean pauseable;              // Is thread pausable or not.
        final Scheduler faction;
+       final Callable<Object,JS> callback;   // callback run when thread 
completes
        
+       Interpreter currentInterpreter; 
+       
+       
        /** Constructor */
-       Thread(Scheduler faction, JS f, boolean pauseable, JS[] args) throws 
JSExn { 
-               //if (f == null) {
-           //    throw new JSExn("attempted to create a null thread");
-           //}
+       Thread(Scheduler faction, String name, JS f, JS[] args) { this(faction, 
name, f, args, false, null); }
+       Thread(Scheduler faction, String type, JS f, JS[] args, boolean 
pauseable, Callable<Object,JS> callback)  {
+               this.type = type;
        this.faction = faction;
            this.f = (JSFunction)f;
        this.pauseable = pauseable;
        this.args = args==null?Constants.EMPTY_JS_ARRAY:args;
        faction.jsthreads.addElement(this);
+       this.callback = callback;
        //Log.info("thread created "+threadCount+"     "+id +"     "+ this);
        }
 
@@ -51,19 +54,40 @@
        }
        
        /** Execute JS code in the background. Method executed by scheduler.  
+        * @throws Exception 
         * @throws JSExn */
-       public Object run(Object o) throws JSExn {
+       public Object run(Object o) throws Exception  {
                faction.setJSThread(this);
                if (currentInterpreter==null) {
                        //First time this thread has been run (i.e. not paused 
or yielded yet)
                        currentInterpreter = new Interpreter(this, f, 
this.pauseable, args);
                }
                try {
-                       Object ret = this.currentInterpreter.run(o);
-                       return ret;
+                       JS ret = this.currentInterpreter.run(o);
+                       if(callback!=null && 
this.currentInterpreter.pausecount<=0) {
+                               callback.run(ret);
+                       }
+                       // if a result is desired then a callback must be used 
+                       return null;
+               } catch(JSExn e){
+                       if(callback!=null){
+                               callback.run(e);
+                               assert(this.currentInterpreter.pausecount<=0);
+                               return null;
+                       }else{
+                               throw e;
+                       }
+               } catch(Throwable e){
+                       // must call the callback as it could be a waiting 
thread
+                       if(callback!=null){
+                               callback.run(e);
+                       }
+                       if(e instanceof Exception) throw (Exception)e;
+                       if(e instanceof Error) throw (Error)e;
+                       throw new Error(e);             
                } finally {
                        if (this.currentInterpreter.pausecount<=0) {
-                           destroy();
+                               destroy();
                        } else {
                            faction.setJSThread(null);
                        }
@@ -72,9 +96,9 @@
        
        public String description() {
                if (f!=null) {
-                       return f.definedAt();
+                       return type+", "+f.definedAt();
                }
-               return "thread, f==null"; 
+               return type; 
        }
        
        public String toString() {

Modified: 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/parse/Function.java
===================================================================
--- 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/parse/Function.java
    2015-02-16 09:55:52 UTC (rev 4764)
+++ 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/parse/Function.java
    2015-02-25 20:11:16 UTC (rev 4765)
@@ -58,7 +58,7 @@
         return this;
     }
     
-    public String definedAt(){return sourceName + ":" + firstLine;};
+    public String definedAt(){return sourceName + ":" + firstLine;}
     // Debugging 
//////////////////////////////////////////////////////////////////////
 
 //    public String toString() {

Deleted: 
branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/JSDynProxy.java
===================================================================
--- 
branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/JSDynProxy.java    
    2015-02-16 09:55:52 UTC (rev 4764)
+++ 
branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/JSDynProxy.java    
    2015-02-25 20:11:16 UTC (rev 4765)
@@ -1,66 +0,0 @@
-package org.ibex.js;
-
-
-
-public class JSDynProxy extends JS.Obj {
-    /** fetches a write trap for property 'name' */
-    private Trap wtrap(JS name) {
-        Trap t = getTrap(name);  
-        return t==null?null:t.findWrite();
-    }
-    
-    /** fetches a read trap for property 'name' */
-    private Trap rtrap(JS name) {
-        Trap t = getTrap(name); 
-        return t==null?null:t.findRead();
-    }
-    
-       
-       public JS get(JS key) throws JSExn {
-        Trap rangeTrap = rtrap(SC_);
-        JSExn rangeTrapException = null;
-        JS value = null;   
-        try {
-            if (rangeTrap != null) {
-                value = Scheduler.findCurrent().runBeforeGet(rangeTrap, key);
-                key = Scheduler.findCurrent().cascadedTo;
-                // if null value returned, avoiding innermost cascade  
-                if (key == null) return value;
-            }
-            value = super.get(key);
-        } catch (JSExn e) {
-            rangeTrapException = e;
-            throw e;
-        } finally {
-            if (rangeTrap != null) {
-                // value in: cascaded back to the lowermost read trap
-                // value out: returned from the outer most read trap  
-                value = 
Scheduler.findCurrent().runAfterGet(value,rangeTrapException);
-            }
-        }
-        return value;
-       }
-       
-       
-       public void put(JS key, JS value) throws JSExn {
-       Trap rangeTrap = wtrap(SC_);
-        JSExn rangeTrapException = null;
-        try {
-            if (rangeTrap != null) {
-                value = Scheduler.findCurrent().runBeforePut(rangeTrap, value, 
key);
-                key = Scheduler.findCurrent().cascadedTo;
-                // returned from trap without cascading (cleaned up in finally 
clause)
-                if (key==null) return;
-            }
-            super.put(key,value);
-        } catch (JSExn e) {
-            rangeTrapException = e;
-            throw e;
-        } finally {
-            if (rangeTrap != null) {
-               Scheduler.findCurrent().runAfterPut(rangeTrapException);
-            }
-        }
-       }
-       
-}

Modified: 
branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/RunJS.java
===================================================================
--- branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/RunJS.java     
2015-02-16 09:55:52 UTC (rev 4764)
+++ branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/RunJS.java     
2015-02-25 20:11:16 UTC (rev 4765)
@@ -120,7 +120,7 @@
                JS export = new JS.Obj();
                JSFunction f = prepareRun(fileName, export);
                SCHEDULER = new Scheduler(LOG, true);
-               SCHEDULER.runInNew(f, null);
+               SCHEDULER.runInNew(f);
                Exception e = (Exception) SCHEDULER.run();
                if(e!=null)
                        throw e;
@@ -346,7 +346,7 @@
                public void put(JS jskey, JS val) throws JSExn {
                        String key = JSU.toString(jskey);
                        if("thread".equals(key)) {
-                               SCHEDULER.runInNew(val,null);
+                               SCHEDULER.runInNew(val);
                                return;
                        }
                        /*
@@ -386,7 +386,7 @@
                        }
                        if("line".equals(methName)) {
                                // TODO reimplement this
-                               Interpreter I = 
SCHEDULER.findCurrentInterpreter();
+                               Interpreter I = 
SCHEDULER.expectCurrentInterpreter();
                                return JSU.N(I.f.line[I.pc]);
                        }
                        if("import".equals(methName)){
@@ -400,11 +400,12 @@
                                        return  new JSRegexp(args[0], args[1]);
                        }
                        if("pause".equals(methName)){
-                   final Callable callback = SCHEDULER.pauseJSThread("pause");
-                   new java.lang.Thread() { public void run() { 
-                       System.out.println("in pause"); 
-                       SCHEDULER.schedule(callback, null);
-                   }}.start();
+                               SCHEDULER.backgroundCall("pause", new 
Callable<Object, JS>() {
+                                       public JS run(Object A) throws 
Exception {
+                                               System.out.println("in pause"); 
+                               return null;
+                                       }
+                               });                 
                        }
             if( "xmlrpc".equals(methName)){
                return new XMLRPC(LOG, JSU.toString(args[0]), "");

Modified: branches/vexi3/org.vexi-library.js/src/test/java/test/js/TestJS.java
===================================================================
--- branches/vexi3/org.vexi-library.js/src/test/java/test/js/TestJS.java        
2015-02-16 09:55:52 UTC (rev 4764)
+++ branches/vexi3/org.vexi-library.js/src/test/java/test/js/TestJS.java        
2015-02-25 20:11:16 UTC (rev 4765)
@@ -12,6 +12,7 @@
 
 import test.js.exec.TestExec;
 import test.js.parse.TestParse;
+import test.js.threading.TestJSThreading;
 
 public class TestJS{
        
@@ -25,6 +26,7 @@
        suite.addTest(TestExec.suite());
        suite.addTest(JUnitUtil.suiteJava(TestParse.class));
        suite.addTest(TestClasses.suite());
+       suite.addTest(JUnitUtil.suiteJava(TestJSThreading.class));
        return suite;
     }
 }

Added: 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/AssertionUtil.java
===================================================================
--- 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/AssertionUtil.java
                               (rev 0)
+++ 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/AssertionUtil.java
       2015-02-25 20:11:16 UTC (rev 4765)
@@ -0,0 +1,99 @@
+package test.js.threading;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+public class AssertionUtil {
+       static boolean shorterrors = true;
+       
+       static public String join(String... ss){ return 
join(Arrays.asList(ss)); }
+       
+       static public String join(Iterable<String> ss){
+               StringBuilder sb = new StringBuilder();
+               boolean first = true;
+               for(String s: ss){
+                       if(first) first = false;
+                       else sb.append(",");
+                       sb.append(s);
+               }
+               return sb.toString();
+       }
+       
+       static public String fromList(Iterable l){
+               if(!(l instanceof SortedSet)){
+                       Collection l1 = new TreeSet();
+                       for(Object o: l){
+                               l1.add(""+o);
+                       }
+                       l = l1;
+               }
+               return fromList((Collection)l);         
+       }
+               
+       static public String fromList(Collection l0){
+               // REMARK 
+               // The dilema here is e.g. importing code where 100s of lines 
may have mismatches
+               // of 1000s of items. Really we don't want to create such long 
stack traces in these cases.  
+               int max = shorterrors?50:1000;
+               Collection l;
+               if(!(l0 instanceof SortedSet)){
+                       Collection l1 = new TreeSet();
+                       int i=0;
+                       for(Object o: l0){
+                               l1.add(""+o);
+                               i++;
+                               if(i>max) break;
+                       }
+                       l = l1;
+               }else{
+                       l = l0;
+               }
+               
+               StringBuilder r = new StringBuilder();
+               int i=0;
+               for(Object o: l){
+                       if(i<max){
+                       r.append("\n    "+o);
+                       }else{
+                               r.append("\n    [first "+max+" out of 
"+l0.size()+" shown]");
+                       }
+                       i++;                    
+               }
+               if(r.length()==0){
+                       r.append("\n    [no choices]");
+               }
+               
+               return r.toString();
+       }
+
+    static private AssertionError mismatch(Set<String> expectedKeys, 
Set<String> actualKeys, Set<String> optionalKeys) {
+       Set<String> missingKeys = new HashSet(expectedKeys);
+               missingKeys.removeAll(actualKeys);
+               missingKeys.removeAll(optionalKeys);
+               Set<String> unexpectedKeys = new HashSet(actualKeys);
+               unexpectedKeys.removeAll(expectedKeys);
+               unexpectedKeys.removeAll(optionalKeys);
+               
+               String s = "Incompatible props sent.";
+               if(missingKeys.size()>0) s+= "\nMissing properties: " + 
fromList(missingKeys);
+               if(unexpectedKeys.size()>0) {
+                       s+= "\nUnexpected properties: " + 
fromList(unexpectedKeys);
+                       s+= "\nOptional properties: " + fromList(optionalKeys); 
                
+               }
+               throw new AssertionError(s);
+       }
+       
+    static public void assertExpected(Set<String> expectedKeys, Set<String> 
actualKeys, Set<String> optionalKeys) {
+       if(!actualKeys.containsAll(expectedKeys))
+               throw mismatch(expectedKeys, actualKeys, optionalKeys);
+       int c=0;
+       for(String s: optionalKeys){
+               if(actualKeys.contains(s)) c++;
+       }
+       if(actualKeys.size()!=expectedKeys.size()+c) throw 
mismatch(expectedKeys, actualKeys, optionalKeys);
+    }
+}


Property changes on: 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/AssertionUtil.java
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/Scripting.java
===================================================================
--- 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/Scripting.java
                           (rev 0)
+++ 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/Scripting.java
   2015-02-25 20:11:16 UTC (rev 4765)
@@ -0,0 +1,94 @@
+package test.js.threading;
+
+import java.io.Reader;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.ibex.js.ExecParser;
+import org.ibex.js.JS;
+import org.ibex.js.JSExn;
+import org.ibex.js.JSFunction;
+import org.ibex.js.JSON;
+import org.ibex.js.JSU;
+import org.ibex.js.Scheduler;
+import org.ibex.js.parse.Function;
+import org.ibex.js.standard.Global;
+import org.ibex.util.Callable;
+import org.ibex.util.DefaultLog;
+
+
+public class Scripting{
+
+       
+       final public Set<String> logged = new LinkedHashSet(); 
+       private JSFunction method;
+       
+       final JS LOG = new JS.Immutable(){
+               public void put(JS key, JS value) throws JSExn {
+                       logged.add(JSU.toString(key));
+               };
+       };
+    final JS TESTOBJ = new JS.Immutable(){
+               @Override public void put(JS keyJS, JS val) throws JSExn {
+                       String key = JSU.toString(keyJS);
+                       if("method".equals(key)){
+                               method = (JSFunction)val;
+                       }else{
+                               super.put(keyJS, val);
+                       }
+               }
+    };
+       final JS GLOBAL =       new Global() {
+               @Override public JS get(JS arg) throws JSExn {
+                       String key = JSU.toString(arg);
+                       if("pause".equals(key))    return METHOD;
+                       if("print".equals(key))    return METHOD;
+                       if("LOG".equals(key))      return LOG;
+            if("TESTOBJ".equals(key)) return TESTOBJ;
+                       return super.get(arg);
+               }               
+               @Override public JS callMethod(JS this_, JS method, JS[] args) 
throws JSExn {
+                       String key = JSU.toString(method);
+                       if("print".equals(key)){
+                               System.err.println(JSON.marshal(args[0]));
+                               return null;
+                       }else if("pause".equals(key)){
+                               SCHEDULER.backgroundCall("pause", new 
Callable<Object, JS>() {
+                                       public JS run(Object A) throws 
Exception {
+                                               System.out.println("in pause"); 
+                               return null;
+                                       }
+                               });
+                               return null;
+                       }
+                       return super.callMethod(this_, method, args);
+               }       
+       };
+    
+       
+       final Scheduler SCHEDULER;
+       public Scripting() {
+               SCHEDULER = new Scheduler(DefaultLog.logger, true);
+               SCHEDULER.incForceActive();
+               new java.lang.Thread(new Runnable(){
+                       public void run() {     
+                               SCHEDULER.run(); 
+                               System.err.println("Exiting...");
+                       }
+               },"Scripting").start();
+       }
+       
+       
+       public void run(final String name, final Reader reader) throws 
Exception{
+               final Function f = ExecParser.parse(name, 0, reader);
+               final JSFunction run = JSU.cloneWithNewGlobalScope(f, GLOBAL);
+               SCHEDULER.syncCall(run, null);
+       }
+
+       public JS callMethod(boolean throwexn) throws Exception {
+               if(method==null){
+                       throw new Exception("method not initialised");
+               }
+               return SCHEDULER.syncCall(method, new JS[]{JSU.B(throwexn)});
+       }
+}


Property changes on: 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/Scripting.java
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/TestJSThreading.java
===================================================================
--- 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/TestJSThreading.java
                             (rev 0)
+++ 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/TestJSThreading.java
     2015-02-25 20:11:16 UTC (rev 4765)
@@ -0,0 +1,69 @@
+package test.js.threading;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.ibex.js.Fountain;
+import org.ibex.js.JSExn;
+import org.ibex.js.JSTestUtil;
+import org.ibex.js.JSU;
+
+
+public class TestJSThreading extends TestCase{
+
+       static public void main(String[] args) throws Exception {
+               TestJSThreading test = new TestJSThreading();
+               test.setUp();
+               test.testSyncCall();
+       }
+       
+       final Fountain jspath;
+       private Scripting scripting;
+       
+       public TestJSThreading(){
+               jspath = JSTestUtil.getResourceFountain(TestJSThreading.class, 
".js");
+       }
+
+    
+       
+       void assertLogged(String  expect){
+               Assert.assertEquals(expect, 
AssertionUtil.join(scripting.logged));
+       }
+       
+       @Override protected void setUp() throws Exception {
+               if(scripting==null){
+                       scripting = new Scripting();
+                       InputStream is = 
((Fountain)jspath.get(JSU.S("script.js"))).getInputStream(true);
+                       Reader reader = new InputStreamReader(is);
+                       scripting.run("script.js", reader);
+               }
+               scripting.logged.clear();
+       }
+       
+       void printLogged(){
+               System.err.println("Logged Actions:-");
+               for(String k: scripting.logged){
+                       System.err.println(" "+k);
+               }
+       }
+       
+       
+       public void testSyncCall() throws Exception{
+               scripting.callMethod(false);
+               assertLogged("method1,method2,method3");
+               
+               try{
+                       scripting.callMethod(true);
+                       fail("Expected exn");
+               }catch(JSExn e){
+                       assertEquals("JSExn: exn",e.getMessage());
+                       assertLogged("method1,method2,method3");                
        
+               }
+               
+               printLogged();
+       }
+}


Property changes on: 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/TestJSThreading.java
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/script.js
===================================================================
--- 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/script.js    
                            (rev 0)
+++ 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/threading/script.js    
    2015-02-25 20:11:16 UTC (rev 4765)
@@ -0,0 +1,17 @@
+
+
+TESTOBJ.method = function(throwexn){
+   LOG.method1 = true;     
+   pause();
+   LOG.method2 = true;     
+   try{
+          if(throwexn){
+              throw "exn";
+          }else{
+              return "done";
+          }   
+   }finally{
+       LOG.method3 = true;        
+   }  
+};
+print("setup");

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Dive into the World of Parallel Programming The Go Parallel Website, sponsored
by Intel and developed in partnership with Slashdot Media, is your hub for all
things parallel software development, from weekly thought leadership blogs to
news, videos, case studies, tutorials and more. Take a look and join the 
conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Vexi-svn mailing list
Vexi-svn@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/vexi-svn

Reply via email to