2003/07/28 23:10:27
authorbrian <brian@xwt.org>
Fri, 30 Jan 2004 07:04:10 +0000 (07:04 +0000)
committerbrian <brian@xwt.org>
Fri, 30 Jan 2004 07:04:10 +0000 (07:04 +0000)
darcs-hash:20040130070410-aa32f-27702bdf7b8aeccf33e486f7547ad8eac2521421.gz

src/org/xwt/js/ArrayImpl.java
src/org/xwt/util/Vec.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(",")); }
 }
-
index 803ce3f..a602089 100644 (file)
@@ -116,4 +116,47 @@ public final class Vec implements Serializable {
         size++;
     }
     
+    public interface CompareFunc {
+        public int compare(Object a, Object b);
+    }
+    
+    public void sort(CompareFunc c) {
+        sort(c,0,size-1);
+    }
+    
+    private final void swap(int a, int b) {
+        if(a != b) {
+            Object tmp = store[a];
+            store[a] = store[b];
+            store[b] = tmp;
+        }
+    }
+    
+    private void sort(CompareFunc c, int start, int end) {
+        Object tmp;
+        if(start >= end) return;
+        if(end-start <= 6) {
+            for(int i=start+1;i<=end;i++) {
+                tmp = store[i];
+                int j;
+                for(j=i-1;j>=start;j--) {
+                    if(c.compare(store[j],tmp) <= 0) break;
+                    store[j+1] = store[j];
+                }
+                store[j+1] = tmp;
+            }
+            return;
+        }
+        Object pivot = store[end];
+        int lo = start - 1;
+        int hi = end;
+        do {
+            while(c.compare(store[++lo],pivot) < 0) { }
+            while((hi > lo) && c.compare(store[--hi],pivot) > 0) { }
+            swap(lo,hi);
+        } while(lo < hi);
+        swap(lo,end);
+        sort(c,start,lo-1);
+        sort(c,lo+1,end);
+    }
 }