From e6a665b309c7103a3a29c2cd96b1073409c13606 Mon Sep 17 00:00:00 2001 From: megacz Date: Fri, 30 Jan 2004 07:00:59 +0000 Subject: [PATCH] 2003/06/10 21:45:35 darcs-hash:20040130070059-2ba56-7e1298d971a0048f63d0e9c1bdb200b3f69f13d0.gz --- src/org/xwt/Box.java | 7 +-- src/org/xwt/ByteStream.java | 4 +- src/org/xwt/Main.java | 2 +- src/org/xwt/Resources.java | 2 +- src/org/xwt/SpecialBoxProperty.java | 4 +- src/org/xwt/Template.java | 20 +++----- src/org/xwt/Trap.java | 10 +--- src/org/xwt/XMLRPC.java | 1 + src/org/xwt/XWT.java | 72 +++++++++++++-------------- src/org/xwt/js/ByteCodeBlock.java | 91 +++++++++++++++++++++++++---------- src/org/xwt/js/ByteCodes.java | 11 +++-- src/org/xwt/js/Context.java | 28 +++++++++++ src/org/xwt/js/JS.java | 16 ++++-- 13 files changed, 172 insertions(+), 96 deletions(-) create mode 100644 src/org/xwt/js/Context.java diff --git a/src/org/xwt/Box.java b/src/org/xwt/Box.java index a18d888..cba4f14 100644 --- a/src/org/xwt/Box.java +++ b/src/org/xwt/Box.java @@ -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); diff --git a/src/org/xwt/ByteStream.java b/src/org/xwt/ByteStream.java index 5aa8526..004c2a3 100644 --- a/src/org/xwt/ByteStream.java +++ b/src/org/xwt/ByteStream.java @@ -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 { diff --git a/src/org/xwt/Main.java b/src/org/xwt/Main.java index 5b78775..a29af2e 100644 --- a/src/org/xwt/Main.java +++ b/src/org/xwt/Main.java @@ -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; diff --git a/src/org/xwt/Resources.java b/src/org/xwt/Resources.java index a152bf8..be4eb99 100644 --- a/src/org/xwt/Resources.java +++ b/src/org/xwt/Resources.java @@ -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(); diff --git a/src/org/xwt/SpecialBoxProperty.java b/src/org/xwt/SpecialBoxProperty.java index c2b52b5..00f43db 100644 --- a/src/org/xwt/SpecialBoxProperty.java +++ b/src/org/xwt/SpecialBoxProperty.java @@ -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 0 && !isreadtrap && !tc.putCascadeHappened) cascadeFunction._call(args, f); diff --git a/src/org/xwt/XMLRPC.java b/src/org/xwt/XMLRPC.java index 27bfcc5..f2e8eee 100644 --- a/src/org/xwt/XMLRPC.java +++ b/src/org/xwt/XMLRPC.java @@ -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; diff --git a/src/org/xwt/XWT.java b/src/org/xwt/XWT.java index cb18679..ed8feb1 100644 --- a/src/org/xwt/XWT.java +++ b/src/org/xwt/XWT.java @@ -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 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 1 && args.elementAt(1) instanceof JS.Function ? (JS.Function)args.elementAt(1) : null); diff --git a/src/org/xwt/js/ByteCodeBlock.java b/src/org/xwt/js/ByteCodeBlock.java index 54b8169..9cd3f0e 100644 --- a/src/org/xwt/js/ByteCodeBlock.java +++ b/src/org/xwt/js/ByteCodeBlock.java @@ -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 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) { diff --git a/src/org/xwt/js/ByteCodes.java b/src/org/xwt/js/ByteCodes.java index 62908af..1089f64 100644 --- a/src/org/xwt/js/ByteCodes.java +++ b/src/org/xwt/js/ByteCodes.java @@ -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 index 0000000..4fc5eaa --- /dev/null +++ b/src/org/xwt/js/Context.java @@ -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; } } + +} diff --git a/src/org/xwt/js/JS.java b/src/org/xwt/js/JS.java index d3da1f1..11faeaa 100644 --- a/src/org/xwt/js/JS.java +++ b/src/org/xwt/js/JS.java @@ -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); -- 1.7.10.4