2004/01/07 20:37:33
[org.ibex.core.git] / src / org / xwt / js / JSArray.java
index 880e64f..a5798bf 100644 (file)
@@ -2,14 +2,15 @@
 package org.xwt.js; 
 
 import org.xwt.util.*; 
-import java.io.*;
 import java.util.*;
 
 /** A JavaScript JSArray */
-public class JSArray extends JSCallable {
-    private Vec vec = new Vec();
+public class JSArray extends JS {
+    private static final Object NULL = new Object();
+    
     public JSArray() { }
-    public JSArray(int size) { vec.setSize(size); }
+    public JSArray(int size) { setSize(size); }
+    
     private static int intVal(Object o) {
         if (o instanceof Number) {
             int intVal = ((Number)o).intValue();
@@ -22,86 +23,126 @@ public class JSArray extends JSCallable {
         return Integer.parseInt(s);
     }
     
-    public Object call(Object method, JSArray args) {
-        if(method.equals("push")) {
-            for(int i=0;i<args.length();i++)
-                vec.push(args.elementAt(i));
-            return new Integer(vec.size());
+    public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
+        //#switch(method)
+        case "pop": {
+            int oldSize = size();
+            if(oldSize == 0) return null;
+            return removeElementAt(oldSize-1);
         }
-        if(method.equals("pop")) {
-            return vec.pop(); // this'll return null on size()==0 
+        case "reverse": return reverse();
+        case "toString": return join(",");
+        case "shift":
+            if(length() == 0) return null;
+            return removeElementAt(0);
+        case "join":
+            return join(nargs == 0 ? "," : JS.toString(a0));
+        case "sort":
+            return sort(nargs < 1 ? null : a0);
+        case "slice":
+            int start = toInt(nargs < 1 ? null : a0);
+            int end = nargs < 2 ? length() : toInt(a1);
+            return slice(start, end);
+        case "push": {
+            int oldSize = size();
+            for(int i=0; i<nargs; i++) insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3],oldSize+i);
+            return N(oldSize + nargs);
         }
-        if(method.equals("shift")) {
-            if(length() > 0) {
-                Object o = vec.elementAt(0);
-                vec.removeElementAt(0);
-                return o;
-            } else {
-                return null;
-            }
-        }
-        if(method.equals("unshift")) {
-            // FEATURE: could be optimized a bit with some help from Vec
-            for(int i=0;i<args.length();i++)
-                vec.insertElementAt(args.elementAt(i),i);
-            return new Integer(vec.size());
-        }
-        if(method.equals("slice")) return slice(args);
-        if(method.equals("join")) return join(args);
-        if(method.equals("reverse")) return reverse(args);
-        if(method.equals("toString")) return join(",");
-        if(method.equals("sort")) return sort(args);
-        if(method.equals("splice")) return splice(args);
-        throw new JS.Exn("unknown method " + method);
+        case "unshift":
+            for(int i=0; i<nargs; i++) insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3],i);
+            return N(size());
+        case "splice":
+            JSArray array = new JSArray();
+            for(int i=0; i<nargs; i++) array.addElement(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
+            return splice(array);
+        //#end
+        return super.callMethod(method, a0, a1, a2, rest, nargs);
     }
         
-    public Object get(Object key) throws JS.Exn {
-        if (key.equals("length")) return new Long(vec.size());
-                
+    public Object get(Object key) throws JSExn {
         int i = intVal(key);
-        if (i == Integer.MIN_VALUE) return super.get(key);
-        try {
-            return vec.elementAt(i);
-        } catch (ArrayIndexOutOfBoundsException e) {
-            return null;
+        if (i != Integer.MIN_VALUE) {
+            if (i < 0 || i >= size()) return null;
+            return elementAt(i);
         }
+        //#switch(key)
+        case "pop": return METHOD;
+        case "reverse": return METHOD;
+        case "toString": return METHOD;
+        case "shift": return METHOD;
+        case "join": return METHOD;
+        case "sort": return METHOD;
+        case "slice": return METHOD;
+        case "push": return METHOD;
+        case "unshift": return METHOD;
+        case "splice": return METHOD;
+        case "length": return N(size());
+        //#end
+        return super.get(key);
     }
 
-    public void put(Object key, Object val) {
-        if (key.equals("length")) vec.setSize(toNumber(val).intValue());
+    public void put(Object key, Object val) throws JSExn {
+        if (key.equals("length")) setSize(toInt(val));
         int i = intVal(key);
-        if (i == Integer.MIN_VALUE) super.put(key, val);
+        if (i == Integer.MIN_VALUE)
+            super.put(key, val);
         else {
-            if (i >= vec.size()) vec.setSize(i+1);
-            vec.setElementAt(val, i);
+            int oldSize = size();
+            if(i < oldSize) {
+                setElementAt(val,i);
+            } else {
+                if(i > oldSize) setSize(i);
+                insertElementAt(val,i);
+            }
         }
     }
 
     public Enumeration keys() {
         return new Enumeration() {
                 int cur = 0;
-                public boolean hasMoreElements() { return cur >= vec.size(); }
+                public boolean hasMoreElements() { return cur >= size(); }
                 public Object nextElement() {
-                    if (cur >= vec.size()) throw new NoSuchElementException();
+                    if (cur >= size()) throw new NoSuchElementException();
                     return new Integer(cur++);
                 }
             };
     }
 
-    public void setSize(int i) { vec.setSize(i); }
-    public int length() { return vec.size(); }
-    public Object elementAt(int i) { return vec.elementAt(i); }
-    public void addElement(Object o) { vec.addElement(o); }
-    public void setElementAt(Object o, int i) { vec.setElementAt(o, i); }
-    public int size() { return vec.size(); }
-    public String typeName() { return "array"; }
-        
-    private Object join(JSArray args) {
-        return join(args.length() == 0 ? "," : JS.toString(args.elementAt(0)));
+    public final void setSize(int newSize) {
+        // FEATURE: This could be done a lot more efficiently in BalancedTree
+        int oldSize = size();
+        for(int i=oldSize;i<newSize;i++) insertElementAt(null,i);
+        for(int i=oldSize-1;i>=newSize;i--) removeElementAt(i);
     }
     
+    public final int length() { return size(); }
+    public final Object elementAt(int i) { 
+        if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
+        Object o = getNode(i);
+        return o == NULL ? null : o;
+    }
+    public final void addElement(Object o) { 
+        insertNode(size(),o==null ? NULL : o);
+    }
+    public final void setElementAt(Object o, int i) {
+        if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
+        replaceNode(i,o==null ? NULL : o);
+    }
+    public final void insertElementAt(Object o, int i) {
+        if(i < 0 || i > size()) throw new ArrayIndexOutOfBoundsException(i);
+        insertNode(i,o==null ? NULL : o);
+    }
+    public final Object removeElementAt(int i) {
+        if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
+        Object o = deleteNode(i);
+        return o == NULL ? null : o;
+    }
+    
+    public final int size() { return treeSize(); }
+    public String typeName() { return "array"; }
+        
     private Object join(String sep) {
-        int length = vec.size();
+        int length = size();
         if(length == 0) return "";
         StringBuffer sb = new StringBuffer(64);
         int i=0;
@@ -114,20 +155,18 @@ public class JSArray extends JSCallable {
         return sb.toString();
     }
     
-    private Object reverse(JSArray args) {
-        Vec oldVec = vec;
-        int size = oldVec.size();
+    // FEATURE: Implement this more efficiently
+    private Object reverse() {
+        int size = size();
         if(size < 2) return this;
-        vec = new Vec(size);
-        for(int i=size-1;i>=0;i--)
-            vec.addElement(oldVec.elementAt(i));
+        Vec vec = toVec();
+        clear();
+        for(int i=size-1,j=0;i>=0;i--,j++) insertElementAt(vec.elementAt(i),j);
         return this;
     }
     
-    private Object slice(JSArray args) {
+    private Object slice(int start, int end) {
         int length = length();
-        int start = JS.toInt(args.length() < 1 ? null : args.elementAt(0));
-        int end = args.length() < 2 ? length : JS.toInt(args.elementAt(1));
         if(start < 0) start = length+start;
         if(end < 0) end = length+end;
         if(start < 0) start = 0;
@@ -145,21 +184,27 @@ public class JSArray extends JSCallable {
             return JS.toString(a).compareTo(JS.toString(b));
         }
     };
-    private Object sort(JSArray args) {
-        Object tmp = args.length() < 1 ? null : args.elementAt(0);
-        if(tmp instanceof JSCallable) {
+    private Object sort(Object tmp) throws JSExn {
+        Vec vec = toVec();
+        if(tmp instanceof JS) {
             final JSArray funcArgs = new JSArray(2);
-            final JSCallable jsFunc = (JSCallable) tmp;
+            final JS jsFunc = (JS) tmp;
             vec.sort(new Vec.CompareFunc() {
                 public int compare(Object a, Object b) {
-                    funcArgs.setElementAt(a,0);
-                    funcArgs.setElementAt(b,1);
-                    return JS.toInt(jsFunc.call(null, funcArgs));
+                    try {
+                        funcArgs.setElementAt(a,0);
+                        funcArgs.setElementAt(b,1);
+                        return JS.toInt(jsFunc.call(a, b, null, null, 2));
+                    } catch (Exception e) {
+                        // FIXME
+                        throw new JSRuntimeExn(e.toString());
+                    }
                 }
             });
         } else {
             vec.sort(defaultSort);
         }
+        setFromVec(vec);
         return this;
     }
     
@@ -193,5 +238,25 @@ public class JSArray extends JSCallable {
         return ret;
     }
     
-     public String coerceToString() { return JS.toString(join(",")); }
+    protected Vec toVec() {
+        int count = size();
+        Vec vec = new Vec();
+        vec.setSize(count);
+        for(int i=0;i<count;i++) {
+            Object o = getNode(i);
+            vec.setElementAt(o == NULL ? null : o,i);
+        }
+        return vec;
+    }
+    
+    protected void setFromVec(Vec vec) {
+        int count = vec.size();
+        clear();
+        for(int i=0;i<count;i++) {
+            Object o = vec.elementAt(i);
+            insertNode(i,o==null ? NULL : o);
+        }
+    }
+    
+    public String coerceToString() { return JS.toString(join(",")); }
 }