// Copyright 2000-2005 the Contributors, as shown in the revision logs. // Licensed under the Apache Public Source License 2.0 ("the License"). // You may not use this file except in compliance with the License. package org.ibex.js; import java.io.InputStream; import org.ibex.util.*; /** A JavaScript JSArray */ public class JSArray extends Basket.Array implements JS, Basket.CompareFunc { private static final JS.Method METHOD = new JS.Method(); private static final String[] empty = new String[0]; public JSArray() { } public JSArray(int size) { super(size); } public JSArray(JS[] args) { super(args.length); addAll(args); } public JSArray(JS arg) { super(1); add(arg); } public JS unclone() { return this; } public JS.Enumeration keys() throws JSExn { return new Enumeration(null) { private int n = 0; public boolean _hasNext() { return n < size(); } public JS _next() { return JSU.N(n++); } }; } public JS get(JS key) throws JSExn { if (key == null || !(key instanceof JSNumber.I)) { //#switch(JSU.str(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 JSU.N(size()); //#end throw new JSExn("arrays only support positive integer keys, can not use: "+JSU.str(key)); } return (JS)get(((JSNumber.I)key).toInt()); } public void put(JS key, JS val) throws JSExn { if (JSU.str(key).equals("length")) { setSize(JSU.toInt(val)); } if (key == null || !(key instanceof JSNumber.I)) throw new JSExn( "arrays only support positive integer keys, can not use: "+JSU.str(key)); int i = ((JSNumber.I)key).toInt(); if (i < 0) throw new JSExn("arrays can not use negative integer keys "+i); if (size() < i+1) size(i + 1); //while (size() < i) add(null); set(i, val); } public String[] getFormalArgs() { return empty; } public String coerceToString() throws JSExn { throw new JSExn("cannot coerce a "+getClass().getName()+" to a string"); } public JS call(JS method, JS[] args) throws JSExn { //#switch(JSU.str(method)) case "pop": return size() == 0 ? null : (JS)remove(size() - 1); case "push": addAll(args); return JSU.N(size()); case "reverse": reverse(); return this; case "toString": return join(","); case "shift": return size() == 0 ? null : (JS)remove(0); case "join": return join(args.length == 0 ? "," : JSU.str(args[0])); case "sort": return sort(args.length == 0 ? null : args[0]); case "slice": int start = JSU.toInt(args.length < 1 ? null : args[0]); int end = args.length < 2 ? size() : JSU.toInt(args[1]); return slice(start, end); case "unshift": for (int i=0; i < args.length; i++) add(i, args[i]); return JSU.N(size()); case "splice": return splice(args); //#end throw new JSExn("arrays have no function: "+JSU.str(method)); } public JS putAndTriggerTraps(JS key, JS val) throws JSExn { put(key, val); return val; } public JS getAndTriggerTraps(JS key) throws JSExn { return get(key); } public JS justTriggerTraps(JS key, JS val) throws JSExn { return val; } public void addTrap(JS k, JS f) throws JSExn { throw new JSExn("arrays do not support traps"); } public void delTrap(JS k, JS f) throws JSExn { throw new JSExn("arrays do not support traps"); } public JS.Trap getTrap(JS k) throws JSExn { return null; } /** FEATURE: move to specialised ArrayStore superclass. */ public void addAll(JS[] entries) { for (int i=0; i < entries.length; i++) add(entries[i]); } public void setSize(int newSize) { size(newSize); for (int i=size(); i < newSize; i++) add(null); for (int i=size() - 1; i >= newSize; i--) remove(i); } // ECMA Implementation //////////////////////////////////////////////////// private JS join(String sep) throws JSExn { int length = size(); if(length == 0) return JSU.S(""); StringBuffer sb = new StringBuffer(64); int i=0; while(true) { JS o = (JS)get(i); if(o != null) sb.append(JSU.toString(o)); if(++i == length) break; sb.append(sep); } return JSU.S(sb.toString()); } private JS slice(int start, int end) { int length = size(); 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 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 0) { setSize(newLength); for(int i=newLength-1;i>=start+newCount;i--) set(i, get(i-lengthChange)); } else if(lengthChange < 0) { for(int i=start+newCount;i