2003/07/28 23:10:27
[org.ibex.core.git] / src / org / xwt / js / ArrayImpl.java
index 110b301..f76e29a 100644 (file)
@@ -6,7 +6,6 @@ import java.io.*;
 import java.util.*;
 
 // FIXME: could use some cleaning up...
-// FIXME: Finish implementing ECMA-262
 
 /** A JavaScript Array */
 class ArrayImpl extends JS.Obj {
@@ -24,21 +23,48 @@ class ArrayImpl extends JS.Obj {
         for(int i=0; i<s.length(); i++) if (s.charAt(i) < '0' || s.charAt(i) > '9') return Integer.MIN_VALUE;
         return Integer.parseInt(s);
     }
+    
+    public Object callMethod(Object method, JS.Array args,boolean justChecking) {
+        if(method.equals("push")) {
+            if(justChecking) return Boolean.TRUE;
+            for(int i=0;i<args.length();i++)
+                vec.push(args.elementAt(i));
+            return new Integer(vec.size());
+        }
+        if(method.equals("pop")) {
+            if(justChecking) return Boolean.TRUE;
+            return vec.pop(); // this'll return null on size()==0 
+        }
+        if(method.equals("shift")) {
+            if(justChecking) return Boolean.TRUE;
+            if(length() > 0) {
+                Object o = vec.elementAt(0);
+                vec.removeElementAt(0);
+                return o;
+            } else {
+                return null;
+            }
+        }
+        if(method.equals("unshift")) {
+            if(justChecking) return Boolean.TRUE;
+            // FIXME: 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 justChecking ? Boolean.TRUE : slice(args);
+        if(method.equals("join")) return justChecking ? Boolean.TRUE : join(args);
+        if(method.equals("reverse")) return justChecking ? Boolean.TRUE : reverse(args);
+        if(method.equals("toString")) return justChecking ? Boolean.TRUE : join(",");
+        if(method.equals("sort")) return justChecking ? Boolean.TRUE : sort(args);
+        if(method.equals("splice")) return justChecking ? Boolean.TRUE : splice(args);
+        return super.callMethod(method,args,justChecking);
+    }
+        
+        
     // we use _get instead of get solely to work around a GCJ bug
     public Object _get(Object key) throws JS.Exn {
         if (key.equals("length")) return new Long(vec.size());
-        if (key.equals("push")) return new JS.Callable() {
-            public Object call(JS.Array args) {
-                for(int i=0;i<args.length();i++)
-                    vec.push(args.elementAt(i));
-                return new Long(vec.size());
-            }
-        };
-        if (key.equals("pop")) return new JS.Callable() {
-            public Object call(JS.Array args) {
-                return vec.pop(); // this'll return null on size()==0 
-            }
-        };
                 
         int i = intVal(key);
         if (i == Integer.MIN_VALUE) return super.get(key);
@@ -73,5 +99,103 @@ class ArrayImpl extends JS.Obj {
     public void setElementAt(Object o, int i) { vec.setElementAt(o, i); }
     
     public String typeName() { return "array"; }
+        
+    private Object join(JS.Array args) {
+        return join(args.length() == 0 ? "," : JS.toString(args.elementAt(0)));
+    }
+    
+    private Object join(String sep) {
+        int length = vec.size();
+        if(length == 0) return "";
+        StringBuffer sb = new StringBuffer(64);
+        int i=0;
+        while(true) {
+            Object o = elementAt(i);
+            if(o != null) sb.append(JS.toString(o));
+            if(++i == length) break;
+            sb.append(sep);
+        }
+        return sb.toString();
+    }
+    
+    private Object reverse(JS.Array args) {
+        Vec oldVec = vec;
+        int size = oldVec.size();
+        if(size < 2) return this;
+        vec = new Vec(size);
+        for(int i=size-1;i>=0;i--)
+            vec.addElement(oldVec.elementAt(i));
+        return this;
+    }
+    
+    private Object slice(JS.Array args) {
+        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;
+        if(end < 0) end = 0;
+        if(start > length) start = length;
+        if(end > length) end = length;
+        JS.Array a = new JS.Array(end-start);
+        for(int i=0;i<end-start;i++)
+            a.setElementAt(elementAt(start+i),i);
+        return a;
+    }
+    
+    private static final Vec.CompareFunc defaultSort = new Vec.CompareFunc() {
+        public int compare(Object a, Object b) {
+            return JS.toString(a).compareTo(JS.toString(b));
+        }
+    };
+    private Object sort(JS.Array args) {
+        Object tmp = args.length() < 1 ? null : args.elementAt(0);
+        if(tmp instanceof JS.Callable) {
+            final JS.Array funcArgs = new JS.Array(2);
+            final JS.Callable jsFunc = (JS.Callable) 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(funcArgs));
+                }
+            });
+        } else {
+            vec.sort(defaultSort);
+        }
+        return this;
+    }
+    
+    private Object splice(JS.Array args) {
+        int oldLength = length();
+        int start = JS.toInt(args.length() < 1 ? null : args.elementAt(0));
+        int deleteCount = JS.toInt(args.length() < 2 ? null : args.elementAt(1));
+        int newCount = args.length() - 2;
+        if(newCount < 0) newCount = 0;
+        if(start < 0) start = oldLength+start;
+        if(start < 0) start = 0;
+        if(start > oldLength) start = oldLength;
+        if(deleteCount < 0) deleteCount = 0;
+        if(deleteCount > oldLength-start) deleteCount = oldLength-start;
+        int newLength = oldLength - deleteCount + newCount;
+        int lengthChange = newLength - oldLength;
+        JS.Array ret = new JS.Array(deleteCount);
+        for(int i=0;i<deleteCount;i++)
+            ret.setElementAt(elementAt(start+i),i);
+        if(lengthChange > 0) {
+            setSize(newLength);
+            for(int i=newLength-1;i>=start+newCount;i--)
+                setElementAt(elementAt(i-lengthChange),i);
+        } else if(lengthChange < 0) {
+            for(int i=start+newCount;i<newLength;i++)
+                setElementAt(elementAt(i-lengthChange),i);
+            setSize(newLength);
+        }
+        for(int i=0;i<newCount;i++)
+            setElementAt(args.elementAt(i+2),start+i);
+        return ret;
+    }
+    
+     public String coerceToString() { return JS.toString(join(",")); }
 }
-