2003/06/29 21:20:38
[org.ibex.core.git] / src / org / xwt / js / CompiledFunctionImpl.java
index 9511333..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;
@@ -223,7 +233,7 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
                 }
                 Object ret = null;
                 if (o == null) throw je("tried to get property \"" + v + "\" from the null value");
-                if (v == null) throw je("tried to get the null key from " + v);
+                if (v == null) throw je("tried to get the null key from " + o);
                 if (o instanceof String) {
                     ret = getFromString((String)o, v);
                 } else if (o instanceof Boolean) {
@@ -331,6 +341,7 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
                     boolean ret;
                     if (l == null) { Object tmp = r; r = l; l = tmp; }
                     if (l == null && r == null) ret = true;
+                    else if (r == null) ret = false; // l != null, so its false
                     else if (l instanceof Boolean) ret = new Boolean(JS.toBoolean(r)).equals(l);
                     else if (l instanceof Number) ret = JS.toNumber(r).doubleValue() == JS.toNumber(l).doubleValue();
                     else if (l instanceof String) ret = r != null && l.equals(r.toString());
@@ -342,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 ////////////////////////////////////////
 
@@ -379,6 +414,24 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
                     if (args.length() != 1) return null;
                     return new Integer(((String)o).indexOf(args.elementAt(0).toString()));
                 } };
+        else if(v.equals("match")) return new JS.Callable() {
+                public Object call(JS.Array args) {
+                    return Regexp.stringMatch(o,args);
+                } };
+        else if(v.equals("search")) return new JS.Callable() {
+                public Object call(JS.Array args) {
+                    return Regexp.stringSearch(o,args);
+                } };
+        else if(v.equals("replace")) return new JS.Callable() {
+                public Object call(JS.Array args) {
+                    return Regexp.stringReplace(o,args);
+                } };
+        else if(v.equals("split")) return new JS.Callable() {
+                public Object call(JS.Array args) {
+                    return Regexp.stringSplit(o,args);
+                } };
+                        
+                        
         throw new JS.Exn("Not Implemented: propery " + v + " on String objects");
     }
 
@@ -386,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 /////////////////////////////////////////////////////////////////
@@ -398,6 +451,7 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
         public String getSourceName() { return sourceName; }
         public Object get(Object key) throws JS.Exn {
             if (key.equals("trapee")) return org.xwt.Trap.currentTrapee();
+            else if (key.equals("trapname")) return org.xwt.Trap.currentTrapname();
             else if (key.equals("cascade")) return org.xwt.Trap.cascadeFunction;
             return super.get(key);
         }
@@ -426,6 +480,7 @@ class CompiledFunctionImpl extends JSCallable implements ByteCodes, Tokens {
 
 }
 
+/** this class exists solely to work around a GCJ bug */
 abstract class JSCallable extends JS.Callable {
         public abstract Object call(JS.Array args) throws JS.Exn;
 }