+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.xwt.js;
-
-import org.xwt.util.*;
-import java.util.*;
-
-/** A JavaScript JSArray */
-public class JSArray extends JS {
- private static final Object NULL = new Object();
-
- public JSArray() { }
- public JSArray(int size) { setSize(size); }
-
- private static int intVal(Object o) {
- if (o instanceof Number) {
- int intVal = ((Number)o).intValue();
- if (intVal == ((Number)o).doubleValue()) return intVal;
- return Integer.MIN_VALUE;
- }
- if (!(o instanceof String)) return Integer.MIN_VALUE;
- String s = (String)o;
- for(int i=0; i<s.length(); i++) if (s.charAt(i) < '0' || s.charAt(i) > '9') return Integer.MIN_VALUE;
- return Integer.parseInt(s);
- }
-
- public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
- //#switch(method)
- case "pop": {
- int oldSize = size();
- if(oldSize == 0) return null;
- return removeElementAt(oldSize-1);
- }
- case "reverse": return reverse();
- case "toString": return join(",");
- case "shift":
- if(length() == 0) return null;
- return removeElementAt(0);
- case "join":
- return join(nargs == 0 ? "," : JS.toString(a0));
- case "sort":
- return sort(nargs < 1 ? null : a0);
- case "slice":
- int start = toInt(nargs < 1 ? null : a0);
- int end = nargs < 2 ? length() : toInt(a1);
- return slice(start, end);
- case "push": {
- int oldSize = size();
- for(int i=0; i<nargs; i++) insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3],oldSize+i);
- return N(oldSize + nargs);
- }
- case "unshift":
- for(int i=0; i<nargs; i++) insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3],i);
- return N(size());
- case "splice":
- JSArray array = new JSArray();
- for(int i=0; i<nargs; i++) array.addElement(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
- return splice(array);
- //#end
- return super.callMethod(method, a0, a1, a2, rest, nargs);
- }
-
- public Object get(Object key) throws JSExn {
- int i = intVal(key);
- if (i != Integer.MIN_VALUE) {
- if (i < 0 || i >= size()) return null;
- return elementAt(i);
- }
- //#switch(key)
- case "pop": return METHOD;
- case "reverse": return METHOD;
- case "toString": return METHOD;
- case "shift": return METHOD;
- case "join": return METHOD;
- case "sort": return METHOD;
- case "slice": return METHOD;
- case "push": return METHOD;
- case "unshift": return METHOD;
- case "splice": return METHOD;
- case "length": return N(size());
- //#end
- return super.get(key);
- }
-
- public void put(Object key, Object val) throws JSExn {
- if (key.equals("length")) setSize(toInt(val));
- int i = intVal(key);
- if (i == Integer.MIN_VALUE)
- super.put(key, val);
- else {
- int oldSize = size();
- if(i < oldSize) {
- setElementAt(val,i);
- } else {
- if(i > oldSize) setSize(i);
- insertElementAt(val,i);
- }
- }
- }
-
- public Enumeration keys() {
- return new Enumeration() {
- int cur = 0;
- public boolean hasMoreElements() { return cur >= size(); }
- public Object nextElement() {
- if (cur >= size()) throw new NoSuchElementException();
- return new Integer(cur++);
- }
- };
- }
-
- public final void setSize(int newSize) {
- // FEATURE: This could be done a lot more efficiently in BalancedTree
- int oldSize = size();
- for(int i=oldSize;i<newSize;i++) insertElementAt(null,i);
- for(int i=oldSize-1;i>=newSize;i--) removeElementAt(i);
- }
-
- public final int length() { return size(); }
- public final Object elementAt(int i) {
- if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
- Object o = getNode(i);
- return o == NULL ? null : o;
- }
- public final void addElement(Object o) {
- insertNode(size(),o==null ? NULL : o);
- }
- public final void setElementAt(Object o, int i) {
- if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
- replaceNode(i,o==null ? NULL : o);
- }
- public final void insertElementAt(Object o, int i) {
- if(i < 0 || i > size()) throw new ArrayIndexOutOfBoundsException(i);
- insertNode(i,o==null ? NULL : o);
- }
- public final Object removeElementAt(int i) {
- if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
- Object o = deleteNode(i);
- return o == NULL ? null : o;
- }
-
- public final int size() { return treeSize(); }
- public String typeName() { return "array"; }
-
- private Object join(String sep) {
- int length = size();
- if(length == 0) return "";
- StringBuffer sb = new StringBuffer(64);
- int i=0;
- while(true) {
- Object o = elementAt(i);
- if(o != null) sb.append(JS.toString(o));
- if(++i == length) break;
- sb.append(sep);
- }
- return sb.toString();
- }
-
- // FEATURE: Implement this more efficiently
- private Object reverse() {
- int size = size();
- if(size < 2) return this;
- Vec vec = toVec();
- clear();
- for(int i=size-1,j=0;i>=0;i--,j++) insertElementAt(vec.elementAt(i),j);
- return this;
- }
-
- private Object slice(int start, int end) {
- int length = length();
- if(start < 0) start = length+start;
- if(end < 0) end = length+end;
- if(start < 0) start = 0;
- if(end < 0) end = 0;
- if(start > length) start = length;
- if(end > length) end = length;
- JSArray a = new JSArray(end-start);
- for(int i=0;i<end-start;i++)
- a.setElementAt(elementAt(start+i),i);
- return a;
- }
-
- private static final Vec.CompareFunc defaultSort = new Vec.CompareFunc() {
- public int compare(Object a, Object b) {
- return JS.toString(a).compareTo(JS.toString(b));
- }
- };
- private Object sort(Object tmp) throws JSExn {
- Vec vec = toVec();
- if(tmp instanceof JS) {
- final JSArray funcArgs = new JSArray(2);
- final JS jsFunc = (JS) tmp;
- vec.sort(new Vec.CompareFunc() {
- public int compare(Object a, Object b) {
- try {
- funcArgs.setElementAt(a,0);
- funcArgs.setElementAt(b,1);
- return JS.toInt(jsFunc.call(a, b, null, null, 2));
- } catch (Exception e) {
- // FIXME
- throw new JSRuntimeExn(e.toString());
- }
- }
- });
- } else {
- vec.sort(defaultSort);
- }
- setFromVec(vec);
- return this;
- }
-
- private Object splice(JSArray args) {
- int oldLength = length();
- int start = JS.toInt(args.length() < 1 ? null : args.elementAt(0));
- int deleteCount = JS.toInt(args.length() < 2 ? null : args.elementAt(1));
- int newCount = args.length() - 2;
- if(newCount < 0) newCount = 0;
- if(start < 0) start = oldLength+start;
- if(start < 0) start = 0;
- if(start > oldLength) start = oldLength;
- if(deleteCount < 0) deleteCount = 0;
- if(deleteCount > oldLength-start) deleteCount = oldLength-start;
- int newLength = oldLength - deleteCount + newCount;
- int lengthChange = newLength - oldLength;
- JSArray ret = new JSArray(deleteCount);
- for(int i=0;i<deleteCount;i++)
- ret.setElementAt(elementAt(start+i),i);
- if(lengthChange > 0) {
- setSize(newLength);
- for(int i=newLength-1;i>=start+newCount;i--)
- setElementAt(elementAt(i-lengthChange),i);
- } else if(lengthChange < 0) {
- for(int i=start+newCount;i<newLength;i++)
- setElementAt(elementAt(i-lengthChange),i);
- setSize(newLength);
- }
- for(int i=0;i<newCount;i++)
- setElementAt(args.elementAt(i+2),start+i);
- return ret;
- }
-
- protected Vec toVec() {
- int count = size();
- Vec vec = new Vec();
- vec.setSize(count);
- for(int i=0;i<count;i++) {
- Object o = getNode(i);
- vec.setElementAt(o == NULL ? null : o,i);
- }
- return vec;
- }
-
- protected void setFromVec(Vec vec) {
- int count = vec.size();
- clear();
- for(int i=0;i<count;i++) {
- Object o = vec.elementAt(i);
- insertNode(i,o==null ? NULL : o);
- }
- }
-
- public String toString() { return JS.toString(join(",")); }
-}