5 // Cesar Lopez Nataren (cesar@ciencias.unam.mx)
7 // (C) 2003, Cesar Lopez Nataren
8 // (C) 2005, Novell Inc, (http://novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
35 using Microsoft.JScript.Vsa;
37 namespace Microsoft.JScript {
39 public class ArrayPrototype : ArrayObject {
41 [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasEngine |
42 JSFunctionAttributeEnum.HasVarArgs, JSBuiltin.Array_concat)]
43 public static ArrayObject concat (object thisObj, VsaEngine engine,
44 params object [] args)
47 ArrayObject result = new ArrayObject ();
49 int arg_count = args.Length;
51 // TODO: Shouldn't this be generic!?
52 SemanticAnalyser.assert_type (thisObj, typeof (ArrayObject));
53 object cur_obj = thisObj;
56 while (cur_obj != null) {
57 if (cur_obj is ArrayObject) {
58 cur_ary = (ArrayObject) cur_obj;
60 int n = (int) cur_ary.length;
61 for (int j = 0; j < n; j++, i++)
62 result.elems [i] = cur_ary.elems [j];
64 result.elems [i++] = cur_obj;
67 cur_obj = arg_idx < arg_count ? args [arg_idx] : null;
75 public static ArrayConstructor constructor {
76 get { return ArrayConstructor.Ctr; }
79 [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_join)]
80 public static string join (object thisObj, object separator)
82 // TODO: Shouldn't this be generic!?
83 SemanticAnalyser.assert_type (thisObj, typeof (ArrayObject));
84 ArrayObject array_obj = (ArrayObject) thisObj;
87 if (separator == null)
90 _separator = Convert.ToString (separator);
92 Hashtable elems = array_obj.elems;
93 int n = (int) array_obj.length;
94 StringBuilder str = new StringBuilder ();
97 for (int i = 0; i < n; i++) {
99 str.Append (_separator);
101 object elem = elems [i];
103 str.Append (Convert.ToString (elem));
105 return str.ToString ();
108 [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_pop)]
109 public static object pop (object thisObj)
111 // TODO: Shouldn't this be generic!?
112 SemanticAnalyser.assert_type (thisObj, typeof (ArrayObject));
113 ArrayObject array_obj = (ArrayObject) thisObj;
114 Hashtable elems = array_obj.elems;
116 int n = (int) array_obj.length;
119 array_obj.length = new_len;
120 if (elems.ContainsKey (new_len)) {
121 object result = elems [new_len];
122 elems.Remove (new_len);
129 [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasVarArgs, JSBuiltin.Array_push)]
130 public static long push (object thisObj, params object [] args)
132 // TODO: Shouldn't this be generic!?
133 SemanticAnalyser.assert_type (thisObj, typeof (ArrayObject));
134 ArrayObject array_obj = (ArrayObject) thisObj;
135 Hashtable elems = array_obj.elems;
137 int i = (int) array_obj.length;
138 int n = i + args.Length;
140 for (int j = 0; i < n; i++, j++)
141 elems [i] = args [j];
143 array_obj.length = n;
147 [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_reverse)]
148 public static object reverse (object thisObj)
150 // TODO: Shouldn't this be generic!?
151 SemanticAnalyser.assert_type (thisObj, typeof (ArrayObject));
152 ArrayObject array_obj = (ArrayObject) thisObj;
153 Hashtable elems = array_obj.elems;
155 int n = (int) array_obj.length;
160 for (int i = 0; i < half_n; i++, j--) {
162 elems [i] = elems [j];
169 [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_shift)]
170 public static object shift (object thisObj)
172 // TODO: Shouldn't this be generic!?
173 SemanticAnalyser.assert_type (thisObj, typeof (ArrayObject));
174 ArrayObject array_obj = (ArrayObject) thisObj;
175 Hashtable elems = array_obj.elems;
177 int n = (int) array_obj.length;
179 array_obj.length = n - 1;
180 if (elems.ContainsKey (0)) {
181 object result = elems [0];
183 for (int i = 1; i < n; i++)
184 elems [i - 1] = elems [i];
185 elems.Remove (n - 1);
192 [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasEngine, JSBuiltin.Array_slice)]
193 public static ArrayObject slice (object thisObj, VsaEngine engine, double start, object end)
195 // TODO: Shouldn't this be generic!?
196 SemanticAnalyser.assert_type (thisObj, typeof (ArrayObject));
197 ArrayObject array_obj = (ArrayObject) thisObj;
198 int array_len = (int) array_obj.length;
201 if (start > array_len)
204 _start = (int) start;
212 _end = Convert.ToInt32 (end);
216 else if (_end > array_len)
223 ArrayObject result = new ArrayObject();
224 result.length = _end - _start;
226 for (int i = _start; i < _end; i++)
227 result.elems [i - _start] = array_obj.elems [i];
232 [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_sort)]
233 public static object sort (object thisObj, object function)
235 throw new NotImplementedException ();
238 [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasVarArgs | JSFunctionAttributeEnum.HasEngine, JSBuiltin.Array_splice)]
239 public static ArrayObject splice (object thisObj, VsaEngine engine,
240 double start, double deleteCnt,
241 params object [] args)
243 // TODO: Shouldn't this be generic!?
244 SemanticAnalyser.assert_type (thisObj, typeof (ArrayObject));
245 ArrayObject array_obj = (ArrayObject) thisObj;
246 ArrayObject result = new ArrayObject ();
247 Hashtable elems = array_obj.elems;
248 Hashtable del_elems = result.elems;
250 int old_length = (int) array_obj.length;
253 start = Math.Max (start + old_length, 0);
255 start = Math.Min (old_length, start);
257 deleteCnt = (int) deleteCnt;
258 deleteCnt = Math.Min (Math.Max (deleteCnt, 0), old_length - start);
260 int arg_length = args.Length;
261 int add_length = arg_length - (int) deleteCnt;
262 add_length = Math.Max (add_length, -old_length);
263 int del_length = -add_length;
264 int new_length = old_length + add_length;
267 // First let's make some free space for the new items (if needed)
268 if (add_length > 0) {
271 for (; i >= start; i--, j--)
272 elems [j] = elems [i];
275 // Then insert the new items in the now free space / replace existing ones
277 int old_start = (int) start + add_length;
278 for (i = (int) start; j < arg_length; i++, j++) {
279 if (i >= old_start && elems.ContainsKey (i)) {
280 del_elems [m] = elems [i];
286 elems [i] = args [j];
289 // Finally, delete elements which have no replacement elements
290 if (add_length < 0) {
291 int last_elem_idx = i + del_length;
292 for (int k = 0; k < del_length; i++, j++, k++) {
293 if (elems.ContainsKey (i)) {
294 del_elems [m] = elems [i];
300 // And move up trailing elements
301 int l = last_elem_idx - del_length;
302 for (int k = last_elem_idx; l < old_length; k++, l++) {
303 if (elems.ContainsKey (k))
304 elems [l] = elems [k];
305 else if (elems.ContainsKey (l))
310 array_obj.length = new_length;
311 result.length = (int) deleteCnt;
315 [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_toLocaleString)]
316 public static string toLocaleString (object thisObj)
318 throw new NotImplementedException ();
321 [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_toString)]
322 public static string toString (object thisObj)
324 SemanticAnalyser.assert_type (thisObj, typeof (ArrayObject));
325 return ArrayPrototype.join (thisObj, null);
328 [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasVarArgs, JSBuiltin.Array_unshift)]
329 public static object unshift (object thisObj, params object [] args)
331 // TODO: Shouldn't this be generic!?
332 SemanticAnalyser.assert_type (thisObj, typeof (ArrayObject));
333 ArrayObject array_obj = (ArrayObject) thisObj;
334 Hashtable elems = array_obj.elems;
336 int old_length = (int) array_obj.length;
337 int arg_length = args.Length;
338 int new_length = old_length + arg_length;
340 if (arg_length > 0) {
341 // First let's make some free space for the new items
342 int i = old_length - 1;
343 int j = i + arg_length;
344 for (; i >= 0; i--, j--)
345 elems [j] = elems [i];
347 // Then insert the new items in the now free space
349 elems [j] = args [j];
352 // NOTE: MSC returns the new array, but
353 // ECMA-262 says to return the new length. We
354 // conform to the standard.
356 array_obj.length = new_length;