2f5f04d8e7b3aeb3aa774e599e21814f6d9b9aa8
[org.ibex.core.git] / src / org / xwt / js / JSArray.java
1 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] 
2 package org.xwt.js; 
3
4 import org.xwt.util.*; 
5 import java.io.*;
6 import java.util.*;
7
8 /** A JavaScript JSArray */
9 public class JSArray extends JS {
10     private Vec vec = new Vec();
11     public JSArray() { }
12     public JSArray(int size) { vec.setSize(size); }
13     private static int intVal(Object o) {
14         if (o instanceof Number) {
15             int intVal = ((Number)o).intValue();
16             if (intVal == ((Number)o).doubleValue()) return intVal;
17             return Integer.MIN_VALUE;
18         }
19         if (!(o instanceof String)) return Integer.MIN_VALUE;
20         String s = (String)o;
21         for(int i=0; i<s.length(); i++) if (s.charAt(i) < '0' || s.charAt(i) > '9') return Integer.MIN_VALUE;
22         return Integer.parseInt(s);
23     }
24     
25     public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
26         //#switch(method)
27         case "pop": return vec.pop();
28         case "reverse": return reverse();
29         case "toString": return join(",");
30         case "shift":
31             if(length() == 0) return null;
32             Object o = vec.elementAt(0);
33             vec.removeElementAt(0);
34             return o;
35         case "join":
36             return join(nargs == 0 ? "," : JS.toString(a0));
37         case "sort":
38             return sort(nargs < 1 ? null : a0);
39         case "slice":
40             int start = toInt(nargs < 1 ? null : a0);
41             int end = nargs < 2 ? length() : toInt(a1);
42             return slice(start, end);
43         case "push":
44             for(int i=0; i<nargs; i++) vec.push(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
45             return N(vec.size());
46         case "unshift":
47             for(int i=0; i<nargs; i++) vec.insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3], i);
48             return N(vec.size());
49         case "splice":
50             JSArray array = new JSArray();
51             for(int i=0; i<nargs; i++) array.addElement(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
52             return splice(array);
53         //#end
54         return super.callMethod(method, a0, a1, a2, rest, nargs);
55     }
56         
57     public Object get(Object key) throws JSExn {
58         if (key instanceof Number) {
59             int i = intVal(key);
60             if (i == Integer.MIN_VALUE) return super.get(key);
61             try {
62                 return vec.elementAt(i);
63             } catch (ArrayIndexOutOfBoundsException e) {
64                 return null;
65             }
66         }
67         //#switch(key)
68         case "pop": return METHOD;
69         case "reverse": return METHOD;
70         case "toString": return METHOD;
71         case "shift": return METHOD;
72         case "join": return METHOD;
73         case "sort": return METHOD;
74         case "slice": return METHOD;
75         case "push": return METHOD;
76         case "unshift": return METHOD;
77         case "splice": return METHOD;
78         case "length": return N(vec.size());
79         //#end
80         return super.get(key);
81     }
82
83     public void put(Object key, Object val) throws JSExn {
84         if (key.equals("length")) vec.setSize(toNumber(val).intValue());
85         int i = intVal(key);
86         if (i == Integer.MIN_VALUE) super.put(key, val);
87         else {
88             if (i >= vec.size()) vec.setSize(i+1);
89             vec.setElementAt(val, i);
90         }
91     }
92
93     public Enumeration keys() {
94         return new Enumeration() {
95                 int cur = 0;
96                 public boolean hasMoreElements() { return cur >= vec.size(); }
97                 public Object nextElement() {
98                     if (cur >= vec.size()) throw new NoSuchElementException();
99                     return new Integer(cur++);
100                 }
101             };
102     }
103
104     public void setSize(int i) { vec.setSize(i); }
105     public int length() { return vec.size(); }
106     public Object elementAt(int i) { return vec.elementAt(i); }
107     public void addElement(Object o) { vec.addElement(o); }
108     public void setElementAt(Object o, int i) { vec.setElementAt(o, i); }
109     public int size() { return vec.size(); }
110     public String typeName() { return "array"; }
111         
112     private Object join(String sep) {
113         int length = vec.size();
114         if(length == 0) return "";
115         StringBuffer sb = new StringBuffer(64);
116         int i=0;
117         while(true) {
118             Object o = elementAt(i);
119             if(o != null) sb.append(JS.toString(o));
120             if(++i == length) break;
121             sb.append(sep);
122         }
123         return sb.toString();
124     }
125     
126     private Object reverse() {
127         Vec oldVec = vec;
128         int size = oldVec.size();
129         if(size < 2) return this;
130         vec = new Vec(size);
131         for(int i=size-1;i>=0;i--) vec.addElement(oldVec.elementAt(i));
132         return this;
133     }
134     
135     private Object slice(int start, int end) {
136         int length = length();
137         if(start < 0) start = length+start;
138         if(end < 0) end = length+end;
139         if(start < 0) start = 0;
140         if(end < 0) end = 0;
141         if(start > length) start = length;
142         if(end > length) end = length;
143         JSArray a = new JSArray(end-start);
144         for(int i=0;i<end-start;i++)
145             a.setElementAt(elementAt(start+i),i);
146         return a;
147     }
148     
149     private static final Vec.CompareFunc defaultSort = new Vec.CompareFunc() {
150         public int compare(Object a, Object b) {
151             return JS.toString(a).compareTo(JS.toString(b));
152         }
153     };
154     private Object sort(Object tmp) throws JSExn {
155         if(tmp instanceof JS) {
156             final JSArray funcArgs = new JSArray(2);
157             final JS jsFunc = (JS) tmp;
158             vec.sort(new Vec.CompareFunc() {
159                 public int compare(Object a, Object b) {
160                     try {
161                         funcArgs.setElementAt(a,0);
162                         funcArgs.setElementAt(b,1);
163                         return JS.toInt(jsFunc.call(a, b, null, null, 2));
164                     } catch (Exception e) {
165                         // FIXME
166                         throw new JSRuntimeExn(e.toString());
167                     }
168                 }
169             });
170         } else {
171             vec.sort(defaultSort);
172         }
173         return this;
174     }
175     
176     private Object splice(JSArray args) {
177         int oldLength = length();
178         int start = JS.toInt(args.length() < 1 ? null : args.elementAt(0));
179         int deleteCount = JS.toInt(args.length() < 2 ? null : args.elementAt(1));
180         int newCount = args.length() - 2;
181         if(newCount < 0) newCount = 0;
182         if(start < 0) start = oldLength+start;
183         if(start < 0) start = 0;
184         if(start > oldLength) start = oldLength;
185         if(deleteCount < 0) deleteCount = 0;
186         if(deleteCount > oldLength-start) deleteCount = oldLength-start;
187         int newLength = oldLength - deleteCount + newCount;
188         int lengthChange = newLength - oldLength;
189         JSArray ret = new JSArray(deleteCount);
190         for(int i=0;i<deleteCount;i++)
191             ret.setElementAt(elementAt(start+i),i);
192         if(lengthChange > 0) {
193             setSize(newLength);
194             for(int i=newLength-1;i>=start+newCount;i--)
195                 setElementAt(elementAt(i-lengthChange),i);
196         } else if(lengthChange < 0) {
197             for(int i=start+newCount;i<newLength;i++)
198                 setElementAt(elementAt(i-lengthChange),i);
199             setSize(newLength);
200         }
201         for(int i=0;i<newCount;i++)
202             setElementAt(args.elementAt(i+2),start+i);
203         return ret;
204     }
205     
206      public String coerceToString() { return JS.toString(join(",")); }
207 }