1 // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
4 import org.ibex.util.*;
7 /** A JavaScript JSArray */
8 public class JSArray extends JS {
9 private static final Object NULL = new Object();
11 private BalancedTree arr = new BalancedTree();
14 public JSArray(int size) { setSize(size); }
16 private static int intVal(Object o) {
17 if (o instanceof Number) {
18 int intVal = ((Number)o).intValue();
19 if (intVal == ((Number)o).doubleValue()) return intVal;
20 return Integer.MIN_VALUE;
22 if (!(o instanceof String)) return Integer.MIN_VALUE;
24 for(int i=0; i<s.length(); i++) if (s.charAt(i) < '0' || s.charAt(i) > '9') return Integer.MIN_VALUE;
25 return Integer.parseInt(s);
28 public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
32 if(oldSize == 0) return null;
33 return removeElementAt(oldSize-1);
35 case "reverse": return reverse();
36 case "toString": return join(",");
38 if(length() == 0) return null;
39 return removeElementAt(0);
41 return join(nargs == 0 ? "," : JS.toString(a0));
43 return sort(nargs < 1 ? null : a0);
45 int start = toInt(nargs < 1 ? null : a0);
46 int end = nargs < 2 ? length() : toInt(a1);
47 return slice(start, end);
50 for(int i=0; i<nargs; i++) insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3],oldSize+i);
51 return N(oldSize + nargs);
54 for(int i=0; i<nargs; i++) insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3],i);
57 JSArray array = new JSArray();
58 for(int i=0; i<nargs; i++) array.addElement(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
61 return super.callMethod(method, a0, a1, a2, rest, nargs);
64 public Object get(Object key) throws JSExn {
66 if (i != Integer.MIN_VALUE) {
67 if (i < 0 || i >= size()) return null;
71 case "pop": return METHOD;
72 case "reverse": return METHOD;
73 case "toString": return METHOD;
74 case "shift": return METHOD;
75 case "join": return METHOD;
76 case "sort": return METHOD;
77 case "slice": return METHOD;
78 case "push": return METHOD;
79 case "unshift": return METHOD;
80 case "splice": return METHOD;
81 case "length": return N(size());
83 return super.get(key);
86 public void put(Object key, Object val) throws JSExn {
87 if (key.equals("length")) setSize(toInt(val));
89 if (i == Integer.MIN_VALUE)
96 if(i > oldSize) setSize(i);
97 insertElementAt(val,i);
102 public Enumeration keys() {
103 return new Enumeration() {
104 private int n = size();
105 public boolean hasMoreElements() { return n > 0; }
106 public Object nextElement() {
107 if(n == 0) throw new NoSuchElementException();
108 return new Integer(--n);
113 public final void setSize(int newSize) {
114 // FEATURE: This could be done a lot more efficiently in BalancedTree
115 int oldSize = size();
116 for(int i=oldSize;i<newSize;i++) insertElementAt(null,i);
117 for(int i=oldSize-1;i>=newSize;i--) removeElementAt(i);
120 public final int length() { return size(); }
121 public final Object elementAt(int i) {
122 if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
123 Object o = arr.getNode(i);
124 return o == NULL ? null : o;
126 public final void addElement(Object o) {
127 arr.insertNode(size(),o==null ? NULL : o);
129 public final void setElementAt(Object o, int i) {
130 if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
131 arr.replaceNode(i,o==null ? NULL : o);
133 public final void insertElementAt(Object o, int i) {
134 if(i < 0 || i > size()) throw new ArrayIndexOutOfBoundsException(i);
135 arr.insertNode(i,o==null ? NULL : o);
137 public final Object removeElementAt(int i) {
138 if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
139 Object o = arr.deleteNode(i);
140 return o == NULL ? null : o;
143 public final int size() { return arr.treeSize(); }
144 public String typeName() { return "array"; }
146 private Object join(String sep) {
148 if(length == 0) return "";
149 StringBuffer sb = new StringBuffer(64);
152 Object o = elementAt(i);
153 if(o != null) sb.append(JS.toString(o));
154 if(++i == length) break;
157 return sb.toString();
160 // FEATURE: Implement this more efficiently
161 private Object reverse() {
163 if(size < 2) return this;
166 for(int i=size-1,j=0;i>=0;i--,j++) insertElementAt(vec.elementAt(i),j);
170 private Object slice(int start, int end) {
171 int length = length();
172 if(start < 0) start = length+start;
173 if(end < 0) end = length+end;
174 if(start < 0) start = 0;
176 if(start > length) start = length;
177 if(end > length) end = length;
178 JSArray a = new JSArray(end-start);
179 for(int i=0;i<end-start;i++)
180 a.setElementAt(elementAt(start+i),i);
184 private static final Vec.CompareFunc defaultSort = new Vec.CompareFunc() {
185 public int compare(Object a, Object b) {
186 return JS.toString(a).compareTo(JS.toString(b));
189 private Object sort(Object tmp) throws JSExn {
191 if(tmp instanceof JS) {
192 final JSArray funcArgs = new JSArray(2);
193 final JS jsFunc = (JS) tmp;
194 vec.sort(new Vec.CompareFunc() {
195 public int compare(Object a, Object b) {
197 funcArgs.setElementAt(a,0);
198 funcArgs.setElementAt(b,1);
199 return JS.toInt(jsFunc.call(a, b, null, null, 2));
200 } catch (Exception e) {
202 throw new JSRuntimeExn(e.toString());
207 vec.sort(defaultSort);
213 private Object splice(JSArray args) {
214 int oldLength = length();
215 int start = JS.toInt(args.length() < 1 ? null : args.elementAt(0));
216 int deleteCount = JS.toInt(args.length() < 2 ? null : args.elementAt(1));
217 int newCount = args.length() - 2;
218 if(newCount < 0) newCount = 0;
219 if(start < 0) start = oldLength+start;
220 if(start < 0) start = 0;
221 if(start > oldLength) start = oldLength;
222 if(deleteCount < 0) deleteCount = 0;
223 if(deleteCount > oldLength-start) deleteCount = oldLength-start;
224 int newLength = oldLength - deleteCount + newCount;
225 int lengthChange = newLength - oldLength;
226 JSArray ret = new JSArray(deleteCount);
227 for(int i=0;i<deleteCount;i++)
228 ret.setElementAt(elementAt(start+i),i);
229 if(lengthChange > 0) {
231 for(int i=newLength-1;i>=start+newCount;i--)
232 setElementAt(elementAt(i-lengthChange),i);
233 } else if(lengthChange < 0) {
234 for(int i=start+newCount;i<newLength;i++)
235 setElementAt(elementAt(i-lengthChange),i);
238 for(int i=0;i<newCount;i++)
239 setElementAt(args.elementAt(i+2),start+i);
243 protected Vec toVec() {
247 for(int i=0;i<count;i++) {
248 Object o = arr.getNode(i);
249 vec.setElementAt(o == NULL ? null : o,i);
254 protected void setFromVec(Vec vec) {
255 int count = vec.size();
257 for(int i=0;i<count;i++) {
258 Object o = vec.elementAt(i);
259 arr.insertNode(i,o==null ? NULL : o);
263 public String toString() { return JS.toString(join(",")); }