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.BT {
9 private static final Object NULL = new Object();
12 public JSArray(int size) { setSize(size); }
14 /*private static int intVal(Object o) {
15 if (o instanceof Number) {
16 int intVal = ((Number)o).intValue();
17 if (intVal == ((Number)o).doubleValue()) return intVal;
18 return Integer.MIN_VALUE;
20 if (!(o instanceof String)) return Integer.MIN_VALUE;
22 for(int i=0; i<s.length(); i++) if (s.charAt(i) < '0' || s.charAt(i) > '9') return Integer.MIN_VALUE;
23 return Integer.parseInt(s);
26 public JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
27 if(isString(method)) {
28 //#switch(JS.toString(method))
31 if(oldSize == 0) return null;
32 return removeElementAt(oldSize-1);
34 case "reverse": return reverse();
35 case "toString": return join(",");
37 if(length() == 0) return null;
38 return removeElementAt(0);
40 return join(nargs == 0 ? "," : JS.toString(a0));
42 return sort(nargs < 1 ? null : a0);
44 int start = toInt(nargs < 1 ? null : a0);
45 int end = nargs < 2 ? length() : toInt(a1);
46 return slice(start, end);
49 for(int i=0; i<nargs; i++) insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3],oldSize+i);
50 return N(oldSize + nargs);
53 for(int i=0; i<nargs; i++) insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3],i);
56 JSArray array = new JSArray();
57 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 JS get(JS key) throws JSExn {
67 if (i < 0 || i >= size()) return null;
71 //#switch(JS.toString(key))
72 case "pop": return METHOD;
73 case "reverse": return METHOD;
74 case "toString": return METHOD;
75 case "shift": return METHOD;
76 case "join": return METHOD;
77 case "sort": return METHOD;
78 case "slice": return METHOD;
79 case "push": return METHOD;
80 case "unshift": return METHOD;
81 case "splice": return METHOD;
82 case "length": return N(size());
85 return super.get(key);
88 public void put(JS key, JS val) throws JSExn {
95 if(i > oldSize) setSize(i);
96 insertElementAt(val,i);
100 if (JS.toString(key).equals("length")) {
101 setSize(JS.toInt(val));
108 // FIXME: Needs to include super's keys
109 public Enumeration keys() {
110 return new Enumeration() {
111 private int n = size();
112 public boolean hasMoreElements() { return n > 0; }
113 public Object nextElement() {
114 if(n == 0) throw new NoSuchElementException();
115 return new Integer(--n);
120 public final void setSize(int newSize) {
121 // FEATURE: This could be done a lot more efficiently in BalancedTree
122 int oldSize = size();
123 for(int i=oldSize;i<newSize;i++) insertElementAt(null,i);
124 for(int i=oldSize-1;i>=newSize;i--) removeElementAt(i);
127 public final int length() { return size(); }
128 public final JS elementAt(int i) {
129 if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
130 Object o = getNode(i);
131 return o == NULL ? (JS)null : (JS)o;
133 public final void addElement(JS o) {
134 insertNode(size(),o==null ? NULL : o);
136 public final void setElementAt(JS o, int i) {
137 if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
138 replaceNode(i,o==null ? NULL : o);
140 public final void insertElementAt(JS o, int i) {
141 if(i < 0 || i > size()) throw new ArrayIndexOutOfBoundsException(i);
142 insertNode(i,o==null ? NULL : o);
144 public final JS removeElementAt(int i) {
145 if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
146 Object o = deleteNode(i);
147 return o == NULL ? (JS)null : (JS)o;
150 public final int size() { return treeSize(); }
152 private JS join(String sep) throws JSExn {
154 if(length == 0) return JS.S("");
155 StringBuffer sb = new StringBuffer(64);
159 if(o != null) sb.append(JS.toString(o));
160 if(++i == length) break;
163 return JS.S(sb.toString());
166 // FEATURE: Implement this more efficiently
167 private JS reverse() {
169 if(size < 2) return this;
172 for(int i=size-1,j=0;i>=0;i--,j++) insertElementAt((JS)vec.elementAt(i),j);
176 private JS slice(int start, int end) {
177 int length = length();
178 if(start < 0) start = length+start;
179 if(end < 0) end = length+end;
180 if(start < 0) start = 0;
182 if(start > length) start = length;
183 if(end > length) end = length;
184 JSArray a = new JSArray(end-start);
185 for(int i=0;i<end-start;i++)
186 a.setElementAt(elementAt(start+i),i);
190 private static final Vec.CompareFunc defaultSort = new Vec.CompareFunc() {
191 public int compare(Object a, Object b) {
193 return JS.toString((JS)a).compareTo(JS.toString((JS)b));
195 // FIXME: See emca about this
196 throw new RuntimeException(e.toString());
200 private JS sort(JS tmp) throws JSExn {
202 if(tmp instanceof JS) {
203 final JS jsFunc = (JS) tmp;
204 vec.sort(new Vec.CompareFunc() {
205 public int compare(Object a, Object b) {
207 return JS.toInt(jsFunc.call((JS)a, (JS)b, null, null, 2));
209 // FIXME: Check ecma to see what we should do here
210 throw new RuntimeException(e.toString());
215 vec.sort(defaultSort);
221 private JS splice(JSArray args) throws JSExn {
222 int oldLength = length();
223 int start = JS.toInt(args.length() < 1 ? null : args.elementAt(0));
224 int deleteCount = JS.toInt(args.length() < 2 ? null : args.elementAt(1));
225 int newCount = args.length() - 2;
226 if(newCount < 0) newCount = 0;
227 if(start < 0) start = oldLength+start;
228 if(start < 0) start = 0;
229 if(start > oldLength) start = oldLength;
230 if(deleteCount < 0) deleteCount = 0;
231 if(deleteCount > oldLength-start) deleteCount = oldLength-start;
232 int newLength = oldLength - deleteCount + newCount;
233 int lengthChange = newLength - oldLength;
234 JSArray ret = new JSArray(deleteCount);
235 for(int i=0;i<deleteCount;i++)
236 ret.setElementAt(elementAt(start+i),i);
237 if(lengthChange > 0) {
239 for(int i=newLength-1;i>=start+newCount;i--)
240 setElementAt(elementAt(i-lengthChange),i);
241 } else if(lengthChange < 0) {
242 for(int i=start+newCount;i<newLength;i++)
243 setElementAt(elementAt(i-lengthChange),i);
246 for(int i=0;i<newCount;i++)
247 setElementAt(args.elementAt(i+2),start+i);
251 protected Vec toVec() {
255 for(int i=0;i<count;i++) {
256 Object o = getNode(i);
257 vec.setElementAt(o == NULL ? null : o,i);
262 protected void setFromVec(Vec vec) {
263 int count = vec.size();
265 for(int i=0;i<count;i++) {
266 Object o = vec.elementAt(i);
267 insertNode(i,o==null ? NULL : o);
271 String coerceToString() throws JSExn { return JS.toString(join(",")); }