From 163ff4c57ec557bb8615f80e875f045cdfbad696 Mon Sep 17 00:00:00 2001 From: megacz Date: Fri, 30 Jan 2004 07:44:21 +0000 Subject: [PATCH] 2004/01/13 10:27:47 darcs-hash:20040130074421-2ba56-09b3f3a017dec2c11eb2bfd3dfd4db92bc47d897.gz --- src/org/xwt/Template.java | 77 +++++++------- src/org/xwt/XMLRPC.java | 29 +++--- src/org/xwt/XWT.java | 184 ++++++++++++++++++++------------- src/org/xwt/builtin/splash.xwt | 12 +-- src/org/xwt/js/Interpreter.java | 20 +++- src/org/xwt/js/JS.java | 104 ++++++++++--------- src/org/xwt/js/JSArray.java | 2 +- src/org/xwt/js/JSDate.java | 2 +- src/org/xwt/js/JSExn.java | 2 +- src/org/xwt/js/JSFunction.java | 6 +- src/org/xwt/js/JSScope.java | 1 + src/org/xwt/js/Parser.java | 8 +- src/org/xwt/plat/AWT.java | 5 +- src/org/xwt/plat/Win32.java | 4 +- src/org/xwt/translators/Freetype.java | 2 +- src/org/xwt/util/Grammar.java | 4 +- 16 files changed, 255 insertions(+), 207 deletions(-) diff --git a/src/org/xwt/Template.java b/src/org/xwt/Template.java index 69af74a..3626eec 100644 --- a/src/org/xwt/Template.java +++ b/src/org/xwt/Template.java @@ -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 content 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 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); } diff --git a/src/org/xwt/XMLRPC.java b/src/org/xwt/XMLRPC.java index 13669ca..2bb107c 100644 --- a/src/org/xwt/XMLRPC.java +++ b/src/org/xwt/XMLRPC.java @@ -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 tag which was malformed: " + s); } case "member": Object memberValue = objects.elementAt(objects.size() - 1); diff --git a/src/org/xwt/XWT.java b/src/org/xwt/XWT.java index 2e4999a..f5785c2 100644 --- a/src/org/xwt/XWT.java +++ b/src/org/xwt/XWT.java @@ -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= 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; + } + } + } diff --git a/src/org/xwt/builtin/splash.xwt b/src/org/xwt/builtin/splash.xwt index a62061c..014e443 100644 --- a/src/org/xwt/builtin/splash.xwt +++ b/src/org/xwt/builtin/splash.xwt @@ -47,13 +47,13 @@ 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"); } diff --git a/src/org/xwt/js/Interpreter.java b/src/org/xwt/js/Interpreter.java index 700462a..359b844 100644 --- a/src/org/xwt/js/Interpreter.java +++ b/src/org/xwt/js/Interpreter.java @@ -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; diff --git a/src/org/xwt/js/JS.java b/src/org/xwt/js/JS.java index 4c33534..355bdc5 100644 --- a/src/org/xwt/js/JS.java +++ b/src/org/xwt/js/JS.java @@ -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"; } - } diff --git a/src/org/xwt/js/JSArray.java b/src/org/xwt/js/JSArray.java index 290eacc..ca2919d 100644 --- a/src/org/xwt/js/JSArray.java +++ b/src/org/xwt/js/JSArray.java @@ -258,5 +258,5 @@ public class JSArray extends JS { } } - public String coerceToString() { return JS.toString(join(",")); } + public String toString() { return JS.toString(join(",")); } } diff --git a/src/org/xwt/js/JSDate.java b/src/org/xwt/js/JSDate.java index ca9c5b7..fc3fcd0 100644 --- a/src/org/xwt/js/JSDate.java +++ b/src/org/xwt/js/JSDate.java @@ -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) { diff --git a/src/org/xwt/js/JSExn.java b/src/org/xwt/js/JSExn.java index c63a7a5..df1022e 100644 --- a/src/org/xwt/js/JSExn.java +++ b/src/org/xwt/js/JSExn.java @@ -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); } diff --git a/src/org/xwt/js/JSFunction.java b/src/org/xwt/js/JSFunction.java index a1e6564..2f75ff2 100644 --- a/src/org/xwt/js/JSFunction.java +++ b/src/org/xwt/js/JSFunction.java @@ -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 diff --git a/src/org/xwt/js/JSScope.java b/src/org/xwt/js/JSScope.java index 2dedfc1..a504d8d 100644 --- a/src/org/xwt/js/JSScope.java +++ b/src/org/xwt/js/JSScope.java @@ -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 { diff --git a/src/org/xwt/js/Parser.java b/src/org/xwt/js/Parser.java index 0601bbd..bffeeb4 100644 --- a/src/org/xwt/js/Parser.java +++ b/src/org/xwt/js/Parser.java @@ -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); diff --git a/src/org/xwt/plat/AWT.java b/src/org/xwt/plat/AWT.java index 875641a..6a0ed9b 100644 --- a/src/org/xwt/plat/AWT.java +++ b/src/org/xwt/plat/AWT.java @@ -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; diff --git a/src/org/xwt/plat/Win32.java b/src/org/xwt/plat/Win32.java index 168e9ff..b56a3ef 100644 --- a/src/org/xwt/plat/Win32.java +++ b/src/org/xwt/plat/Win32.java @@ -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; diff --git a/src/org/xwt/translators/Freetype.java b/src/org/xwt/translators/Freetype.java index 4d14852..7fc5447 100644 --- a/src/org/xwt/translators/Freetype.java +++ b/src/org/xwt/translators/Freetype.java @@ -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); diff --git a/src/org/xwt/util/Grammar.java b/src/org/xwt/util/Grammar.java index 48018c7..6ad2580 100644 --- a/src/org/xwt/util/Grammar.java +++ b/src/org/xwt/util/Grammar.java @@ -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; -- 1.7.10.4