1 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
8 // FIXME: could use some cleaning up...
10 /** A JavaScript Array */
11 class ArrayImpl extends JS.Obj {
12 private Vec vec = new Vec();
13 public ArrayImpl() { }
14 public ArrayImpl(int size) { vec.setSize(size); }
15 private static int intVal(Object o) {
16 if (o instanceof Number) {
17 int intVal = ((Number)o).intValue();
18 if (intVal == ((Number)o).doubleValue()) return intVal;
19 return Integer.MIN_VALUE;
21 if (!(o instanceof String)) return Integer.MIN_VALUE;
23 for(int i=0; i<s.length(); i++) if (s.charAt(i) < '0' || s.charAt(i) > '9') return Integer.MIN_VALUE;
24 return Integer.parseInt(s);
27 public Object callMethod(Object method, JS.Array args,boolean justChecking) {
28 if(method.equals("push")) {
29 if(justChecking) return Boolean.TRUE;
30 for(int i=0;i<args.length();i++)
31 vec.push(args.elementAt(i));
32 return new Integer(vec.size());
34 if(method.equals("pop")) {
35 if(justChecking) return Boolean.TRUE;
36 return vec.pop(); // this'll return null on size()==0
38 if(method.equals("shift")) {
39 if(justChecking) return Boolean.TRUE;
41 Object o = vec.elementAt(0);
42 vec.removeElementAt(0);
48 if(method.equals("unshift")) {
49 if(justChecking) return Boolean.TRUE;
50 // FIXME: could be optimized a bit with some help from Vec
51 for(int i=0;i<args.length();i++)
52 vec.insertElementAt(args.elementAt(i),i);
53 return new Integer(vec.size());
55 if(method.equals("slice")) return justChecking ? Boolean.TRUE : slice(args);
56 if(method.equals("join")) return justChecking ? Boolean.TRUE : join(args);
57 if(method.equals("reverse")) return justChecking ? Boolean.TRUE : reverse(args);
58 if(method.equals("toString")) return justChecking ? Boolean.TRUE : join(",");
59 if(method.equals("sort")) return justChecking ? Boolean.TRUE : sort(args);
60 if(method.equals("splice")) return justChecking ? Boolean.TRUE : splice(args);
61 return super.callMethod(method,args,justChecking);
65 // we use _get instead of get solely to work around a GCJ bug
66 public Object _get(Object key) throws JS.Exn {
67 if (key.equals("length")) return new Long(vec.size());
70 if (i == Integer.MIN_VALUE) return super.get(key);
72 return vec.elementAt(i);
73 } catch (ArrayIndexOutOfBoundsException e) {
77 // we use _put instead of put solely to work around a GCJ bug
78 public void _put(Object key, Object val) {
79 if (key.equals("length")) vec.setSize(toNumber(val).intValue());
81 if (i == Integer.MIN_VALUE) super.put(key, val);
83 if (i >= vec.size()) vec.setSize(i+1);
84 vec.setElementAt(val, i);
87 public Object[] keys() {
88 Object[] sup = super.keys();
89 Object[] ret = new Object[vec.size() + 1 + sup.length];
90 System.arraycopy(sup, 0, ret, vec.size(), sup.length);
91 for(int i=0; i<vec.size(); i++) ret[i] = new Integer(i);
92 ret[vec.size()] = "length";
95 public void setSize(int i) { vec.setSize(i); }
96 public int length() { return vec.size(); }
97 public Object elementAt(int i) { return vec.elementAt(i); }
98 public void addElement(Object o) { vec.addElement(o); }
99 public void setElementAt(Object o, int i) { vec.setElementAt(o, i); }
101 public String typeName() { return "array"; }
103 private Object join(JS.Array args) {
104 return join(args.length() == 0 ? "," : JS.toString(args.elementAt(0)));
107 private Object join(String sep) {
108 int length = vec.size();
109 if(length == 0) return "";
110 StringBuffer sb = new StringBuffer(64);
113 Object o = elementAt(i);
114 if(o != null) sb.append(JS.toString(o));
115 if(++i == length) break;
118 return sb.toString();
121 private Object reverse(JS.Array args) {
123 int size = oldVec.size();
124 if(size < 2) return this;
126 for(int i=size-1;i>=0;i--)
127 vec.addElement(oldVec.elementAt(i));
131 private Object slice(JS.Array args) {
132 int length = length();
133 int start = JS.toInt(args.length() < 1 ? null : args.elementAt(0));
134 int end = args.length() < 2 ? length : JS.toInt(args.elementAt(1));
135 if(start < 0) start = length+start;
136 if(end < 0) end = length+end;
137 if(start < 0) start = 0;
139 if(start > length) start = length;
140 if(end > length) end = length;
141 JS.Array a = new JS.Array(end-start);
142 for(int i=0;i<end-start;i++)
143 a.setElementAt(elementAt(start+i),i);
147 private static final Vec.CompareFunc defaultSort = new Vec.CompareFunc() {
148 public int compare(Object a, Object b) {
149 return JS.toString(a).compareTo(JS.toString(b));
152 private Object sort(JS.Array args) {
153 Object tmp = args.length() < 1 ? null : args.elementAt(0);
154 if(tmp instanceof JS.Callable) {
155 final JS.Array funcArgs = new JS.Array(2);
156 final JS.Callable jsFunc = (JS.Callable) tmp;
157 vec.sort(new Vec.CompareFunc() {
158 public int compare(Object a, Object b) {
159 funcArgs.setElementAt(a,0);
160 funcArgs.setElementAt(b,1);
161 return JS.toInt(jsFunc.call(funcArgs));
165 vec.sort(defaultSort);
170 private Object splice(JS.Array args) {
171 int oldLength = length();
172 int start = JS.toInt(args.length() < 1 ? null : args.elementAt(0));
173 int deleteCount = JS.toInt(args.length() < 2 ? null : args.elementAt(1));
174 int newCount = args.length() - 2;
175 if(newCount < 0) newCount = 0;
176 if(start < 0) start = oldLength+start;
177 if(start < 0) start = 0;
178 if(start > oldLength) start = oldLength;
179 if(deleteCount < 0) deleteCount = 0;
180 if(deleteCount > oldLength-start) deleteCount = oldLength-start;
181 int newLength = oldLength - deleteCount + newCount;
182 int lengthChange = newLength - oldLength;
183 JS.Array ret = new JS.Array(deleteCount);
184 for(int i=0;i<deleteCount;i++)
185 ret.setElementAt(elementAt(start+i),i);
186 if(lengthChange > 0) {
188 for(int i=newLength-1;i>=start+newCount;i--)
189 setElementAt(elementAt(i-lengthChange),i);
190 } else if(lengthChange < 0) {
191 for(int i=start+newCount;i<newLength;i++)
192 setElementAt(elementAt(i-lengthChange),i);
195 for(int i=0;i<newCount;i++)
196 setElementAt(args.elementAt(i+2),start+i);
200 public String coerceToString() { return JS.toString(join(",")); }