2003/06/10 21:45:35
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:00:59 +0000 (07:00 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:00:59 +0000 (07:00 +0000)
darcs-hash:20040130070059-2ba56-7e1298d971a0048f63d0e9c1bdb200b3f69f13d0.gz

13 files changed:
src/org/xwt/Box.java
src/org/xwt/ByteStream.java
src/org/xwt/Main.java
src/org/xwt/Resources.java
src/org/xwt/SpecialBoxProperty.java
src/org/xwt/Template.java
src/org/xwt/Trap.java
src/org/xwt/XMLRPC.java
src/org/xwt/XWT.java
src/org/xwt/js/ByteCodeBlock.java
src/org/xwt/js/ByteCodes.java
src/org/xwt/js/Context.java [new file with mode: 0644]
src/org/xwt/js/JS.java

index a18d888..cba4f14 100644 (file)
@@ -268,7 +268,7 @@ public final class Box extends JS.Scope {
 
     /** a trivial private class to serve as the box.indexof function object */
     private class IndexOf extends JS.Function {
-        public IndexOf() { this.setSeal(true); }
+        public IndexOf() { super(-1, "java", null, null); this.setSeal(true); }
         public Object _call(JS.Array args) throws JS.Exn {
             if (args.length() != 1 || args.elementAt(0) == null || !(args.elementAt(0) instanceof Box)) return new Integer(-1);
             Box b = (Box)args.elementAt(0);
@@ -460,7 +460,7 @@ public final class Box extends JS.Scope {
                             if (ret != -1) bytesDownloaded += ret;
                             if (clear && callback != null) {
                                 clear = false;
-                                ThreadMessage.newthread(new JS.Function() {
+                                ThreadMessage.newthread(new JS.Function(-1, "java", null, null) {
                                         public Object _call(JS.Array args_) throws JS.Exn {
                                             try {
                                                JS.Array args = new JS.Array();
@@ -1236,7 +1236,8 @@ public final class Box extends JS.Scope {
 
         if (name.charAt(0) == '_') {
             if (value != null && !(value instanceof Function)) {
-                if (Log.on) Log.log(this, "attempt to put a non-function value to " + name + " at " + JS.getFileAndLine());
+                if (Log.on) Log.log(this, "attempt to put a non-function value (" + value + ") to " +
+                                   name + " at " + JS.getFileAndLine());
             } else if (name.charAt(1) == '_') {
                 name = name.substring(2).intern();
                 Trap t = Trap.getTrap(this, name);
index 5aa8526..004c2a3 100644 (file)
@@ -101,14 +101,14 @@ public class ByteStream extends JS.Obj {
         os.close();
     }
 
-    private final JS.Function getDOM = new JS.Function() {
+    private final JS.Function getDOM = new JS.Function(-1, "java", null, null) {
             public Object _call(JS.Array args) throws JS.Exn {
                 if (args.length() != 0) return null;
                 return new XMLHelper().doParse();
             }
         };
 
-    private final JS.Function getUTF = new JS.Function() {
+    private final JS.Function getUTF = new JS.Function(-1, "java", null, null) {
             public Object _call(JS.Array args) throws JS.Exn {
                 if (args.length() != 0) return null;
                 try {
index 5b78775..a29af2e 100644 (file)
@@ -102,7 +102,7 @@ public class Main {
             
             if (Log.on) Log.log(Main.class, "instantiating " + initialTemplate);
             final String initialTemplate_f = initialTemplate;
-            ThreadMessage.newthread(new JS.Function() {
+            ThreadMessage.newthread(new JS.Function(-1, "java", null, null) {
                     public Object _call(JS.Array args) throws JS.Exn {
                         new Box(initialTemplate_f, null);
                        doneInitializing = true;
index a152bf8..be4eb99 100644 (file)
@@ -86,7 +86,7 @@ public class Resources {
                     int ret = super.read(b, off, len);
                     if (clear && callback != null) {
                         clear = false;
-                        ThreadMessage.newthread(new JS.Function() {
+                        ThreadMessage.newthread(new JS.Function(-1, "java", null, null) {
                                 public Object _call(JS.Array args_) throws JS.Exn {
                                     try {
                                        JS.Array args = new JS.Array();
index c2b52b5..00f43db 100644 (file)
@@ -689,7 +689,7 @@ class SpecialBoxProperty {
     public static class Apply extends JS.Function {
 
         Box b;
-        public Apply(Box b) { this.b = b; }
+        public Apply(Box b) { super(-1, "java", null, null); this.b = b; }
 
         public Object _call(JS.Array args) throws JS.Exn {
 
@@ -712,7 +712,7 @@ class SpecialBoxProperty {
             } else if (args.elementAt(0) instanceof JS && !(args.elementAt(0) instanceof Box)) {
                 JS s = (JS)args.elementAt(0);
                 Object[] keys = s.keys();
-                for(int j=0; j<keys.length; j++) b.put(keys[j].toString(), s);
+                for(int j=0; j<keys.length; j++) b.put(keys[j].toString(), s.get(keys[j]));
             }
 
             return b;
index 1fbe9ce..4022c42 100644 (file)
@@ -73,10 +73,10 @@ public class Template {
     private boolean changed = false;
 
     /** the script on the static node of this template, null if it has already been executed */
-    private JS.Script staticscript = null;
+    private JS.Function staticscript = null;
 
     /** the script on this node */
-    private JS.Script script = null;
+    private JS.Function script = null;
 
     /** during XML parsing, this holds the list of currently-parsed children; null otherwise */
     private Vec childvect = new Vec();
@@ -206,9 +206,7 @@ public class Template {
         if (redirect != null && !"self".equals(redirect)) redir = (Box)b.get("$" + redirect);
 
         if (script != null) try {
-           JS.Array jsa = new JS.Array();
-           jsa.addElement(b);
-            script.call(jsa);
+            script.cloneWithNewParentScope(b).call(new JS.Array());
         } catch (JS.Exn e) {
             if (Log.on) Log.log(this, "WARNING: uncaught ecmascript exception: " + e.getMessage());
         }
@@ -365,7 +363,7 @@ public class Template {
         if (staticscript != null) try { 
             JS.Scope s = Static.createStatic(nodeName, false);
             if (staticscript != null) {
-                JS.Script temp = staticscript;
+                JS.Function temp = staticscript;
                 staticscript = null;
 
                // we layer a transparent scope over the Static so that we can catch requests for the xwt object
@@ -376,9 +374,7 @@ public class Template {
                            if ("xwt".equals(key)) return XWT.singleton; else return super.get(key);
                        } };
 
-               JS.Array args = new JS.Array();
-               args.addElement(varScope);
-                temp.call(args);
+               temp.cloneWithNewParentScope(varScope).call(null);
             }
         } catch (JS.Exn e) {
             if (Log.on) Log.log(this, "WARNING: uncaught ecmascript exception: " + e.getMessage());
@@ -654,10 +650,10 @@ public class Template {
             }
         }
 
-        private JS.Script genscript(boolean isstatic) {
-            JS.Script thisscript = null;
+        private JS.Function genscript(boolean isstatic) {
+            JS.Function thisscript = null;
             try {
-                thisscript = JS.Script.parse(new StringReader(t.content.toString()), t.nodeName + (isstatic ? "._" : ""), t.content_start);
+                thisscript = JS.parse(new StringReader(t.content.toString()), t.nodeName + (isstatic ? "._" : ""), t.content_start);
             } catch (JS.Exn ee) {
                 if (Log.on) Log.log(this, "  ERROR: " + ee.getMessage());
                 thisscript = null;
index 770ad51..1ce4289 100644 (file)
@@ -119,7 +119,7 @@ public class Trap {
     /** Called by Rhino's arguments.cascade. Note: cx will be null if this was invoked from perform() rather than from a script. */
     public static final CascadeFunction cascadeFunction = new CascadeFunction();
     private static class CascadeFunction extends JS.Function {
-        CascadeFunction() { setSeal(true); }
+        CascadeFunction() { super(-1, "java", null, null); setSeal(true); }
         public Object _call(JS.Array args) { return _call(args, JS.getCurrentFunction()); }
         public Object _call(JS.Array args, Function currentFunction) {
             Trap currentTrap = TrapContext.get().currentTrap;
@@ -177,13 +177,7 @@ public class Trap {
                 return ret;
             }
             
-           System.out.println("calling trap on " + name);
-           Object ret = null;
-           try {
-               ret = f._call(args);
-           } catch (org.xwt.js.ByteCodeBlock.ReturnException re) {
-               ret = re.retval;
-           }
+           Object ret = f.call(args);
            
             // autocascade if required
             if (args.length() > 0 && !isreadtrap && !tc.putCascadeHappened) cascadeFunction._call(args, f);
index 27bfcc5..f2e8eee 100644 (file)
@@ -395,6 +395,7 @@ class XMLRPC extends JS.Function {
     }
 
     public XMLRPC(String url, String methodname, HTTP http) {
+       super(-1, "java", null, null);
         this.http = http;
         this.url = url;
         this.methodname = methodname;
index cb18679..ed8feb1 100644 (file)
@@ -57,63 +57,65 @@ public final class XWT extends JS.Obj {
         put("tempDir", System.getProperty("java.io.tempdir"));
 
        put("math", new JS.Obj() { public Object get(Object name) {
-           if ("ceil".equals(name)) return new JS.Function() { public Object _call(JS.Array args)
+           if ("ceil".equals(name)) return new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args)
                    { if (args.elementAt(0) == null) return null;
                    return new Long((long)Math.ceil(Double.parseDouble(args.elementAt(0).toString()))); } };
-           else if ("floor".equals(name)) return new JS.Function() { public Object _call(JS.Array args)
+           else if ("floor".equals(name)) return new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args)
                    { if (args.elementAt(0) == null) return null;
                        return new Long((long)Math.floor(Double.parseDouble(args.elementAt(0).toString()))); } };
-           else if ("round".equals(name)) return new JS.Function() { public Object _call(JS.Array args)
+           else if ("round".equals(name)) return new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args)
                    { if (args.elementAt(0) == null) return null;
                        return new Long((long)Math.round(Double.parseDouble(args.elementAt(0).toString()))); } };
-           else if ("abs".equals(name)) return new JS.Function() { public Object _call(JS.Array args)
+           else if ("abs".equals(name)) return new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args)
                    { if (args.elementAt(0) == null) return null;
                        return new Long((long)Math.abs(Double.parseDouble(args.elementAt(0).toString()))); } };
-           else if ("min".equals(name)) return new JS.Function() { public Object _call(JS.Array args) {
+           else if ("min".equals(name)) return new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) {
                if (args.length() < 2 || args.elementAt(0) == null || args.elementAt(1) == null) return args.elementAt(0);
                return new Double(Math.min(((Number)args.elementAt(0)).doubleValue(),
                                           ((Number)args.elementAt(1)).doubleValue())); } };
-           else if ("max".equals(name)) return new JS.Function() { public Object _call(JS.Array args) {
+           else if ("max".equals(name)) return new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) {
                if (args.length() < 2) return args.elementAt(0);
                return new Double(Math.max(((Number)args.elementAt(0)).doubleValue(),
                                           ((Number)args.elementAt(1)).doubleValue())); } };
-           else if ("cos".equals(name)) return new JS.Function() { public Object _call(JS.Array args) {
+           else if ("cos".equals(name)) return new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) {
                return new Double(Math.cos(((Number)args.elementAt(0)).doubleValue())); } };
-           else if ("sin".equals(name)) return new JS.Function() { public Object _call(JS.Array args) {
+           else if ("sin".equals(name)) return new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) {
                return new Double(Math.sin(((Number)args.elementAt(0)).doubleValue())); } };
-           else if ("tan".equals(name)) return new JS.Function() { public Object _call(JS.Array args) {
+           else if ("tan".equals(name)) return new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) {
                return new Double(Math.tan(((Number)args.elementAt(0)).doubleValue())); } };
-           else if ("acos".equals(name)) return new JS.Function() { public Object _call(JS.Array args) {
+           else if ("acos".equals(name)) return new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) {
                return new Double(Math.acos(((Number)args.elementAt(0)).doubleValue())); } };
-           else if ("asin".equals(name)) return new JS.Function() { public Object _call(JS.Array args) {
+           else if ("asin".equals(name)) return new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) {
                return new Double(Math.asin(((Number)args.elementAt(0)).doubleValue())); } };
-           else if ("atan".equals(name)) return new JS.Function() { public Object _call(JS.Array args) {
+           else if ("atan".equals(name)) return new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) {
                return new Double(Math.atan(((Number)args.elementAt(0)).doubleValue())); } };
+           else if ("sqrt".equals(name)) return new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) {
+               return new Double(Math.sqrt(((Number)args.elementAt(0)).doubleValue())); } };
            return null;
        }});
 
-       put("newBrowserWindow", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("newBrowserWindow", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args.length() != 1 || args.elementAt(0) == null) return null;
            Platform.newBrowserWindow(args.elementAt(0).toString());
            return null;
        }});
 
-       put("parseFloat", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("parseFloat", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args.length() != 1 || args.elementAt(0) == null) return null;
            return new Float(args.elementAt(0).toString());
        }});
 
-       put("parseInt", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("parseInt", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args.length() != 1 || args.elementAt(0) == null) return null;
            return new Float(args.elementAt(0).toString());
        }});
 
-       put("yield", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("yield", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            sleep(0);
            return null;
        }});
 
-       put("theme", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("theme", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
                if (args.length() != 2) return null;
                if (args.elementAt(0) == null || args.elementAt(1) == null) return null;
                for(int i=1; i<args.length(); i++) {
@@ -131,38 +133,38 @@ public final class XWT extends JS.Obj {
                return null;
        }});
            
-       put("println", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("println", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args.length() != 1) return null;
            if (Log.on) Log.log(this, JS.getFileAndLine() + " " +
                                (args.elementAt(0) == null ? "**null**" : args.elementAt(0).toString()));
            return null;
        }});
 
-       put("date", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("date", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            Log.log(XWT.class, "date not implemented");
            //throw new Error("not implemented");
            return null;
         }});
 
-       put("regexp", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("regexp", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            //throw new Error("not implemented");
            Log.log(XWT.class, "regexp not implemented");
            return null;
        }});
 
-       put("listfonts", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("listfonts", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            Object[] fonts = Platform.listFonts();
            JS.Array ret = new JS.Array();
            for(int i=0; i<fonts.length; i++) ret.addElement(fonts[i]);
            return ret;
        }});
 
-       put("xmlrpc", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("xmlrpc", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args.length() != 1 || args.elementAt(0) == null) return null;
            return new XMLRPC(args.elementAt(0).toString(), "");
        }});
 
-       put("soap", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("soap", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args.length() == 1 && args.elementAt(0) != null) return new SOAP(args.elementAt(0).toString(), "", null, null);
            else if (args.length() == 2 && args.elementAt(0) != null && args.elementAt(1) != null)
                return new SOAP(args.elementAt(0).toString(), "", args.elementAt(1).toString(), null);
@@ -171,7 +173,7 @@ public final class XWT extends JS.Obj {
            else return null;
        }});
 
-       put("textwidth", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("textwidth", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args.length() < 1 || args.length() > 2) return null;
            if (args.elementAt(0) == null || (args.length() == 2 && args.elementAt(1) == null)) return null;
            String font = args.length() == 1 ? Platform.getDefaultFont() : args.elementAt(0).toString();
@@ -181,7 +183,7 @@ public final class XWT extends JS.Obj {
            else return new Integer(xwf.stringWidth(text));
        }});
 
-       put("textheight", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("textheight", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args.length() > 1) return null;
            if (args.length() == 1 && args.elementAt(0) == null) return null;
            String font = args.length() == 0 || args.elementAt(0) == null ? Platform.getDefaultFont() : args.elementAt(0).toString();
@@ -190,7 +192,7 @@ public final class XWT extends JS.Obj {
            else return new Integer(xwf.getMaxAscent() + xwf.getMaxDescent());
        }});
        
-       put("newBox", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("newBox", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args.length() > 0) Log.log(XWT.class, "DEPRECATED: xwt.newBox() with multiple arguments is deprecated; use xwt.newBox().apply()");
            JS.Function callback = null;
            for(int i=1; i<args.length(); i++)
@@ -210,20 +212,20 @@ public final class XWT extends JS.Obj {
            return ret;
        }});
 
-       put("sleep", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("sleep", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args != null && (args.length() != 1 || args.elementAt(0) == null)) return null;
            int i = args == null ? 0 : SpecialBoxProperty.stoi(args.elementAt(0).toString());
            sleep(i);
            return null;
        }});
 
-       put("openFile", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("openFile", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args.length() != 1) return null;
            String file = Platform.fileDialog(args.elementAt(0).toString(), false);
            return file == null ? null : new ByteStream(file);
        }});
 
-       put("saveFile", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("saveFile", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args.length() != 2) return null;
            if (!(args.elementAt(1) instanceof ByteStream)) return null;
            String file = args.elementAt(0).toString();
@@ -242,7 +244,7 @@ public final class XWT extends JS.Obj {
            }
        }});
 
-       put("saveFileAs", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("saveFileAs", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args.length() != 2) return null;
            if (!(args.elementAt(1) instanceof ByteStream)) return null;
            String file = args.elementAt(0).toString();
@@ -259,12 +261,12 @@ public final class XWT extends JS.Obj {
            }
        }});
 
-       put("utfEncode", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("utfEncode", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
            if (args == null || args.length() != 1) return null;
            return new ByteStream(args.elementAt(0).toString().getBytes());
        }});
 
-       put("parseHTML", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+       put("parseHTML", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
                 if (args == null || args.length() != 1 || args.elementAt(0) == null) return null;
                 try {
                     if (args.elementAt(0) instanceof ByteStream) {
@@ -280,13 +282,13 @@ public final class XWT extends JS.Obj {
             }
         });
     
-    put("recursivePrintObject", new JS.Function() { public Object _call(JS.Array args) {
+    put("recursivePrintObject", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) {
        if (args.length() != 1) return null;
        recurse("", "", args.elementAt(0));
        return null;
     }});
 
-    put("loadArchive", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+    put("loadArchive", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
        if (!ThreadMessage.suspendThread()) return null;
        try {
            if (args == null || args.length() < 1 || args.elementAt(0) == null) return null;
@@ -345,7 +347,7 @@ public final class XWT extends JS.Obj {
        return null;
     }});
 
-    put("prefetchImage", new JS.Function() { public Object _call(JS.Array args) throws JS.Exn {
+    put("prefetchImage", new JS.Function(-1, "java", null, null) { public Object _call(JS.Array args) throws JS.Exn {
        if (args == null || args.length() < 1 || args.elementAt(0) == null) return null;
        Box.getImage(args.elementAt(0).toString(),
                     args.length() > 1 && args.elementAt(1) instanceof JS.Function ? (JS.Function)args.elementAt(1) : null);
index 54b8169..9cd3f0e 100644 (file)
@@ -39,9 +39,9 @@ public class ByteCodeBlock implements ByteCodes, Tokens {
         return this;
     }
         
-    public Object eval(final JS.Scope s, Vec t) throws ControlTransferException {
-
-        for(int i=0; i<size; i++) {
+    public void eval(JS.Scope s) throws ControlTransferException {
+       Vec t = Context.getContextForCurrentThread().stack;
+        OUTER: for(int i=0; i<size; i++) {
            switch(op[i]) {
             case LABEL: break;
             case LITERAL: t.push(arg[i]); break;
@@ -56,19 +56,26 @@ public class ByteCodeBlock implements ByteCodes, Tokens {
             case SWAP: { Object o1 = t.pop(); Object o2 = t.pop(); t.push(o1); t.push(o2); break; }
             case DUP: t.push(t.peek()); break;
 
-               // FIXME: shouldn't need its own stack
-            case SCOPE: t.push(((ByteCodeBlock)arg[i]).eval(new JS.Scope(s), new Vec())); break;
+            case PUSHSCOPE: s = new JS.Scope(s); break;
+           case POPSCOPE: s = s.getParentScope(); break;
 
             case ASSERT: if (!JS.toBoolean(t.pop())) throw new EvaluatorException(line, sourceName, "assertion failed"); break;
-            case RETURN: throw new ReturnException(t.pop());
+            case RETURN: {
+               Object retval = t.pop();
+               while(t.size() > 0) {
+                   Object o = t.pop();
+                   if (o != null && o instanceof Context.CallMarker) {
+                       t.push(retval);
+                       return;
+                   }
+               }
+               throw new Error("error: RETURN invoked but couldn't find a CallMarker!");
+           }
+
             case THROW: throw new JS.Exn(t.pop());
             case TRY: break;
+            case TYPEOF: break;   // FIXME: implement
 
-               // FIXME: implement
-            case TYPEOF: break;
-
-            case BREAK: return Boolean.FALSE;
-            case CONTINUE: return Boolean.TRUE;
             case BITNOT: t.push(new Long(~JS.toLong(t.pop()))); break;
             case BANG: t.push(new Boolean(!JS.toBoolean(t.pop()))); break;
 
@@ -89,29 +96,65 @@ public class ByteCodeBlock implements ByteCodes, Tokens {
             }
 
             case LOOP: {
+               t.push(s);
+               t.push(new Context.LoopMarker(i));
+               t.push(Boolean.TRUE);
+               break;
+           }
+
+            case BREAK:
+           case CONTINUE:
+               while(t.size() > 0) {
+                   Object o = t.pop();
+                   if (o != null && o instanceof Context.LoopMarker) {
+                       int loopInstructionLocation = ((Context.LoopMarker)o).location;
+                       int endOfLoop = ((Integer)arg[loopInstructionLocation]).intValue() + loopInstructionLocation;
+                       s = (JS.Scope)t.pop();
+                       if (op[i] == CONTINUE) { t.push(s); t.push(o); t.push(Boolean.FALSE); }
+                       i = op[i] == BREAK ? endOfLoop - 1 : loopInstructionLocation;
+                       continue OUTER;
+                   }
+               }
+               throw new Error("CONTINUE/BREAK invoked but couldn't find a LoopMarker at " + sourceName + ":" + line);
+
+               /*
                 ByteCodeBlock loop = (ByteCodeBlock)arg[i];
                 Vec stack2 = new Vec();
-                stack2.push(Boolean.TRUE);
-                while (true) {
-                    Boolean result;
-                   try { result = (Boolean)loop.eval(new JS.Scope(s), stack2);
-                    } catch (ContinueException c) { result = Boolean.TRUE;
-                    } catch (BreakException b) { result = Boolean.FALSE; }
-                    if (result == Boolean.FALSE) break;
-                    stack2 = new Vec();
-                    stack2.push(Boolean.FALSE);
-                }
+               Context cur = Context.getContextForCurrentThread();
+               boolean first = true;
+               try {
+                   while (true) {
+                       Boolean result;
+                       try {
+                           Context cx = new Context();
+                           cx.bindToCurrentThread();
+                           cx.stack.push(new Boolean(first));
+                           loop.eval(new JS.Scope(s));
+                           result = (Boolean)cx.stack.pop();
+                       } catch (ContinueException c) { result = Boolean.TRUE;
+                       } catch (BreakException b) { result = Boolean.FALSE;
+                       }
+                       first = false;
+                       if (result == Boolean.FALSE) break;
+                   }
+               } finally {
+                   cur.bindToCurrentThread();
+               }
                 break;
             }
+               */
 
             case PUT: {
                 Object val = t.pop();
                 Object key = t.pop();
-                JS target = (JS)t.peek();
+               Object target = t.peek();
                 if (target == null)
                    throw new JS.Exn(sourceName + ":" + line + ": tried to put a value to the " + key +
                                     " property on the null value");
-                target.put(key, val);
+                if (!(target instanceof JS))
+                   throw new JS.Exn(sourceName + ":" + line + ": tried to put a value to the " + key +
+                                    " property on a " + target.getClass().getName());
+                ((JS)target).put(key, val);
                 t.push(val);
                 break;
             }
@@ -209,8 +252,6 @@ public class ByteCodeBlock implements ByteCodes, Tokens {
                 } }
             }
        }
-        if (t.size() != 1) throw new Error("eval() terminated with " + t.size() + " elements on the stack; one expected");
-        return t.pop();
     }
 
     public Object doGet(final Object o, final Object v) {
index 62908af..1089f64 100644 (file)
@@ -58,16 +58,19 @@ interface ByteCodes {
     public static final byte SWAP = -17;         
 
     /** execute the ForthBlock pointed to by the literal in a fresh scope with parentScope==THIS */
-    public static final byte SCOPE = -18;        
+    public static final byte PUSHSCOPE = -18;        
+
+    /** execute the ForthBlock pointed to by the literal in a fresh scope with parentScope==THIS */
+    public static final byte POPSCOPE = -19;
 
     /** push a copy of the top stack element */
-    public static final byte DUP = -19;          
+    public static final byte DUP = -20;          
 
     /** declare a label */
-    public static final byte LABEL = -20;        
+    public static final byte LABEL = -21;        
 
     /** execute the ForthBlock pointed to by the literal until BREAK encountered; push TRUE onto the stack for the first iteration
      *  and FALSE for all subsequent iterations */
-    public static final byte LOOP = -21;         
+    public static final byte LOOP = -22;         
 
 }
diff --git a/src/org/xwt/js/Context.java b/src/org/xwt/js/Context.java
new file mode 100644 (file)
index 0000000..4fc5eaa
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
+package org.xwt.js;
+
+import org.xwt.util.*;
+import java.io.*;
+
+/** encapsulates a single JavaScript thread and its state */
+public class Context {
+
+    private static Hash javaThreadToContextMap = new Hash();
+
+    public Vec stack = new Vec();
+
+    /** at any point in time, one JS Context can be bound to each Java thread; this determines which context any call()s execute in */
+    public void bindToCurrentThread() { javaThreadToContextMap.put(Thread.currentThread(), this); }
+    public static Context getContextForCurrentThread() {
+       Context ret = (Context)javaThreadToContextMap.get(Thread.currentThread());
+       if (ret == null) {
+           ret = new Context();
+           ret.bindToCurrentThread();
+       }
+       return ret;
+    }
+
+    public static class CallMarker { public CallMarker() { } }
+    public static class LoopMarker { public int location; public LoopMarker(int location) { this.location = location; } }
+
+}
index d3da1f1..11faeaa 100644 (file)
@@ -152,9 +152,18 @@ public abstract class JS {
        public int getLine() throws JS.Exn { return line; }
        public Object _call(JS.Array args) throws JS.Exn, ByteCodeBlock.ControlTransferException {
            if (bytecodes == null) throw new Error("tried to call() a JS.Function with bytecodes == null");
-           Vec stack = new Vec();
-           stack.push(args);
-           return bytecodes.eval(args == null ? parentScope : new FunctionScope(sourceName, parentScope), stack);
+           Context cx = Context.getContextForCurrentThread();
+           int size = cx.stack.size();
+           cx.stack.push(new Context.CallMarker());
+           cx.stack.push(args);
+           bytecodes.eval(args == null ? parentScope : new FunctionScope(sourceName, parentScope));
+           Object ret = cx.stack.pop();
+           if (cx.stack.size() > size) {
+               Log.log(this, "warning, stack grew by " + (cx.stack.size() - size) +
+                       " elements during call to " + getSourceName() + ":" + getLine());
+               Log.log(this, "top element is " + cx.stack.peek());
+           }
+           return ret;
        }
        public final Object call(JS.Array args) throws JS.Exn {
            Function saved = (Function)currentFunction.get(Thread.currentThread());
@@ -182,6 +191,7 @@ public abstract class JS {
                p.parseStatement(false, b);
                if (size == b.size()) break;
            }
+           b.add(Tokens.RETURN);
            return new Function(line, sourceName, b, null);
        } catch (Exception e) {
            if (Log.on) Log.log(Parser.class, e);