+++ /dev/null
-// Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
-package org.ibex.js;
-
-import org.ibex.util.*;
-import java.util.*;
-
-/** A JavaScript JSArray */
-public class JSArray extends JS.O {
- private static final Object NULL = new Object();
- private final BalancedTree bt = new BalancedTree();
-
- 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 JS callMethod(JS method, JS a0, JS a1, JS a2, JS[] rest, int nargs) throws JSExn {
- //#jswitch(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 JS get(JS key) throws JSExn {
- if (isInt(key)) {
- int i = toInt(key);
- if (i < 0 || i >= size()) return null;
- return elementAt(i);
- }
- //#jswitch(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(JS key, JS val) throws JSExn {
- if (isInt(key)) {
- int i = toInt(key);
- int oldSize = size();
- if(i < oldSize) {
- setElementAt(val,i);
- } else {
- if(i > oldSize) setSize(i);
- insertElementAt(val,i);
- }
- return;
- }
- if(isString(key)) {
- if (JS.toString(key).equals("length")) {
- setSize(JS.toInt(val));
- return;
- }
- }
- super.put(key,val);
- }
-
- public Enumeration keys() throws JSExn {
- return new Enumeration(super.keys()) {
- private int n = 0;
- public boolean _hasMoreElements() { return n < size(); }
- public JS _nextElement() {
- return n >= size() ? null : JS.N(n++);
- }
- };
- }
-
- 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 JS elementAt(int i) {
- if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
- Object o = bt.getNode(i);
- return o == NULL ? (JS)null : (JS)o;
- }
- public final void addElement(JS o) {
- bt.insertNode(size(),o==null ? NULL : o);
- }
- public final void setElementAt(JS o, int i) {
- if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
- bt.replaceNode(i,o==null ? NULL : o);
- }
- public final void insertElementAt(JS o, int i) {
- if(i < 0 || i > size()) throw new ArrayIndexOutOfBoundsException(i);
- bt.insertNode(i,o==null ? NULL : o);
- }
- public final JS removeElementAt(int i) {
- if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
- Object o = bt.deleteNode(i);
- return o == NULL ? (JS)null : (JS)o;
- }
-
- public final int size() { return bt.treeSize(); }
-
- private JS join(String sep) throws JSExn {
- int length = size();
- if(length == 0) return JS.S("");
- StringBuffer sb = new StringBuffer(64);
- int i=0;
- while(true) {
- JS o = elementAt(i);
- if(o != null) sb.append(JS.toString(o));
- if(++i == length) break;
- sb.append(sep);
- }
- return JS.S(sb.toString());
- }
-
- // FEATURE: Implement this more efficiently
- private JS reverse() {
- int size = size();
- if(size < 2) return this;
- Vec vec = toVec();
- bt.clear();
- for(int i=size-1,j=0;i>=0;i--,j++) insertElementAt((JS)vec.elementAt(i),j);
- return this;
- }
-
- private JS 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) {
- try {
- return JS.toString((JS)a).compareTo(JS.toString((JS)b));
- } catch(JSExn e) { throw new JSExn.Wrapper(e); }
- }
- };
- private JS sort(JS tmp) throws JSExn {
- Vec vec = toVec();
- try {
- if(tmp instanceof JS) {
- final JS jsFunc = (JS) tmp;
- vec.sort(new Vec.CompareFunc() {
- public int compare(Object a, Object b) {
- try {
- return JS.toInt(jsFunc.call((JS)a, (JS)b, null, null, 2));
- } catch(JSExn e) { throw new JSExn.Wrapper(e); }
- }
- });
- } else {
- vec.sort(defaultSort);
- }
- } catch(JSExn.Wrapper e) {
- throw e.refill();
- }
- setFromVec(vec);
- return this;
- }
-
- private JS splice(JSArray args) throws JSExn {
- 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 = bt.getNode(i);
- vec.setElementAt(o == NULL ? null : o,i);
- }
- return vec;
- }
-
- protected void setFromVec(Vec vec) {
- int count = vec.size();
- bt.clear();
- for(int i=0;i<count;i++) {
- Object o = vec.elementAt(i);
- bt.insertNode(i,o==null ? NULL : o);
- }
- }
-
- String coerceToString() throws JSExn { return JS.toString(join(",")); }
-}