2003/06/29 21:20:38
authorbrian <brian@xwt.org>
Fri, 30 Jan 2004 07:02:40 +0000 (07:02 +0000)
committerbrian <brian@xwt.org>
Fri, 30 Jan 2004 07:02:40 +0000 (07:02 +0000)
darcs-hash:20040130070240-aa32f-e13c29c9462f9e27161a8683c2e3a916411a289c.gz

src/org/xwt/Box.java
src/org/xwt/Template.java
src/org/xwt/Trap.java
src/org/xwt/js/ByteCodes.java
src/org/xwt/js/CompiledFunctionImpl.java
src/org/xwt/js/JS.java
src/org/xwt/js/Math.java
src/org/xwt/js/Regexp.java

index 501f061..f40a413 100644 (file)
@@ -1203,7 +1203,8 @@ public final class Box extends JS.Scope {
     public void put(Object name, Object value, boolean ignoretraps) { put(name, value, ignoretraps, null); }
     public void put(Object name_, Object value, boolean ignoretraps, RootProxy rp) {
         if (name_ instanceof Number) { put(((Number)name_).intValue(), value); return; }
-        String name = (String)name_;
+        if (!(name_ instanceof String)) { super.put(name_,value); return; }
+        String name = name_.toString();
         if (name == null) return;  // FIXME, shouldn't be necessary
         if (name.startsWith("xwt_")) {
             if (Log.on) Log.logJS(this, "attempt to set reserved property " + name);
index 6ee6f0b..2f14040 100644 (file)
@@ -212,15 +212,19 @@ public class Template {
         }
 
         for(int i=0; keys != null && i<keys.length; i++) {
-            // FIXME: make sure that if exceptions are thrown in here, the line number of the offending XML is logged
-            if (keys[i] == null) { }
-            else if (keys[i].equals("border") || keys[i].equals("image") &&
-                     !vals[i].toString().startsWith("http://") && !vals[i].toString().startsWith("https://")) {
-                String s = Resources.resolve(vals[i].toString() + ".png", importlist);
-                if (s != null) b.put(keys[i], s.substring(0, s.length() - 4));
-                else if (Log.on) Log.log(this, "unable to resolve image " + vals[i].toString() + " referenced in attributes of " + nodeName); 
+            try {
+                if (keys[i] == null) { }
+                else if (keys[i].equals("border") || keys[i].equals("image") &&
+                        !vals[i].toString().startsWith("http://") && !vals[i].toString().startsWith("https://")) {
+                    String s = Resources.resolve(vals[i].toString() + ".png", importlist);
+                    if (s != null) b.put(keys[i], s.substring(0, s.length() - 4));
+                    else if (Log.on) Log.log(this, "unable to resolve image " + vals[i].toString() + " referenced in attributes of " + nodeName); 
+                }
+                else b.put(keys[i], vals[i]);
+            } catch(JS.Exn e) {
+                if(Log.on) Log.log(this,"WARNING: uncaught ecmascript exception while putting attr \"" + keys[i] + 
+                    "\" of " + nodeName + " : " + e.getMessage());
             }
-            else b.put(keys[i], vals[i]);
         }
 
         if (redirect != null && !"self".equals(redirect)) b.redirect = redir;
index bb32ee4..e3b6c19 100644 (file)
@@ -155,7 +155,7 @@ public class Trap {
     private Trap() { allTraps.put(myWeak, dummy); }
 
     /** perform this trap -- arg.length == 0 if this is a get; otherwise it contains a single element to be put */
-    public Object perform(JS.Array args) {
+    public Object perform(JS.Array args) throws JS.Exn {
         TrapContext tc = TrapContext.get();
 
         // save both thread-locals on the stack and update their values
@@ -182,17 +182,13 @@ public class Trap {
             if (args.length() > 0 && !isreadtrap && !tc.putCascadeHappened) cascadeFunction.call(args);
             
             return ret;
-
-        } catch (JS.Exn e) {
-            if (Log.on) Log.log(this, e);
-
+            
         } finally {
             // restore the thread-locals
             tc.putCascadeHappened = save_putCascadeHappened;
             tc.currentTrap = save_currentTrap;
             tc.trapDepth--;
         }
-        return null;
     }
 
     /** removes this trap */
index b23af2d..c74c564 100644 (file)
@@ -73,4 +73,10 @@ interface ByteCodes {
      *  and FALSE for all subsequent iterations */
     public static final byte LOOP = -22;         
 
+
+    public static final String[] bytecodeToString = new String[] {
+        "", "", "LITERAL", "ARRAY", "OBJECT", "NEWFUNCTION", "DECLARE", "TOPSCOPE",
+        "GET", "GET_PRESERVE", "PUT", "JT", "JF", "JMP", "POP", "CALL", "PUSHKEYS",
+        "SWAP", "NEWSCOPE", "OLDSCOPE", "DUP", "LABEL", "LOOP"
+    };
 }
index 9912ab1..5aff71a 100644 (file)
@@ -53,7 +53,8 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
             p.parseStatement(this, null);
             if (s == size()) break;
         }
-        add(-1, Tokens.RETURN);
+        add(-1, LITERAL, null); 
+        add(-1, RETURN);
     }
     
     public Object call(JS.Array args) throws JS.Exn { return call(args, new FunctionScope(sourceName, parentScope)); }
@@ -67,7 +68,10 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
             cx.stack.push(args);
             eval(scope);
             Object ret = cx.stack.pop();
-            if (cx.stack.size() > size) Log.logJS(this, "warning, stack grew by " + (cx.stack.size() - size) + " elements during call");
+            // FIXME: if we catch an exception in Java, JS won't notice and the stack will be messed up
+            if (cx.stack.size() > size)
+                // this should never happen
+                throw new Error("ERROR: stack grew by " + (cx.stack.size() - size) + " elements during call");
             return ret;
         } finally {
             cx.currentCompiledFunction = saved;
@@ -94,17 +98,23 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
         size++;
         return this;
     }
+    
+    public int getLine(int pc) {
+        if(pc < 0 || pc >= size) return -1;
+        return line[pc];
+    }
 
 
     // Invoking the Bytecode ///////////////////////////////////////////////////////
         
-    int pc = 0;
     void eval(JS.Scope s) {
         final JS.Thread cx = JS.Thread.fromJavaThread(java.lang.Thread.currentThread());
         final Vec t = cx.stack;
+        int pc;
+        int lastPC = -1;
         OUTER: for(pc=0; pc<size; pc++) {
             String label = null;
-            cx.line = line[pc];
+            cx.pc = lastPC = pc;
             switch(op[pc]) {
             case LITERAL: t.push(arg[pc]); break;
             case OBJECT: t.push(new JS.Obj()); break;
@@ -343,8 +353,32 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
                 } }
             }
         }
+        // this should never happen, we will ALWAYS have a RETURN at the end of the func
+        throw new Error("Just fell out of CompiledFunction::eval() loop. Last PC was " + lastPC);
     }
 
+    // Debugging //////////////////////////////////////////////////////////////////////
+
+    public String toString() {
+        StringBuffer sb = new StringBuffer(1024);
+        sb.append("\n" + sourceName + ": " + firstLine + "\n");
+        for (int i=0; i < size; i++) {
+            sb.append(i);
+            sb.append(": ");
+            if (op[i] < 0)
+                sb.append(bytecodeToString[-op[i]]);
+            else
+                sb.append(codeToString[op[i]]);
+            sb.append(" ");
+            sb.append(arg[i] == null ? "(no arg)" : arg[i]);
+            if((op[i] == JF || op[i] == JT || op[i] == JMP) && arg[i] != null && arg[i] instanceof Number) {
+                sb.append(" jump to ");
+                sb.append(i+((Number) arg[i]).intValue());
+            }
+            sb.append("\n");
+        }
+        return sb.toString();
+    } 
 
     // Helpers for Number, String, and Boolean ////////////////////////////////////////
 
@@ -405,8 +439,8 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
     // Exception Stuff ////////////////////////////////////////////////////////////////
 
     static class EvaluatorException extends RuntimeException { public EvaluatorException(String s) { super(s); } }
-    EvaluatorException ee(String s) { throw new EvaluatorException(sourceName + ":" + line[pc] + " " + s); }
-    JS.Exn je(String s) { throw new JS.Exn(sourceName + ":" + line[pc] + " " + s); }
+    EvaluatorException ee(String s) { throw new EvaluatorException(sourceName + ":" + JS.Thread.currentJSThread().getLine() + " " + s); }
+    JS.Exn je(String s) { throw new JS.Exn(sourceName + ":" + JS.Thread.currentJSThread().getLine() + " " + s); }
 
 
     // FunctionScope /////////////////////////////////////////////////////////////////
index 9cd65ee..48eb61b 100644 (file)
@@ -139,13 +139,13 @@ public abstract class JS {
 
         CompiledFunction currentCompiledFunction = null;
         Vec stack = new Vec();
-        int line = -1;
+        int pc;
 
         /** binds this thread to the current Java Thread */
         public void bindToCurrentJavaThread() { javaThreadToJSThread.put(java.lang.Thread.currentThread(), this); }
 
         /** returns the line of code that is currently executing */
-        public int getLine() { return line; }
+        public int getLine() { return currentCompiledFunction == null ? -1 : currentCompiledFunction.getLine(pc); }
 
         /** returns the name of the source code file which declared the currently executing function */
         public String getSourceName() { return currentCompiledFunction == null ? null : currentCompiledFunction.getSourceName();  }
@@ -168,6 +168,9 @@ public abstract class JS {
             return ret;
         }
         
+        public static JS.Thread currentJSThread() {
+            return fromJavaThread(java.lang.Thread.currentThread());
+        }
     }
 } 
 
index 2c7eb32..558d34a 100644 (file)
@@ -91,6 +91,7 @@ class Math extends JS.Obj {
         put("min", min);
         put("pow", pow);
         put("random", random);
+        put("round",round);
         put("sin", sin);
         put("sqrt", sqrt);
         put("tan", tan);
index fd85881..694d3ee 100644 (file)
@@ -30,26 +30,30 @@ public class Regexp extends JS.Obj {
                 }
             }
             re = newRE(pattern,flags);
-            put("source",pattern);
-            put("global",wrapBool(global));
-            put("ignoreCase",wrapBool(flags & RE.REG_ICASE));
-            put("multiline",wrapBool(flags & RE.REG_MULTILINE));
+            _put("source",pattern);
+            _put("global",wrapBool(global));
+            _put("ignoreCase",wrapBool(flags & RE.REG_ICASE));
+            _put("multiline",wrapBool(flags & RE.REG_MULTILINE));
         }
         // FIXME: Do whatever we need to do to take advantage of the GETCALL bytecode when its available
         final JS.Callable execFN = new JS.Callable() { public Object call(JS.Array args) { return exec(args); } };
         final JS.Callable testFN = new JS.Callable() { public Object call(JS.Array args) { return test(args); } };
         final JS.Callable toStringFN = new JS.Callable() { public Object call(JS.Array args) { return Regexp.this.toString(); } };
-        put("exec",execFN);
-        put("test",testFN);
-        put("toString",toStringFN);
+        _put("exec",execFN);
+        _put("test",testFN);
+        _put("toString",toStringFN);
     }
     
-    public Object get(Object key) {
+    // gcj bug...
+    public Object get(Object key) { return _get(key); }
+    public void put(Object key,Object value) { _put(key,value); }
+
+    public Object _get(Object key) {
         if(key.equals("lastIndex")) return new Integer(lastIndex);
         return super.get(key);
     }
     
-    public void put(Object key, Object value) {
+    public void _put(Object key, Object value) {
         if(key.equals("lastIndex")) lastIndex = JS.toNumber(value).intValue();
         super.put(key,value);
     }
@@ -111,11 +115,11 @@ public class Regexp extends JS.Obj {
     public String toString() {
         StringBuffer sb = new StringBuffer();
         sb.append('/');
-        sb.append(get("source"));
+        sb.append(_get("source"));
         sb.append('/');
         if(global) sb.append('g');
-        if(Boolean.TRUE.equals(get("ignoreCase"))) sb.append('i');
-        if(Boolean.TRUE.equals(get("multiline"))) sb.append('m');
+        if(Boolean.TRUE.equals(_get("ignoreCase"))) sb.append('i');
+        if(Boolean.TRUE.equals(_get("multiline"))) sb.append('m');
         return sb.toString();
     }