2004/01/13 10:27:47
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:44:21 +0000 (07:44 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:44:21 +0000 (07:44 +0000)
darcs-hash:20040130074421-2ba56-09b3f3a017dec2c11eb2bfd3dfd4db92bc47d897.gz

16 files changed:
src/org/xwt/Template.java
src/org/xwt/XMLRPC.java
src/org/xwt/XWT.java
src/org/xwt/builtin/splash.xwt
src/org/xwt/js/Interpreter.java
src/org/xwt/js/JS.java
src/org/xwt/js/JSArray.java
src/org/xwt/js/JSDate.java
src/org/xwt/js/JSExn.java
src/org/xwt/js/JSFunction.java
src/org/xwt/js/JSScope.java
src/org/xwt/js/Parser.java
src/org/xwt/plat/AWT.java
src/org/xwt/plat/Win32.java
src/org/xwt/translators/Freetype.java
src/org/xwt/util/Grammar.java

index 69af74a..3626eec 100644 (file)
@@ -33,7 +33,7 @@ public class Template {
     private Vec children = new Vec();     ///< during XML parsing, this holds the list of currently-parsed children; null otherwise
     private int numunits = -1;            ///< see numUnits(); -1 means that this value has not yet been computed
 
-    private JSFunction script = null;       ///< the script on this node
+    private JS script = null;       ///< the script on this node
     private String fileName = "unknown";  ///< the filename this node came from; used only for debugging
     private Vec preapply = new Vec();     ///< templates that should be preapplied (in the order of application)
 
@@ -41,7 +41,7 @@ public class Template {
     // Instance Members that are only meaningful on root Template //////////////////////////////////////
 
     private JSScope staticScope = null;   ///< the scope in which the static block is executed
-    private JSFunction staticscript = null;  ///< the script on the static node of this template, null already performed
+    private JS staticscript = null;  ///< the script on the static node of this template, null already performed
 
 
     // Only used during parsing /////////////////////////////////////////////////////////////////
@@ -49,59 +49,53 @@ public class Template {
     private StringBuffer content = null;   ///< during XML parsing, this holds partially-read character data; null otherwise
     private int content_start = 0;         ///< line number of the first line of <tt>content</tt>
     private int startLine = -1;            ///< the line number that this element starts on
-    private final Stream r;                   ///< the resource we came from
+    private XWT xwt;
 
 
     // Static data/methods ///////////////////////////////////////////////////////////////////
 
-    // FIXME need to provide the XWT object too
-    public static Template getTemplate(Stream r) throws JSExn {
+    public Template(InputStream is, XWT xwt) {
+        this.xwt = xwt;
         try {
-            r = r.addExtension(".xwt");
-            if (r.t != null) return r.t;
-            r.t = new Template(r);
-            new TemplateHelper().parseit(r.getInputStream(), r.t);
-            return r.t;
+            new TemplateHelper().parseit(is, this);
         } catch (Exception e) {
-            throw new JSExn("Error reading template stream: " + r + "\n" + e.toString());
+            throw new RuntimeException(e.toString());
         }
     }
 
-    public static Stream resolveStringToResource(String str, XWT xwt, boolean permitAbsolute) throws JSExn {
+    public Template(XWT xwt) {
+        this.xwt = xwt;
+    }
+
+    public static JS resolveStringToResource(String str, XWT xwt, boolean permitAbsolute) throws JSExn {
         // URL
+        /* FIXME
         if (str.indexOf("://") != -1) {
             if (permitAbsolute) return (Stream)xwt.url2res(str);
             throw new JSExn("absolute URL " + str + " not permitted here");
         }
-
+        */
         // root-relative
-        Stream ret = xwt.rr;
+        JS ret = (JS)xwt.getAndTriggerTraps("");
         while(str.indexOf('.') != -1) {
             String path = str.substring(0, str.indexOf('.'));
             str = str.substring(str.indexOf('.') + 1);
-            ret = (Stream)ret.get(path);
+            ret = (JS)ret.get(path);
         }
-        ret = (Stream)ret.get(str);
+        ret = (JS)ret.get(str);
         return ret;
     }
 
 
     // Methods to apply templates ////////////////////////////////////////////////////////
 
-    private Template(Stream r) {
-        this.r = r;
-        String f = r.toString();
-        if (f != null && !f.equals(""))
-            fileName = f.substring(f.lastIndexOf('/')+1, f.endsWith(".xwt") ? f.length() - 4 : f.length());
-    }
-
     /** called before this template is applied or its static object can be externally referenced */
-    JSScope getStatic(XWT xwt) throws JSExn {
+    JSScope getStatic() throws JSExn {
         if (staticScope == null) staticScope = new PerInstantiationJSScope(null, xwt, null, null);
         if (staticscript == null) return staticScope;
-        JSFunction temp = staticscript;
+        JS temp = staticscript;
         staticscript = null;
-        temp.cloneWithNewParentScope(staticScope).call(null, null, null, null, 0);
+        JS.cloneWithNewParentScope(temp, staticScope).call(null, null, null, null, 0);
         return staticScope;
     }
     
@@ -109,9 +103,13 @@ public class Template {
      *  @param pboxes a vector of all box parents on which to put $-references
      *  @param ptemplates a vector of the fileNames to recieve private references on the pboxes
      */
-    void apply(Box b, XWT xwt) throws JSExn {
+    void apply(Box b) throws JSExn {
         try {
-            apply(b, xwt, null);
+            apply(b, null);
+        } catch (IOException e) {
+            b.clear(b.VISIBLE);
+            b.mark_for_repack();
+            throw new JSExn(e.toString());
         } catch (JSExn e) {
             b.clear(b.VISIBLE);
             b.mark_for_repack();
@@ -119,26 +117,25 @@ public class Template {
         }
     }
 
-
-    private void apply(Box b, XWT xwt, PerInstantiationJSScope parentPis) throws JSExn {
-        getStatic(xwt);
+    private void apply(Box b, PerInstantiationJSScope parentPis) throws JSExn, IOException {
+        getStatic();
 
         if (id != null) parentPis.putDollar(id, b);
         for(int i=0; i<preapply.size(); i++) {
-            Template t = getTemplate(resolveStringToResource((String)preapply.elementAt(i), xwt, false));
+            Template t = new Template(Stream.getInputStream(resolveStringToResource((String)preapply.elementAt(i), xwt, false)), xwt);
             if (t == null) throw new RuntimeException("unable to resolve resource " + preapply.elementAt(i));
-            t.apply(b, xwt);
+            t.apply(b);
         }
 
         PerInstantiationJSScope pis = new PerInstantiationJSScope(b, xwt, parentPis, staticScope);
 
         for (int i=0; children != null && i<children.size(); i++) {
             Box kid = new Box();
-            ((Template)children.elementAt(i)).apply(kid, xwt, pis);
+            ((Template)children.elementAt(i)).apply(kid, pis);
             b.putAndTriggerTraps(b.get("numchildren"), kid);
         }
 
-        if (script != null) script.cloneWithNewParentScope(pis).call(null, null, null, null, 0);
+        if (script != null) JS.cloneWithNewParentScope(script, pis).call(null, null, null, null, 0);
 
         Object key, val;
         for(int i=0; keys != null && i < keys.length; i++) {
@@ -238,7 +235,7 @@ public class Template {
                 // push the last node we were in onto the stack
                 nodeStack.addElement(t);
                 // instantiate a new node, and set its fileName/importlist/preapply
-                Template t2 = new Template(t.r);
+                Template t2 = new Template(t.xwt);
                 t2.startLine = getLine();
                 if (!c.getLocalName().equals("box") && !c.getLocalName().equals("template"))
                     t2.preapply.addElement((c.getUri().equals("") ? "" : (c.getUri() + ".")) + c.getLocalName());
@@ -314,11 +311,11 @@ public class Template {
             }
         }
 
-        private JSFunction parseScript(boolean isstatic) throws IOException {
-            JSFunction thisscript = null;
+        private JS parseScript(boolean isstatic) throws IOException {
+            JS thisscript = null;
             String contentString = t.content.toString();
             if (contentString.trim().length() > 0)
-                thisscript = JSFunction.fromReader(t.fileName + (isstatic ? "._" : ""),
+                thisscript = JS.fromReader(t.fileName + (isstatic ? "._" : ""),
                                                    t.content_start,
                                                    new StringReader(contentString));
             t.content = null;
@@ -389,7 +386,7 @@ public class Template {
         public Object get(Object key) throws JSExn {
             if (super.has(key)) return super.get(key);
             if (key.equals("xwt")) return xwt;
-            if (key.equals("")) return xwt.rr;
+            if (key.equals("")) return xwt.get("");
             if (key.equals("static")) return myStatic;
             return super.get(key);
         }
index 13669ca..2bb107c 100644 (file)
@@ -39,9 +39,9 @@ class XMLRPC extends JS {
 
     /** this holds character content as we read it in -- since there is only one per instance, we don't support mixed content */
     protected AccessibleCharArrayWriter content = new AccessibleCharArrayWriter(100);
-    protected String url = null;       ///< the url to connect to
-    protected String method = null;    ///< the method name to invoke on the remove server
-    protected HTTP http = null;        ///< the HTTP connection to use
+    protected String url = null;         ///< the url to connect to
+    protected String method = null;      ///< the method name to invoke on the remove server
+    protected HTTP http = null;          ///< the HTTP connection to use
     private Hash tracker;                ///< used to detect multi-ref data
     protected boolean fault = false;     ///< True iff the return value is a fault (and should be thrown as an exception)
 
@@ -92,8 +92,9 @@ class XMLRPC extends JS {
             case "boolean": objects.setElementAt(content.getBuf()[0] == '1' ? Boolean.TRUE : Boolean.FALSE, objects.size() - 1);
             case "string": objects.setElementAt(new String(content.getBuf(), 0, content.size()), objects.size() - 1);
             case "double": objects.setElementAt(new Double(new String(content.getBuf(), 0, content.size())), objects.size() - 1);
-            case "base64": objects.setElementAt(new Stream.ByteArray(Base64.decode(new String(content.getBuf(), 0, content.size())),
-                                                                  null), objects.size() - 1);
+            case "base64":
+                objects.setElementAt(new Stream.ByteArray(Base64.decode(new String(content.getBuf(), 0, content.size())),
+                                                          null), objects.size() - 1);
             case "name": objects.addElement(new String(content.getBuf(), 0, content.size()));
             case "value": if ("".equals(objects.lastElement()))
                 objects.setElementAt(new String(content.getBuf(), 0, content.size()), objects.size() - 1);
@@ -108,19 +109,19 @@ class XMLRPC extends JS {
                 try {
                     JSDate nd = new JSDate();
                     double date = JSDate.date_msecFromDate(Double.valueOf(s.substring(0, 4)).doubleValue(),
-                                                                    Double.valueOf(s.substring(4, 6)).doubleValue() - 1,
-                                                                    Double.valueOf(s.substring(6, 8)).doubleValue(),
-                                                                    Double.valueOf(s.substring(9, 11)).doubleValue(),
-                                                                    Double.valueOf(s.substring(12, 14)).doubleValue(),
-                                                                    Double.valueOf(s.substring(15, 17)).doubleValue(),
-                                                                    (double)0
-                                                                    );
+                                                           Double.valueOf(s.substring(4, 6)).doubleValue() - 1,
+                                                           Double.valueOf(s.substring(6, 8)).doubleValue(),
+                                                           Double.valueOf(s.substring(9, 11)).doubleValue(),
+                                                           Double.valueOf(s.substring(12, 14)).doubleValue(),
+                                                           Double.valueOf(s.substring(15, 17)).doubleValue(),
+                                                           (double)0
+                                                           );
                     nd.setTime(JSDate.internalUTC(date));
                     objects.setElementAt(nd, objects.size() - 1);
                     
                 } catch (Exception e) {
-                    if (Log.on) Log.info(this, "error parsing date : " + s);
-                    if (Log.on) Log.info(this, e);
+                    throw new RuntimeException("xwt.net.rpc.xml.recieve.malformedDateTag" +
+                                    "the server sent a <dateTime.iso8601> tag which was malformed: " + s);
                 }
             case "member":
                 Object memberValue = objects.elementAt(objects.size() - 1);
index 2e4999a..f5785c2 100644 (file)
@@ -1,3 +1,4 @@
+// FIXME
 // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
@@ -11,10 +12,10 @@ import org.xwt.translators.*;
 import org.bouncycastle.util.encoders.Base64;
 
 /** Singleton class that provides all functionality in the xwt.* namespace */
-public final class XWT extends JS {
+public final class XWT extends JS.Cloneable {
 
-    public final Stream rr;
-    public XWT(Stream rr) { this.rr = rr; }
+    private final JS rr;
+    public XWT(Stream rr) { this.rr = bless(rr); }
 
     private Cache subCache = new Cache(20);
     private Sub getSub(String s) {
@@ -27,13 +28,8 @@ public final class XWT extends JS {
     private class Sub extends JS {
         String key;
         Sub(String key) { this.key = key; }
-        public String toString() { return "XWTSUB " + key; }
         public void put(Object key, Object val) throws JSExn { XWT.this.put(this.key + "." + key, val); }
         public Object get(Object key) throws JSExn { return XWT.this.get(this.key + "." + key); }
-        public boolean coerceToBoolean() {
-            if (key.equals("ui.key.alt")) return Surface.alt ? true : false;
-            return super.coerceToBoolean();
-        }
         public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
             return XWT.this.callMethod(this.key, a0, a1, a2, rest, nargs);
         }
@@ -48,11 +44,11 @@ public final class XWT extends JS {
         case "math": return xwtMath;
         case "string": return xwtString;
         case "date": return METHOD;
-        case "origin": return Main.origin;  // FIXME not in ref
         case "box": return new Box();
         case "apply": return METHOD;
         case "graft": return METHOD;
         case "clone": return METHOD;
+        case "bless": return METHOD;
         case "regexp": return METHOD;
         case "ui.font": return getSub("ui.font");
         case "ui.font.sansserif": return Main.builtin.get("fonts/vera/Vera.ttf");
@@ -67,23 +63,24 @@ public final class XWT extends JS {
             else if (!Surface.button1 && !Surface.button2 && Surface.button3) return N(3);
             else return ZERO;
         case "ui.key": return getSub("ui.key");
-        case "ui.key.alt": return getSub("ui.key.alt");
-        case "ui.key.alt.name": return Platform.altKeyName();
+        case "ui.key.name": return getSub("ui.key.name");
+        case "ui.key.name.alt": return Platform.altKeyName();
+        case "ui.key.alt": return Surface.alt ? T : F;
         case "ui.key.control": return Surface.control ? T : F;
         case "ui.key.shift": return Surface.shift ? T : F;
         case "ui.clipboard": return Platform.getClipBoard();
-        case "ui.maxdim": return new Integer(Short.MAX_VALUE);
+        case "ui.maxdim": return N(Short.MAX_VALUE);
         case "ui.screen": return getSub("ui.screen");
-        case "ui.screen.width": return new Integer(Platform.getScreenWidth());
-        case "ui.screen.height": return new Integer(Platform.getScreenHeight());
+        case "ui.screen.width": return N(Platform.getScreenWidth());
+        case "ui.screen.height": return N(Platform.getScreenHeight());
         case "undocumented": return getSub("undocumented");
-        case "undocumented.internal": return getSub("undocumented.internal");
+        case "undocumented.initialOrigin": return Main.origin;
         case "thread": return getSub("thread");
         case "thread.yield": return METHOD;
         case "thread.sleep": return METHOD;
         case "stream": return getSub("stream");
-        case "stream.home": return url2res("file:" + System.getProperty("user.home"));
-        case "stream.temp": return url2res("file:" + System.getProperty("java.io.tempdir"));
+        case "stream.homedir": return url2res("file:" + System.getProperty("user.home"));
+        case "stream.tempdir": return url2res("file:" + System.getProperty("java.io.tempdir"));
         case "stream.watch": return METHOD;
         case "stream.unzip": return METHOD;
         case "stream.uncab": return METHOD;
@@ -112,7 +109,7 @@ public final class XWT extends JS {
 
     public void put(Object name, final Object value) throws JSExn {
         //#switch(name)
-        case "thread": Scheduler.add((JSFunction)value); return;
+        case "thread": Scheduler.add((Scheduler.Task)value); return;
         case "ui.clipboard": Platform.setClipBoard((String)value); return;
         case "ui.frame":
             Box b = (Box)value;
@@ -120,7 +117,7 @@ public final class XWT extends JS {
             if(b.get("titlebar") != null) s.setTitleBarText(JS.toString(b.get("titlebar")));
             return;
         case "ui.window": Platform.createSurface((Box)value, false, true); return;
-        case "undocumented.internal.proxyAuthorization":
+        case "undocumented.proxyAuthorization":
             HTTP.Proxy.Authorization.authorization = value.toString();
             HTTP.Proxy.Authorization.waitingForUser.release(); return;
         //#end
@@ -132,14 +129,7 @@ public final class XWT extends JS {
         try {
             //#switch(name)
             case "date": return new JSDate(a, b, c, rest, nargs);
-            case "rpc.soap": return new SOAP((String)a, "", (String)b, (String)c);
-            case "graft":
-                if (a instanceof Box) throw new JSExn("can't graft onto Boxes");
-                if (a instanceof String) throw new JSExn("can't graft onto Strings");
-                if (a instanceof Number) throw new JSExn("can't graft onto Numbers");
-                if (a instanceof Stream) return new Stream.Graft((Stream)a, b, c);
-                // FEATURE: grafting onto JS
-                throw new JSExn("cannot graft onto "+a.getClass());
+            case "net.rpc.soap": return new SOAP((String)a, "", (String)b, (String)c);
             //#end
  
             switch (nargs) {
@@ -150,13 +140,23 @@ public final class XWT extends JS {
                     break;
                 case 1:
                     //#switch(name)
+                    case "clone":
+                        if (!(a instanceof JS.Cloneable)) throw new JSExn("cannot clone a " + a.getClass().getName());
+                        return ((JS.Cloneable)a).jsclone();
+                    case "bless": return bless((JS)a);
                     case "ui.browser": Platform.newBrowserWindow((String)a); return null;
-                    case "clone": return new XWT((Stream)a);
                     case "stream.unzip": return new Stream.Zip((Stream)a);
                     case "stream.uncab": return new Stream.Cab((Stream)a);
                     case "stream.cache": try { return new Stream.CachedStream((Stream)a, "resources", true); }
                                       catch (Stream.NotCacheableException e) { throw new JSExn("this resource cannot be cached"); }
-                    case "stream.url": return url2res((String)a);
+                    case "stream.url": {
+                        String url = (String)a;
+                        if (url.startsWith("http://")) return new Stream.HTTP(url);
+                        else if (url.startsWith("https://")) return new Stream.HTTP(url);
+                        else if (url.startsWith("data:")) return new Stream.ByteArray(Base64.decode(url.substring(5)), null);
+                        else if (url.startsWith("utf8:")) return new Stream.ByteArray(url.substring(5).getBytes(), null);
+                        throw new JSExn("invalid resource specifier " + url);
+                    }
                     case "thread.sleep": sleep(JS.toInt(a)); return null;
                     case "log.debug":   JS.log(this, a== null ? "**null**" : a.toString()); return null;
                     case "log.info":   JS.log(this, a== null ? "**null**" : a.toString()); return null;
@@ -168,23 +168,16 @@ public final class XWT extends JS {
                     case "crypto.md5": /* FEATURE */ return null;
                     case "crypto.sha1": /* FEATURE */ return null;
                     case "crypto.rc4": /* FEATURE */ return null;
-                    case "stream.parse.html": /* FIXME */ return null;
-                    case "stream.parse.xml": /* FIXME -- SAX NOT DOM!! */ return null;
-                    case "stream.parse.utf8": /* FIXME */ return null;
+                    case "stream.parse.html": throw new JSExn("not implemented yet"); //return null;
+                    case "stream.parse.xml": new XMLHelper((JS)b).doParse((JS)a); return null;
+                    case "stream.parse.utf8": 
+                        //return new String(InputStreamToByteArray.convert(((Stream)a).getInputStream()));
+                    return null;
                     //#end
                     break;
                 case 2:
                     //#switch(name)
-                    case "stream.watch": return new Stream.ProgressWatcher((Stream)a, (JSFunction)b);
-                    case "apply":
-                        if (b instanceof Stream) Template.getTemplate((Stream)b).apply((Box)a, XWT.this);
-                        else {
-                            JS to = (JS)a, from = (JS)b; Object k;
-                            for (Enumeration e = from.keys(); e.hasMoreElements();) {
-                                k = e.nextElement(); to.put(k, from.get(k));
-                            }
-                        }
-                        return a;
+                    case "stream.watch": return new Stream.ProgressWatcher((Stream)a, (JS)b);
                     case "regexp": return new JSRegexp(a, b);
                     //#end
                     break;
@@ -254,53 +247,52 @@ public final class XWT extends JS {
         };
 
     private class XMLHelper extends XML {
-        Vector obStack = new Vector();
-        public XMLHelper() { super(BUFFER_SIZE); }
+        private JS characters, whitespace, endElement, startElement;
+        public XMLHelper(JS b) throws JSExn {
+            super(BUFFER_SIZE);
+            // FIXME: trigger traps?
+            startElement = (JS)b.get("startElement");
+            endElement = (JS)b.get("endElement");
+            characters = (JS)b.get("characters");
+            whitespace = (JS)b.get("whitespace");
+        }
+        private class XMLJSWrapper extends XML.Exn {
+            public JSExn wrapee; public XMLJSWrapper(JSExn jse) { super(""); wrapee = jse; } }
         public void startElement(XML.Element c) throws XML.Exn {
             try {
-                JS o = new JS();
-                o.put("$name", c.getLocalName());
-                for(int i=0; i < c.getAttrLen(); i++) o.put(c.getAttrKey(i), c.getAttrVal(i));
-                o.put("$numchildren", new Integer(0));
-                obStack.addElement(o);
+                JS attrs = new JS();
+                for(int i=0; i<c.getAttrLen(); i++) attrs.put(c.getAttrKey(i), c.getAttrVal(i));   // FIXME attribute URIs?
+                startElement.call(c.getLocalName(), attrs, c.getUri(), null, 3);
             } catch (JSExn jse) {
-                throw new Error("this should never happen");
+                throw new XMLJSWrapper(jse);
             }
         }
         public void endElement(XML.Element c) throws XML.Exn {
             try {
-                if (obStack.size() == 1) return;
-                JS me = (JS)obStack.lastElement();
-                obStack.setSize(obStack.size() - 1);
-                JS parent = (JS)obStack.lastElement();
-                int numchildren = ((Integer)parent.get("$numchildren")).intValue();
-                parent.put("$numchildren", new Integer(numchildren + 1));
-                parent.put(new Integer(numchildren), me);
+                endElement.call(c.getLocalName(), c.getUri(), null, null, 2);
             } catch (JSExn jse) {
-                throw new Error("this should never happen");
+                throw new XMLJSWrapper(jse);
             }
         }
         public void characters(char[] ch, int start, int length) throws XML.Exn {
             try {
-                String s = new String(ch, start, length);
-                JS parent = (JS)obStack.lastElement();
-                int numchildren = ((Integer)parent.get("$numchildren")).intValue();
-                Object lastChild = parent.get(new Integer(numchildren - 1));
-                if (lastChild instanceof String) {
-                    parent.put(new Integer(numchildren - 1), lastChild + s);
-                } else {
-                    parent.put("$numchildren", new Integer(numchildren + 1));
-                    parent.put(new Integer(numchildren), s);
-                }
+                characters.call(new String(ch, start, length), null, null, null, 1);
             } catch (JSExn jse) {
-                throw new Error("this should never happen");
+                throw new XMLJSWrapper(jse);
             }
         }
-        public void whitespace(char[] ch, int start, int length) {}
-        public JS doParse(InputStream is) throws JSExn {
+        public void whitespace(char[] ch, int start, int length) throws XML.Exn {
+            try {
+                whitespace.call(new String(ch, start, length), null, null, null, 1);
+            } catch (JSExn jse) {
+                throw new XMLJSWrapper(jse);
+            }
+        }
+        public void doParse(JS s) throws JSExn {
             try { 
-                BufferedReader r = new BufferedReader(new InputStreamReader(is));
-                parse(r);
+                parse(new BufferedReader(new InputStreamReader(Stream.getInputStream(s))));
+            } catch (XMLJSWrapper e) {
+                throw e.wrapee;
             } catch (XML.Exn e) {
                 throw new JSExn("error parsing XML: " + e.toString());
             } catch (IOException e) {
@@ -308,7 +300,51 @@ public final class XWT extends JS {
                 if (Log.on) Log.info(this, e);
                 throw new JSExn("error reading from Resource");
             }
-            return obStack.size() >= 1 ? (JS)obStack.elementAt(0) : null;
         }
     }
+
+    public Blessing bless(JS b) { return new XWT.Blessing((JS.Cloneable)b, this, null, null); }
+    public static class Blessing extends JS.Clone {
+        private XWT xwt;
+        private Template t = null;
+        private Object parentkey = null;
+        private Blessing parent = null;
+        public Blessing(JS.Cloneable clonee, XWT xwt, Blessing parent, Object parentkey) {
+            super(clonee); this.xwt = xwt; this.parentkey = parentkey; this.parent = parent; }
+        public Object get(Object key) throws JSExn {
+            return key.equals("") ? ((Object)getStatic()) : (new Blessing((JS.Cloneable)clonee.get(key), xwt, this, key));
+        }
+        public InputStream getImage() throws JSExn {
+            InputStream in = null;
+            try {
+                in = Stream.getInputStream(this);
+                if (in != null) return in;
+            } catch (IOException e) { /* DELIBERATE */ in = null; }
+            String[] exts = new String[] { ".png", ".jpeg", ".gif" };
+            for (int i=0; i < exts.length && in == null; i++) {
+                try {
+                    in = Stream.getInputStream(parent.get(parentkey + exts[i]));
+                    if (in != null) return in;
+                } catch (IOException f) { in = null; }
+            }
+            return null;
+        }
+        public JSScope getStatic() throws JSExn {
+            try {
+                // FIXME background?
+                if (t == null) t = new Template(Stream.getInputStream(parent.get(parentkey + ".xwt")), xwt);
+                return t.getStatic();
+            } catch (Exception e) {
+                Log.error(this, e);
+                return null;
+            }
+        }
+        public Object call(Object a, Object b, Object c, Object[] rest, int nargs) throws JSExn {
+            if (nargs != 1) throw new JSExn("FIXME can only call with one arg");
+            getStatic();
+            t.apply((Box)a);
+            return a;
+        }
+    }
+
 }
index a62061c..014e443 100644 (file)
             var new_xwt = xwt.clone(new_rr);
 
             xwt.thread = function() {
-for(var i=0; 100>i; i++) {
-progress(i, 100);
-xwt.thread.yield();
-}
-                new_xwt.apply(xwt.box, new_xwt["main.xwt"]);
-                thisbox = null;
+                for(var i=0; 100>i; i++) {
+                progress(i, 100);
+                xwt.thread.yield();
             }
+            new_xwt.apply(xwt.box, new_xwt["main.xwt"]);
+            thisbox = null;
+        }
 xwt.log.println("leaving");
         }
 
index 700462a..359b844 100644 (file)
@@ -44,7 +44,17 @@ class Interpreter implements ByteCodes, Tokens {
         }
     }
 
-    private static JSExn je(String s) { return new JSExn(JS.getSourceName() + ":" + JS.getLine() + " " + s); }
+    static int getLine() {
+        Interpreter c = Interpreter.current();
+        return c == null || c.f == null || c.pc < 0 || c.pc >= c.f.size ? -1 : c.f.line[c.pc];
+    }
+
+    static String getSourceName() {
+        Interpreter c = Interpreter.current();
+        return c == null || c.f == null ? null : c.f.sourceName;
+    } 
+
+    private static JSExn je(String s) { return new JSExn(getSourceName() + ":" + getLine() + " " + s); }
 
     // FIXME: double check the trap logic
     private Object run() throws JSExn {
@@ -87,17 +97,17 @@ class Interpreter implements ByteCodes, Tokens {
             case ASSERT: if (!JS.toBoolean(stack.pop())) throw je("xwt.assertion.failed" /*FEATURE: line number*/); break;
             case BITNOT: stack.push(JS.N(~JS.toLong(stack.pop()))); break;
             case BANG: stack.push(JS.B(!JS.toBoolean(stack.pop()))); break;
-            case NEWFUNCTION: stack.push(((JSFunction)arg).cloneWithNewParentScope(scope)); break;
+            case NEWFUNCTION: stack.push(((JSFunction)arg)._cloneWithNewParentScope(scope)); break;
             case LABEL: break;
 
             case TYPEOF: {
                 Object o = stack.pop();
                 if (o == null) stack.push(null);
-                else if (o instanceof JS) stack.push(((JS)o).typeName());
+                else if (o instanceof JS) stack.push("object");
                 else if (o instanceof String) stack.push("string");
                 else if (o instanceof Number) stack.push("number");
                 else if (o instanceof Boolean) stack.push("boolean");
-                else stack.push("unknown");
+                else throw new Error("this should not happen");
                 break;
             }
 
@@ -139,7 +149,7 @@ class Interpreter implements ByteCodes, Tokens {
                     }
                 }
                 throw new Error("CONTINUE/BREAK invoked but couldn't find LoopMarker at " +
-                                JS.getSourceName() + ":" + JS.getLine());
+                                getSourceName() + ":" + getLine());
 
             case TRY: {
                 int[] jmps = (int[]) arg;
index 4c33534..355bdc5 100644 (file)
@@ -9,25 +9,51 @@ import java.util.*;
 /** The minimum set of functionality required for objects which are manipulated by JavaScript */
 public class JS extends org.xwt.util.BalancedTree { 
 
-    // Static Interpreter Control Methods ///////////////////////////////////////////////////////////////
+    public static final Object METHOD = new Object();
+    public final JS unclone() { return _unclone(); }
+    public Enumeration keys() throws JSExn { return entries == null ? emptyEnumeration : entries.keys(); }
+    public Object get(Object key) throws JSExn { return entries == null ? null : entries.get(key, null); }
+    public void put(Object key, Object val) throws JSExn { (entries==null?entries=new Hash():entries).put(key,null,val); }
+    public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
+        throw new JSExn("attempted to call the null value (method "+method+")");
+    }    
+    public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
+        throw new JSExn("you cannot call this object (class=" + this.getClass().getName() +")");
+    }
 
-    /** log a message with the current JavaScript sourceName/line */
-    public static void log(Object o, Object message) { log(message); }
-    public static void log(Object message) { Log.echo(JS.getSourceName() + ":" + JS.getLine(), message); }
-    public static void log(JSExn e) {
-        Log.echo(e,"JS Exception: " + e.getObject() + "\n" + e.backtrace());
-        Log.echo(e,e);
+    JS _unclone() { return this; }
+    public static class Cloneable extends JS {
+        public Cloneable() { }
+        public Object jsclone() throws JSExn {
+            throw new JSExn("cloning not yet implemented");
+        }
     }
 
-    public static int getLine() {
-        Interpreter c = Interpreter.current();
-        return c == null || c.f == null || c.pc < 0 || c.pc >= c.f.size ? -1 : c.f.line[c.pc];
+    public static class Clone extends JS.Cloneable {
+        protected JS.Cloneable clonee = null;
+        JS _unclone() { return clonee; }
+        public Clone(JS.Cloneable clonee) { this.clonee = clonee; }
+        public boolean equals(Object o) {
+            if (!(o instanceof JS)) return false;
+            return unclone() == ((JS)o).unclone();
+        }
+        public Enumeration keys() throws JSExn { return clonee.keys(); }
+        public Object get(Object key) throws JSExn { return clonee.get(key); }
+        public void put(Object key, Object val) throws JSExn { clonee.put(key, val); }
+        public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
+            return clonee.callMethod(method, a0, a1, a2, rest, nargs);
+        }    
+        public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
+            return clonee.call(a0, a1, a2, rest, nargs);
+        }
     }
 
-    public static String getSourceName() {
-        Interpreter c = Interpreter.current();
-        return c == null || c.f == null ? null : c.f.sourceName;
-    } 
+    // Static Interpreter Control Methods ///////////////////////////////////////////////////////////////
+
+    /** log a message with the current JavaScript sourceName/line */
+    public static void log(Object o, Object message) { log(message); }
+    public static void log(Object message) { Log.echo(Interpreter.getSourceName() + ":" + Interpreter.getLine(), message); }
+    public static void log(JSExn e) { Log.echo(e,"JS Exception: " + e.getObject() + "\n" + e.backtrace()); Log.echo(e,e); }
 
     public static class NotPauseableException extends Exception { NotPauseableException() { } }
 
@@ -85,10 +111,8 @@ public class JS extends org.xwt.util.BalancedTree {
 
         // NOTE: There are about 3 pages of rules in ecma262 about string to number conversions
         //       We aren't even close to following all those rules.  We probably never will be.
-        if (o instanceof String)
-            try { return N((String)o); } catch (NumberFormatException e) { return N(Double.NaN); }
+        if (o instanceof String) try { return N((String)o); } catch (NumberFormatException e) { return N(Double.NaN); }
         if (o instanceof Boolean) return ((Boolean)o).booleanValue() ? N(1) : ZERO;
-        if (o instanceof JS) return ((JS)o).coerceToNumber();
         throw new Error("toNumber() got object of type " + o.getClass().getName() + " which we don't know how to handle");
     }
 
@@ -97,16 +121,16 @@ public class JS extends org.xwt.util.BalancedTree {
         if(o == null) return "null";
         if(o instanceof String) return (String) o;
         if(o instanceof Integer || o instanceof Long || o instanceof Boolean) return o.toString();
-        if(o instanceof JS) return ((JS)o).coerceToString();
+        if(o instanceof JSArray) return o.toString();
+        if(o instanceof JSDate) return o.toString();
         if(o instanceof Double || o instanceof Float) {
             double d = ((Number)o).doubleValue();
             if((int)d == d) return Integer.toString((int)d);
             return o.toString();
         }
-        return o.toString();
+        throw new RuntimeException("can't coerce that!");
     }
 
-    
     // Instance Methods ////////////////////////////////////////////////////////////////////
 
     public static final Integer ZERO = new Integer(0);
@@ -145,21 +169,22 @@ public class JS extends org.xwt.util.BalancedTree {
         };
     
     private Hash entries = null;
-    public Enumeration keys() throws JSExn {
-        return entries == null ? emptyEnumeration : entries.keys();
+
+    public static JS fromReader(String sourceName, int firstLine, Reader sourceCode) throws IOException {
+        return JSFunction._fromReader(sourceName, firstLine, sourceCode);
     }
-    public Object get(Object key) throws JSExn { return entries == null ? null : entries.get(key, null); }
-    public void put(Object key, Object val) throws JSExn {
-        if (entries == null) entries = new Hash();
-        entries.put(key, null, val);
+
+    // HACK: caller can't know if the argument is a JSFunction or not...
+    public static JS cloneWithNewParentScope(JS j, JSScope s) {
+        return ((JSFunction)j)._cloneWithNewParentScope(s);
     }
 
 
     // Trap support //////////////////////////////////////////////////////////////////////////////
 
     /** override and return true to allow placing traps on this object.
-        *  if isRead true, this is a read trap, otherwise write trap
-        **/
+     *  if isRead true, this is a read trap, otherwise write trap
+     **/
     protected boolean isTrappable(Object name, boolean isRead) { return true; }
 
     /** performs a put, triggering traps if present; traps are run in an unpauseable interpreter */
@@ -205,27 +230,4 @@ public class JS extends org.xwt.util.BalancedTree {
     }
 
 
-    // Call Support //////////////////////////////////////////////////////////////////////////////
-
-    // return this from get() if the key was actually a method.
-    public static final Object METHOD = new Object();
-    public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
-        throw new JSExn("attempted to call the null value (method "+method+")");
-    }    
-    public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
-        throw new JSExn("you cannot call this object (class=" + this.getClass().getName() +")");
-    }
-
-
-    // Typing Support //////////////////////////////////////////////////////////////////////////////
-
-    public Number coerceToNumber() { throw new JSRuntimeExn("tried to coerce a JavaScript object of type " + 
-                                                            getClass().getName() + " to a Number"); }
-    public String coerceToString() { throw new JSRuntimeExn("tried to coerce a JavaScript object of type " +
-                                                            getClass().getName() + " to a String"); }
-    public boolean coerceToBoolean() { throw new JSRuntimeExn("tried to coerce a JavaScript object of type " +
-                                                            getClass().getName() + " to a Boolean"); }
-
-    public String typeName() { return "object"; }
-
 } 
index 290eacc..ca2919d 100644 (file)
@@ -258,5 +258,5 @@ public class JSArray extends JS {
         }
     }
     
-    public String coerceToString() { return JS.toString(join(",")); }
+    public String toString() { return JS.toString(join(",")); }
 }
index ca9c5b7..fc3fcd0 100644 (file)
@@ -59,7 +59,7 @@ public class JSDate extends JS {
         }
     }
 
-    public String coerceToString() { return date_format(date, FORMATSPEC_FULL); }
+    public String toString() { return date_format(date, FORMATSPEC_FULL); }
 
     public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
         switch(nargs) {
index c63a7a5..df1022e 100644 (file)
@@ -11,7 +11,7 @@ public class JSExn extends Exception {
     private Vec backtrace = new Vec();
     private Object js = null; 
     public JSExn(Object js) { this.js = js; } 
-    public String toString() { return "JSExn: " + JS.toString(js); }
+    public String toString() { return "JSExn: " + js; }
     public String getMessage() { return toString(); }
     public Object getObject() { return js; } 
     public void addBacktrace(String sourceName, int lineNo) { backtrace.addElement(sourceName + ":" + lineNo); }
index a1e6564..2f75ff2 100644 (file)
@@ -6,7 +6,7 @@ import java.util.*;
 import java.io.*;
 
 /** A JavaScript function, compiled into bytecode */
-public class JSFunction extends JS implements ByteCodes, Tokens, org.xwt.Scheduler.Task {
+class JSFunction extends JS implements ByteCodes, Tokens, org.xwt.Scheduler.Task {
 
 
     // Fields and Accessors ///////////////////////////////////////////////
@@ -35,7 +35,7 @@ public class JSFunction extends JS implements ByteCodes, Tokens, org.xwt.Schedul
     }
 
     /** parse and compile a function */
-    public static JSFunction fromReader(String sourceName, int firstLine, Reader sourceCode) throws IOException {
+    public static JSFunction _fromReader(String sourceName, int firstLine, Reader sourceCode) throws IOException {
         JSFunction ret = new JSFunction(sourceName, firstLine, null);
         if (sourceCode == null) return ret;
         Parser p = new Parser(sourceCode, sourceName, firstLine);
@@ -49,7 +49,7 @@ public class JSFunction extends JS implements ByteCodes, Tokens, org.xwt.Schedul
         return ret;
     }
 
-    public JSFunction cloneWithNewParentScope(JSScope s) {
+    public JSFunction _cloneWithNewParentScope(JSScope s) {
         JSFunction ret = new JSFunction(sourceName, firstLine, s);
         // Reuse the same op, arg, line, and size variables for the new "instance" of the function
         // NOTE: Neither *this* function nor the new function should be modified after this call
index 2dedfc1..a504d8d 100644 (file)
@@ -5,6 +5,7 @@ import org.xwt.util.*;
 import java.io.*;
 import java.util.*;
 
+// FIXME: should allow parentScope to be a JS, not a JSScope
 /** Implementation of a JavaScript Scope */
 public class JSScope extends JS { 
 
index 0601bbd..bffeeb4 100644 (file)
@@ -73,7 +73,7 @@ class Parser extends Lexer implements ByteCodes {
 
     /** for debugging */
     public static void main(String[] s) throws Exception {
-        JSFunction block = JSFunction.fromReader("stdin", 0, new InputStreamReader(System.in));
+        JS block = JS.fromReader("stdin", 0, new InputStreamReader(System.in));
         if (block == null) return;
         System.out.println(block);
     }
@@ -370,9 +370,9 @@ class Parser extends Lexer implements ByteCodes {
             Grammar g = parseGrammar(null);
             if (peekToken() == LC) {
                 g.action = new JSFunction(sourceName, parserLine, null);
-                parseBlock(g.action);
-                g.action.add(parserLine, LITERAL, null);         // in case we "fall out the bottom", return NULL              
-                g.action.add(parserLine, RETURN);
+                parseBlock((JSFunction)g.action);
+                ((JSFunction)g.action).add(parserLine, LITERAL, null);         // in case we "fall out the bottom", return NULL              
+                ((JSFunction)g.action).add(parserLine, RETURN);
             }
             b.add(parserLine, MAKE_GRAMMAR, g);
             b.add(parserLine, PUT);
index 875641a..6a0ed9b 100644 (file)
@@ -5,6 +5,7 @@ import org.xwt.*;
 import org.xwt.util.*;
 import java.net.*;
 import java.io.*;
+import org.xwt.js.*;
 import java.util.*;
 import java.awt.*;
 import java.awt.datatransfer.*;
@@ -16,7 +17,7 @@ public class AWT extends JVM {
 
     protected String getDescriptiveName() { return "Generic JDK 1.1+ with AWT"; }
     protected PixelBuffer _createPixelBuffer(int w, int h, Surface owner) { return new AWTPixelBuffer(w, h); }
-    protected Picture _createPicture(Stream r) { return new AWTPicture(r); }
+    protected Picture _createPicture(JS r) { return new AWTPicture(r); }
     protected int _getScreenWidth() { return Toolkit.getDefaultToolkit().getScreenSize().width; }
     protected int _getScreenHeight() { return Toolkit.getDefaultToolkit().getScreenSize().height; }
     protected Surface _createSurface(Box b, boolean framed) { return new AWTSurface(b, framed); }
@@ -161,7 +162,7 @@ public class AWT extends JVM {
         private static ColorModel cmodel = new DirectColorModel(32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
         
         boolean initialized = false;
-        public AWTPicture(Stream r) { super(r); }
+        public AWTPicture(JS r) { super(r); }
         public void init() {
             if (initialized) return;
             initialized = true;
index 168e9ff..b56a3ef 100644 (file)
@@ -92,8 +92,8 @@ public class Win32 extends GCJ {
 
         HTTP.Proxy ret = new HTTP.Proxy();
         if (container[2] != null) {
-            ret.proxyAutoConfigJSFunction = HTTP.Proxy.getProxyAutoConfigJSFunction(container[2]);
-            if (ret.proxyAutoConfigJSFunction != null) return ret;
+            ret.proxyAutoConfigFunction = HTTP.Proxy.getProxyAutoConfigFunction(container[2]);
+            if (ret.proxyAutoConfigFunction != null) return ret;
         }
 
         if (container[0] == null) return null;
index 4d14852..7fc5447 100644 (file)
@@ -23,7 +23,7 @@ public class Freetype {
         try {
             Log.info(this, "loading font " + res);
             loadedStream = res;
-            InputStream is = res.getInputStream();
+            InputStream is = Stream.getInputStream(res);
             byte[] fontstream = InputStreamToByteArray.convert(is);
             vm = new MIPSApps();
             int baseAddr = vm.sbrk(fontstream.length);
index 48018c7..6ad2580 100644 (file)
@@ -6,7 +6,7 @@ import org.xwt.js.*;
 
 public abstract class Grammar extends JS {
 
-    public JSFunction action = null;
+    public JS action = null;
     public Grammar() { }
 
     // means we call()ed a Grammar that hasn't been bound to a scope yet
@@ -22,7 +22,7 @@ public abstract class Grammar extends JS {
         final int ret = match(s, start, v2, scope);
         Object result = ret == -1 ? NULL : action == null ?
             s.substring(start, ret) :
-            action.cloneWithNewParentScope(new JSScope(scope) {
+            JS.cloneWithNewParentScope(action, new JSScope(scope) {
                     public Object get(Object key) throws JSExn {
                         Object val = v2.get(key);
                         if (val == NULL) return null;