2003/06/16 07:58:57
[org.ibex.core.git] / src / org / xwt / js / CompiledFunctionImpl.java
similarity index 89%
rename from src/org/xwt/js/CompiledFunction.java
rename to src/org/xwt/js/CompiledFunctionImpl.java
index ac14075..ae92d06 100644 (file)
@@ -5,7 +5,7 @@ import org.xwt.util.*;
 import java.io.*;
 
 /** a JavaScript function, compiled into bytecode */
-public final class CompiledFunction extends JS.Callable implements ByteCodes, Tokens {
+public class CompiledFunctionImpl extends JS.Callable implements ByteCodes, Tokens {
 
     // Fields and Accessors ///////////////////////////////////////////////
 
@@ -30,27 +30,23 @@ public final class CompiledFunction extends JS.Callable implements ByteCodes, To
     private int size = 0;
     int size() { return size; }
 
-    /** the scope in which this function was declared */
+    /** the scope in which this function was declared; by default this function is called in a fresh subscope of the parentScope */
     private JS.Scope parentScope;
-    JS.Scope getParentScope() { return parentScope; }
 
 
     // Constructors ////////////////////////////////////////////////////////
 
-    public CompiledFunction cloneWithNewParentScope(JS.Scope s) throws IOException {
-       CompiledFunction ret = new CompiledFunction(sourceName, firstLine, s);
+    private CompiledFunctionImpl cloneWithNewParentScope(JS.Scope s) throws IOException {
+       CompiledFunctionImpl ret = new JS.CompiledFunction(sourceName, firstLine, null, s);
        ret.paste(this);
        return ret;
     }
 
-    CompiledFunction(String sourceName, int firstLine, JS.Scope parentScope) throws IOException {
+    protected CompiledFunctionImpl(String sourceName, int firstLine, Reader sourceCode, JS.Scope parentScope) throws IOException {
        this.sourceName = sourceName;
        this.firstLine = firstLine;
        this.parentScope = parentScope;
-    }
-
-    CompiledFunction(String sourceName, int firstLine, Reader sourceCode, JS.Scope parentScope) throws IOException {
-       this(sourceName, firstLine, parentScope);
+       if (sourceCode == null) return;
        Parser p = new Parser(sourceCode, sourceName, firstLine);
        try {
            while(true) {
@@ -64,18 +60,16 @@ public final class CompiledFunction extends JS.Callable implements ByteCodes, To
        }
     }
     
-    public Object call(Array args) throws JS.Exn {
-       CompiledFunction saved = (CompiledFunction)Context.currentFunction.get(Thread.currentThread());
+    public Object call(JS.Array args) throws JS.Exn { return call(args, new FunctionScope(sourceName, parentScope)); }
+    public Object call(JS.Array args, JS.Scope scope) throws JS.Exn {
+       CompiledFunctionImpl saved = (CompiledFunctionImpl)Context.currentFunction.get(Thread.currentThread());
        try {
            Context.currentFunction.put(Thread.currentThread(), this);
            Context cx = Context.getContextForThread(Thread.currentThread());
            int size = cx.stack.size();
            cx.stack.push(new Context.CallMarker());
            cx.stack.push(args);
-           
-           // FIXME, ugly
-           eval(args == null ? parentScope : new FunctionScope(sourceName, parentScope));
-           
+           eval(scope);
            Object ret = cx.stack.pop();
            if (cx.stack.size() > size)
                Log.log(this, "warning, stack grew by " + (cx.stack.size() - size) +
@@ -93,9 +87,9 @@ public final class CompiledFunction extends JS.Callable implements ByteCodes, To
     int get(int pos) { return op[pos]; }
     void set(int pos, int op_, Object arg_) { op[pos] = op_; arg[pos] = arg_; }
     void set(int pos, Object arg_) { arg[pos] = arg_; }
-    void paste(CompiledFunction other) { for(int i=0; i<other.size; i++) add(other.line[i], other.op[i], other.arg[i]); }
-    CompiledFunction add(int line, int op_) { return add(line, op_, null); }
-    CompiledFunction add(int line, int op_, Object arg_) {
+    void paste(CompiledFunctionImpl other) { for(int i=0; i<other.size; i++) add(other.line[i], other.op[i], other.arg[i]); }
+    CompiledFunctionImpl add(int line, int op_) { return add(line, op_, null); }
+    CompiledFunctionImpl add(int line, int op_, Object arg_) {
         if (size == op.length - 1) {
             int[] line2 = new int[op.length * 2]; System.arraycopy(this.line, 0, line2, 0, op.length); this.line = line2;
             Object[] arg2 = new Object[op.length * 2]; System.arraycopy(arg, 0, arg2, 0, arg.length); arg = arg2;
@@ -119,7 +113,7 @@ public final class CompiledFunction extends JS.Callable implements ByteCodes, To
            switch(op[pc]) {
             case LITERAL: t.push(arg[pc]); break;
             case OBJECT: t.push(new JS.Obj()); break;
-            case ARRAY: t.push(new Array(JS.toNumber(arg[pc]).intValue())); break;
+            case ARRAY: t.push(new JS.Array(JS.toNumber(arg[pc]).intValue())); break;
             case DECLARE: s.declare((String)t.pop()); break;
             case TOPSCOPE: t.push(s); break;
             case JT: if (JS.toBoolean(t.pop())) pc += JS.toNumber(arg[pc]).intValue() - 1; break;
@@ -128,8 +122,8 @@ public final class CompiledFunction extends JS.Callable implements ByteCodes, To
             case POP: t.pop(); break;
             case SWAP: { Object o1 = t.pop(); Object o2 = t.pop(); t.push(o1); t.push(o2); break; }
             case DUP: t.push(t.peek()); break;
-            case NEWSCOPE: s = new JS.Scope(s); break;
-           case OLDSCOPE: s = s.getParentScope(); break;
+            case NEWSCOPE: /*s = new JS.Scope(s);*/ break;
+           case OLDSCOPE: /*s = s.getParentScope();*/ break;
             case ASSERT: if (!JS.toBoolean(t.pop())) throw je("assertion failed"); break;
             case BITNOT: t.push(new Long(~JS.toLong(t.pop()))); break;
             case BANG: t.push(new Boolean(!JS.toBoolean(t.pop()))); break;
@@ -147,9 +141,8 @@ public final class CompiledFunction extends JS.Callable implements ByteCodes, To
            }
 
             case NEWFUNCTION: {
-               CompiledFunction bytes = (CompiledFunction)arg[pc];
                try {
-                   t.push(bytes.cloneWithNewParentScope(s));
+                   t.push(((CompiledFunctionImpl)arg[pc]).cloneWithNewParentScope(s));
                } catch (IOException e) {
                    throw new Error("this should never happen");
                }
@@ -159,7 +152,7 @@ public final class CompiledFunction extends JS.Callable implements ByteCodes, To
             case PUSHKEYS: {
                 Object o = t.peek();
                 Object[] keys = ((JS)o).keys();
-                Array a = new Array();
+                JS.Array a = new JS.Array();
                 a.setSize(keys.length);
                 for(int j=0; j<keys.length; j++) a.setElementAt(keys[j], j);
                 t.push(a);
@@ -250,7 +243,7 @@ public final class CompiledFunction extends JS.Callable implements ByteCodes, To
             }
                     
             case CALL: {
-                Array arguments = new Array();
+                JS.Array arguments = new JS.Array();
                 int numArgs = JS.toNumber(arg[pc]).intValue();
                 arguments.setSize(numArgs);
                 for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(t.pop(), j);
@@ -362,7 +355,7 @@ public final class CompiledFunction extends JS.Callable implements ByteCodes, To
     private Object getFromString(final String o, final Object v) {
        if (v.equals("length")) return new Integer(((String)o).length());
        else if (v.equals("substring")) return new JS.Callable() {
-               public Object call(Array args) {
+               public Object call(JS.Array args) {
                    if (args.length() == 1) return ((String)o).substring(JS.toNumber(args.elementAt(0)).intValue());
                    else if (args.length() == 2) return ((String)o).substring(JS.toNumber(args.elementAt(0)).intValue(),
                                                                              JS.toNumber(args.elementAt(1)).intValue());
@@ -370,24 +363,24 @@ public final class CompiledFunction extends JS.Callable implements ByteCodes, To
                }
            };
        else if (v.equals("toLowerCase")) return new JS.Callable() {
-               public Object call(Array args) {
+               public Object call(JS.Array args) {
                    return ((String)o).toLowerCase();
                } };
        else if (v.equals("toUpperCase")) return new JS.Callable() {
-               public Object call(Array args) {
+               public Object call(JS.Array args) {
                    return ((String)o).toString().toUpperCase();
                } };
        else if (v.equals("charAt")) return new JS.Callable() {
-               public Object call(Array args) {
+               public Object call(JS.Array args) {
                    return ((String)o).charAt(JS.toNumber(args.elementAt(0)).intValue()) + "";
                } };
        else if (v.equals("lastIndexOf")) return new JS.Callable() {
-               public Object call(Array args) {
+               public Object call(JS.Array args) {
                    if (args.length() != 1) return null;
                    return new Integer(((String)o).lastIndexOf(args.elementAt(0).toString()));
                } };
        else if (v.equals("indexOf")) return new JS.Callable() {
-               public Object call(Array args) {
+               public Object call(JS.Array args) {
                    if (args.length() != 1) return null;
                    return new Integer(((String)o).indexOf(args.elementAt(0).toString()));
                } };