1 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
8 /** A JavaScript JSArray */
9 public class JSArray extends JSCallable {
10 private Vec vec = new Vec();
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;
19 if (!(o instanceof String)) return Integer.MIN_VALUE;
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);
25 public Object call(Object method, JSArray args) {
26 if(method.equals("push")) {
27 for(int i=0;i<args.length();i++)
28 vec.push(args.elementAt(i));
29 return new Integer(vec.size());
31 if(method.equals("pop")) {
32 return vec.pop(); // this'll return null on size()==0
34 if(method.equals("shift")) {
36 Object o = vec.elementAt(0);
37 vec.removeElementAt(0);
43 if(method.equals("unshift")) {
44 // FEATURE: could be optimized a bit with some help from Vec
45 for(int i=0;i<args.length();i++)
46 vec.insertElementAt(args.elementAt(i),i);
47 return new Integer(vec.size());
49 if(method.equals("slice")) return slice(args);
50 if(method.equals("join")) return join(args);
51 if(method.equals("reverse")) return reverse(args);
52 if(method.equals("toString")) return join(",");
53 if(method.equals("sort")) return sort(args);
54 if(method.equals("splice")) return splice(args);
55 throw new JS.Exn("unknown method " + method);
58 public Object get(Object key) throws JS.Exn {
59 if (key.equals("length")) return new Long(vec.size());
62 if (i == Integer.MIN_VALUE) return super.get(key);
64 return vec.elementAt(i);
65 } catch (ArrayIndexOutOfBoundsException e) {
70 public void put(Object key, Object val) {
71 if (key.equals("length")) vec.setSize(toNumber(val).intValue());
73 if (i == Integer.MIN_VALUE) super.put(key, val);
75 if (i >= vec.size()) vec.setSize(i+1);
76 vec.setElementAt(val, i);
80 public Enumeration keys() {
81 return new Enumeration() {
83 public boolean hasMoreElements() { return cur >= vec.size(); }
84 public Object nextElement() {
85 if (cur >= vec.size()) throw new NoSuchElementException();
86 return new Integer(cur++);
91 public void setSize(int i) { vec.setSize(i); }
92 public int length() { return vec.size(); }
93 public Object elementAt(int i) { return vec.elementAt(i); }
94 public void addElement(Object o) { vec.addElement(o); }
95 public void setElementAt(Object o, int i) { vec.setElementAt(o, i); }
96 public int size() { return vec.size(); }
97 public String typeName() { return "array"; }
99 private Object join(JSArray args) {
100 return join(args.length() == 0 ? "," : JS.toString(args.elementAt(0)));
103 private Object join(String sep) {
104 int length = vec.size();
105 if(length == 0) return "";
106 StringBuffer sb = new StringBuffer(64);
109 Object o = elementAt(i);
110 if(o != null) sb.append(JS.toString(o));
111 if(++i == length) break;
114 return sb.toString();
117 private Object reverse(JSArray args) {
119 int size = oldVec.size();
120 if(size < 2) return this;
122 for(int i=size-1;i>=0;i--)
123 vec.addElement(oldVec.elementAt(i));
127 private Object slice(JSArray args) {
128 int length = length();
129 int start = JS.toInt(args.length() < 1 ? null : args.elementAt(0));
130 int end = args.length() < 2 ? length : JS.toInt(args.elementAt(1));
131 if(start < 0) start = length+start;
132 if(end < 0) end = length+end;
133 if(start < 0) start = 0;
135 if(start > length) start = length;
136 if(end > length) end = length;
137 JSArray a = new JSArray(end-start);
138 for(int i=0;i<end-start;i++)
139 a.setElementAt(elementAt(start+i),i);
143 private static final Vec.CompareFunc defaultSort = new Vec.CompareFunc() {
144 public int compare(Object a, Object b) {
145 return JS.toString(a).compareTo(JS.toString(b));
148 private Object sort(JSArray args) {
149 Object tmp = args.length() < 1 ? null : args.elementAt(0);
150 if(tmp instanceof JSCallable) {
151 final JSArray funcArgs = new JSArray(2);
152 final JSCallable jsFunc = (JSCallable) tmp;
153 vec.sort(new Vec.CompareFunc() {
154 public int compare(Object a, Object b) {
155 funcArgs.setElementAt(a,0);
156 funcArgs.setElementAt(b,1);
157 return JS.toInt(jsFunc.call(null, funcArgs));
161 vec.sort(defaultSort);
166 private Object splice(JSArray args) {
167 int oldLength = length();
168 int start = JS.toInt(args.length() < 1 ? null : args.elementAt(0));
169 int deleteCount = JS.toInt(args.length() < 2 ? null : args.elementAt(1));
170 int newCount = args.length() - 2;
171 if(newCount < 0) newCount = 0;
172 if(start < 0) start = oldLength+start;
173 if(start < 0) start = 0;
174 if(start > oldLength) start = oldLength;
175 if(deleteCount < 0) deleteCount = 0;
176 if(deleteCount > oldLength-start) deleteCount = oldLength-start;
177 int newLength = oldLength - deleteCount + newCount;
178 int lengthChange = newLength - oldLength;
179 JSArray ret = new JSArray(deleteCount);
180 for(int i=0;i<deleteCount;i++)
181 ret.setElementAt(elementAt(start+i),i);
182 if(lengthChange > 0) {
184 for(int i=newLength-1;i>=start+newCount;i--)
185 setElementAt(elementAt(i-lengthChange),i);
186 } else if(lengthChange < 0) {
187 for(int i=start+newCount;i<newLength;i++)
188 setElementAt(elementAt(i-lengthChange),i);
191 for(int i=0;i<newCount;i++)
192 setElementAt(args.elementAt(i+2),start+i);
196 public String coerceToString() { return JS.toString(join(",")); }