1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
7 import java.io.InputStream;
8 import org.ibex.util.*;
10 /** A JavaScript JSArray */
11 public class JSArray extends Basket.Array implements JS, Basket.CompareFunc {
12 private static final JS.Method METHOD = new JS.Method();
13 private static final String[] empty = new String[0];
16 public JSArray(int size) { super(size); }
17 public JSArray(JS[] args) { super(args.length); addAll(args); }
18 public JSArray(JS arg) { super(1); add(arg); }
20 public JS unclone() { return this; }
21 public JS.Enumeration keys() throws JSExn {
22 return new Enumeration(null) {
24 public boolean _hasNext() { return n < size(); }
25 public JS _next() { return JSU.N(n++); }
28 public JS get(JS key) throws JSExn {
29 if (key == null || !(key instanceof JSNumber.I)) {
30 //#switch(JSU.str(key))
31 case "pop": return METHOD;
32 case "reverse": return METHOD;
33 case "toString": return METHOD;
34 case "shift": return METHOD;
35 case "join": return METHOD;
36 case "sort": return METHOD;
37 case "slice": return METHOD;
38 case "push": return METHOD;
39 case "unshift": return METHOD;
40 case "splice": return METHOD;
41 case "length": return JSU.N(size());
43 throw new JSExn("arrays only support positive integer keys, can not use: "+JSU.str(key));
45 return (JS)get(((JSNumber.I)key).toInt());
47 public void put(JS key, JS val) throws JSExn {
48 if (JSU.str(key).equals("length")) { setSize(JSU.toInt(val)); }
50 if (key == null || !(key instanceof JSNumber.I)) throw new JSExn(
51 "arrays only support positive integer keys, can not use: "+JSU.str(key));
52 int i = ((JSNumber.I)key).toInt();
53 if (i < 0) throw new JSExn("arrays can not use negative integer keys "+i);
54 if (size() < i+1) size(i + 1);
55 //while (size() < i) add(null);
59 public String[] getFormalArgs() { return empty; }
60 public String coerceToString() throws JSExn { throw new JSExn("cannot coerce a "+getClass().getName()+" to a string"); }
62 public JS call(JS method, JS[] args) throws JSExn {
63 //#switch(JSU.str(method))
64 case "pop": return size() == 0 ? null : (JS)remove(size() - 1);
65 case "push": addAll(args); return JSU.N(size());
66 case "reverse": reverse(); return this;
67 case "toString": return join(",");
68 case "shift": return size() == 0 ? null : (JS)remove(0);
69 case "join": return join(args.length == 0 ? "," : JSU.str(args[0]));
70 case "sort": return sort(args.length == 0 ? null : args[0]);
72 int start = JSU.toInt(args.length < 1 ? null : args[0]);
73 int end = args.length < 2 ? size() : JSU.toInt(args[1]);
74 return slice(start, end);
76 for (int i=0; i < args.length; i++) add(i, args[i]);
78 case "splice": return splice(args);
80 throw new JSExn("arrays have no function: "+JSU.str(method));
83 public JS putAndTriggerTraps(JS key, JS val) throws JSExn { put(key, val); return val; }
84 public JS getAndTriggerTraps(JS key) throws JSExn { return get(key); }
85 public JS justTriggerTraps(JS key, JS val) throws JSExn { return val; }
87 public void addTrap(JS k, JS f) throws JSExn { throw new JSExn("arrays do not support traps"); }
88 public void delTrap(JS k, JS f) throws JSExn { throw new JSExn("arrays do not support traps"); }
89 public JS.Trap getTrap(JS k) throws JSExn { return null; }
91 /** FEATURE: move to specialised ArrayStore superclass. */
92 public void addAll(JS[] entries) { for (int i=0; i < entries.length; i++) add(entries[i]); }
94 public void setSize(int newSize) {
96 for (int i=size(); i < newSize; i++) add(null);
97 for (int i=size() - 1; i >= newSize; i--) remove(i);
101 // ECMA Implementation ////////////////////////////////////////////////////
103 private JS join(String sep) throws JSExn {
105 if(length == 0) return JSU.S("");
106 StringBuffer sb = new StringBuffer(64);
110 if(o != null) sb.append(JSU.toString(o));
111 if(++i == length) break;
114 return JSU.S(sb.toString());
117 private JS slice(int start, int end) {
119 if(start < 0) start = length+start;
120 if(end < 0) end = length+end;
121 if(start < 0) start = 0;
123 if(start > length) start = length;
124 if(end > length) end = length;
125 JSArray a = new JSArray(end-start);
126 for(int i=0;i<end-start;i++) // FEATURE: with ArrayStore do System.arraycopy()
127 a.set(i, get(start+i));
131 private JS splice(JS[] args) throws JSExn {
132 int oldLength = size();
133 int start = JSU.toInt(args.length < 1 ? null : args[0]);
134 int deleteCount = JSU.toInt(args.length < 2 ? null : args[1]);
135 int newCount = args.length - 2;
136 if(newCount < 0) newCount = 0;
137 if(start < 0) start = oldLength+start;
138 if(start < 0) start = 0;
139 if(start > oldLength) start = oldLength;
140 if(deleteCount < 0) deleteCount = 0;
141 if(deleteCount > oldLength-start) deleteCount = oldLength-start;
142 int newLength = oldLength - deleteCount + newCount;
143 int lengthChange = newLength - oldLength;
144 JSArray ret = new JSArray(deleteCount);
145 for(int i=0;i<deleteCount;i++) // FEATURE: ArrayStore System.arraycopy()
146 ret.set(i, get(start+i));
147 if(lengthChange > 0) {
149 for(int i=newLength-1;i>=start+newCount;i--)
150 set(i, get(i-lengthChange));
151 } else if(lengthChange < 0) {
152 for(int i=start+newCount;i<newLength;i++)
153 set(i, get(i-lengthChange));
156 for(int i=0;i<newCount;i++)
157 set(start+i, args[i+2]);
161 private static final Basket.CompareFunc defaultSort = new Basket.CompareFunc() {
162 public int compare(Object a, Object b) {
163 try { return JSU.toString((JS)a).compareTo(JSU.toString((JS)b)); }
164 catch (JSExn e) { throw new JSExn.Wrapper(e); }
167 private JS sort(JS comparator) throws JSExn {
169 if (comparator == null) sort(defaultSort);
170 else { sort = comparator; sort((CompareFunc)this); }
172 } catch (JSExn.Wrapper w) { throw w.unwrap();
173 } finally { sort = null; }
176 private JS sort = null;
177 private final JS[] sortargs = new JS[2];
178 public int compare(Object a, Object b) throws JSExn.Wrapper {
180 sortargs[0] = (JS)a; sortargs[1] = (JS)b;
181 return JSU.toInt(sort.call(null, sortargs));
182 } catch (JSExn e) { throw new JSExn.Wrapper(e);
183 } finally { sortargs[0] = null; sortargs[1] = null; }