1 /*
2  * Copyright (c) 2003
3  *      David Leonard.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of David Leonard nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #if HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34 
35 #include <see/mem.h>
36 #include <see/value.h>
37 #include <see/string.h>
38 #include <see/object.h>
39 #include <see/native.h>
40 #include <see/cfunction.h>
41 #include <see/error.h>
42 #include <see/interpreter.h>
43 #include <see/debug.h>
44 #include <see/intern.h>
45 
46 #include "stringdefs.h"
47 #include "array.h"
48 #include "parse.h"
49 #include "init.h"
50 #include "nmath.h"
51 
52 /*
53  * The Array object.
54  * 15.4
55  */
56 
57 /* structure of array instances */
58 struct array_object {
59 	struct SEE_native native;
60 	SEE_uint32_t length;
61 };
62 
63 
64 /* Prototypes */
65 static void intstr_p(struct SEE_string *, SEE_uint32_t);
66 static struct SEE_string *intstr(struct SEE_interpreter *,
67 	struct SEE_string **, SEE_uint32_t);
68 static struct array_object *toarray(struct SEE_interpreter *,
69 	struct SEE_object *);
70 static void check_too_long(struct SEE_interpreter *, SEE_uint32_t,
71 	SEE_uint32_t);
72 
73 static void array_init(struct array_object *, struct SEE_interpreter *,
74 	unsigned int);
75 static void array_construct(struct SEE_interpreter *, struct SEE_object *,
76 	struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
77 
78 static void array_proto_toString(struct SEE_interpreter *,
79 	struct SEE_object *, struct SEE_object *, int, struct SEE_value **,
80 	struct SEE_value *);
81 static void array_proto_toLocaleString(struct SEE_interpreter *,
82 	struct SEE_object *, struct SEE_object *, int, struct SEE_value **,
83 	struct SEE_value *);
84 static void array_proto_concat(struct SEE_interpreter *, struct SEE_object *,
85 	struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
86 static void array_proto_join(struct SEE_interpreter *, struct SEE_object *,
87 	struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
88 static void array_proto_pop(struct SEE_interpreter *, struct SEE_object *,
89 	struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
90 static void array_proto_push(struct SEE_interpreter *, struct SEE_object *,
91 	struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
92 static void array_proto_reverse(struct SEE_interpreter *, struct SEE_object *,
93 	struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
94 static void array_proto_shift(struct SEE_interpreter *, struct SEE_object *,
95 	struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
96 static void array_proto_slice(struct SEE_interpreter *, struct SEE_object *,
97 	struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
98 static int SortCompare(struct SEE_interpreter *, struct SEE_value *,
99 	struct SEE_value *, struct SEE_object *);
100 static int qs_partition(struct SEE_interpreter *, struct SEE_object *,
101 	SEE_uint32_t, SEE_uint32_t, struct SEE_object *, struct SEE_string **,
102 	struct SEE_string **);
103 static void qs_sort(struct SEE_interpreter *, struct SEE_object *,
104 	SEE_uint32_t, SEE_uint32_t, struct SEE_object *, struct SEE_string **,
105 	struct SEE_string **);
106 static void array_proto_sort(struct SEE_interpreter *, struct SEE_object *,
107 	struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
108 static void array_proto_splice(struct SEE_interpreter *, struct SEE_object *,
109 	struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
110 static void array_proto_unshift(struct SEE_interpreter *, struct SEE_object *,
111 	struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
112 static void array_setlength(struct SEE_interpreter *, struct array_object *,
113 	struct SEE_value *);
114 
115 static void array_get(struct SEE_interpreter *, struct SEE_object *,
116 	struct SEE_string *, struct SEE_value *);
117 static void array_put(struct SEE_interpreter *, struct SEE_object *,
118 	struct SEE_string *, struct SEE_value *, int);
119 static int array_hasproperty(struct SEE_interpreter *, struct SEE_object *,
120 	struct SEE_string *);
121 static int array_delete(struct SEE_interpreter *, struct SEE_object *,
122 	struct SEE_string *);
123 
124 /* object class for Array constructor */
125 static struct SEE_objectclass array_const_class = {
126 	"ArrayConstructor",		/* Class */
127 	SEE_native_get,			/* Get */
128 	SEE_native_put,			/* Put */
129 	SEE_native_canput,		/* CanPut */
130 	SEE_native_hasproperty,		/* HasProperty */
131 	SEE_native_delete,		/* Delete */
132 	SEE_native_defaultvalue,	/* DefaultValue */
133 	SEE_native_enumerator,		/* DefaultValue */
134 	array_construct,
135 	array_construct,
136 };
137 
138 /* object class for array instances */
139 static struct SEE_objectclass array_inst_class = {
140 	"Array",			/* Class */
141 	array_get,			/* Get */
142 	array_put,			/* Put */
143 	SEE_native_canput,		/* CanPut */
144 	array_hasproperty,		/* HasProperty */
145 	array_delete,			/* Delete */
146 	SEE_native_defaultvalue,	/* DefaultValue */
147 	SEE_native_enumerator		/* enumerator */
148 };
149 
150 void
SEE_Array_alloc(interp)151 SEE_Array_alloc(interp)
152 	struct SEE_interpreter *interp;
153 {
154 	interp->Array =
155 		(struct SEE_object *)SEE_NEW(interp, struct SEE_native);
156 	interp->Array_prototype =
157 		(struct SEE_object *)SEE_NEW(interp, struct array_object);
158 }
159 
160 void
SEE_Array_init(interp)161 SEE_Array_init(interp)
162 	struct SEE_interpreter *interp;
163 {
164 	struct SEE_object *Array;		/* struct SEE_native */
165 	struct SEE_object *Array_prototype;	/* struct array_object */
166 	struct SEE_value v;
167 
168 	Array = interp->Array;
169 	Array_prototype = interp->Array_prototype;
170 
171 	SEE_native_init((struct SEE_native *)Array, interp, &array_const_class,
172 		interp->Function_prototype);
173 
174 	/* 15.4.3 Array.length = 1 */
175 	SEE_SET_NUMBER(&v, 1);
176 	SEE_OBJECT_PUT(interp, Array, STR(length), &v, SEE_ATTR_LENGTH);
177 
178 	/* 15.4.3.1 Array.prototype */
179 	SEE_SET_OBJECT(&v, Array_prototype);
180 	SEE_OBJECT_PUT(interp, Array, STR(prototype), &v,
181 		SEE_ATTR_DONTENUM | SEE_ATTR_DONTDELETE | SEE_ATTR_READONLY);
182 
183 	/* 15.4.4 Array.prototype.length = 0 */
184 	array_init((struct array_object *)Array_prototype, interp, 0);
185 
186 	/* 14.4.4 Array.prototype.[[Prototype]] = Object.prototype */
187 	Array_prototype->Prototype = interp->Object_prototype;
188 
189 	/* 15.4.4.1 Array.prototype.constructor = Array */
190 	SEE_SET_OBJECT(&v, Array);
191 	SEE_OBJECT_PUT(interp, Array_prototype, STR(constructor), &v,
192 		SEE_ATTR_DEFAULT);
193 
194 #define PUTFUNC(name, len) 						  \
195 	SEE_SET_OBJECT(&v, SEE_cfunction_make(interp, array_proto_##name, \
196 		STR(name), len)); 					  \
197 	SEE_OBJECT_PUT(interp, Array_prototype, STR(name), &v, 		  \
198 		SEE_ATTR_DEFAULT);
199 
200 	PUTFUNC(toString, 0)			/* 15.4.4.2 */
201 	PUTFUNC(toLocaleString, 0)		/* 15.4.4.3 */
202 	PUTFUNC(concat, 1)			/* 15.4.4.4 */
203 	PUTFUNC(join, 1)			/* 15.4.4.5 */
204 	PUTFUNC(pop, 0)				/* 15.4.4.6 */
205 	PUTFUNC(push, 1)			/* 15.4.4.7 */
206 	PUTFUNC(reverse, 0)			/* 15.4.4.8 */
207 	PUTFUNC(shift, 0)			/* 15.4.4.9 */
208 	PUTFUNC(slice, 2)			/* 15.4.4.10 */
209 	PUTFUNC(sort, 1)			/* 15.4.4.11 */
210 	PUTFUNC(splice, 2)			/* 15.4.4.12 */
211 	PUTFUNC(unshift, 1)			/* 15.4.4.13 */
212 }
213 
214 #define MAX_ARRAY_INDEX	       4294967295
215 #define MAX_ARRAY_INDEX_DIV_10 429496729
216 #define MAX_ARRAY_INDEX_MOD_10          5
217 
218 /*
219  * Helper function that returns true if the string
220  * is an integer property less than 2^32-1 (4294967295), and stores
221  * the integer value in the given pointer. Don't allow leading zeroes.
222  */
223 int
SEE_to_array_index(s,ip)224 SEE_to_array_index(s, ip)
225 	struct SEE_string *s;
226 	SEE_uint32_t *ip;
227 {
228 	SEE_uint32_t n = 0;
229 	unsigned int i, digit;
230 
231 	if (s->length == 0)
232 		return 0;
233 	/* Don't allow leading zeros */
234 	if (s->data[0] == '0' && s->length != 1)
235 		return 0;
236 	for (i = 0; i < s->length; i++) {
237 	    if (s->data[i] < '0' || s->data[i] > '9')
238 		return 0;
239 	    digit = s->data[i] - '0';
240 	    if (n > (MAX_ARRAY_INDEX_DIV_10) ||
241 	        (n == (MAX_ARRAY_INDEX_DIV_10) &&
242 		 digit >= (MAX_ARRAY_INDEX_MOD_10)))
243 		    return 0;
244 	    n = n * 10 + digit;
245 	}
246 	*ip = n;
247 	return 1;
248 }
249 
250 /*
251  * Helper functions for quickly building a string from an integer.
252  * Only called from intstr().
253  */
254 static void
intstr_p(s,i)255 intstr_p(s, i)
256 	struct SEE_string *s;
257 	SEE_uint32_t i;
258 {
259 	if (i >= 10)
260 		intstr_p(s, i / 10);
261 	SEE_string_addch(s, '0' + (i % 10));
262 }
263 
264 /*
265  * If sp is null, allocates a new empty string.
266  * Clears the string *sp and puts unsigned integer i into it.
267  * Returns an intern'd string
268  */
269 static struct SEE_string *
intstr(interp,sp,i)270 intstr(interp, sp, i)
271 	struct SEE_interpreter *interp;
272 	struct SEE_string **sp;
273 	SEE_uint32_t i;
274 {
275 	switch (i) {
276 	case 0: return STR(zero_digit);
277 	case 1: return STR(1);
278 	case 2: return STR(2);
279 	case 3: return STR(3);
280 	case 4: return STR(4);
281 	case 5: return STR(5);
282 	case 6: return STR(6);
283 	case 7: return STR(7);
284 	case 8: return STR(8);
285 	case 9: return STR(9);
286 	}
287 
288 	if (!*sp)
289 		*sp = SEE_string_new(interp, 9);
290 	else
291 		(*sp)->length = 0;
292 	intstr_p(*sp, i);
293 	return SEE_intern(interp, *sp);
294 }
295 
296 /*
297  * Convert the object to a native array, or raise an error
298  */
299 static struct array_object *
toarray(interp,o)300 toarray(interp, o)
301 	struct SEE_interpreter *interp;
302 	struct SEE_object *o;
303 {
304 	if (!SEE_is_Array(o))
305 	    SEE_error_throw_string(interp, interp->TypeError,
306 		STR(not_array));
307 	return (struct array_object *)o;
308 }
309 
310 /* Throws a RangeError if a + b would exceed the maximum array length */
311 static void
check_too_long(interp,a,b)312 check_too_long(interp, a, b)
313 	struct SEE_interpreter *interp;
314 	SEE_uint32_t a, b;
315 {
316 	if (a + b < a || a + b < b)
317 	    SEE_error_throw(interp, interp->RangeError,
318 	    	"array too long");
319 }
320 
321 int
SEE_is_Array(o)322 SEE_is_Array(o)
323 	struct SEE_object *o;
324 {
325 	return o && o->objectclass == &array_inst_class;
326 }
327 
328 /* Fast native array push() */
329 void
SEE_Array_push(interp,o,v)330 SEE_Array_push(interp, o, v)
331 	struct SEE_interpreter *interp;
332 	struct SEE_object *o;
333 	struct SEE_value *v;
334 {
335 	struct array_object *a;
336 	struct SEE_string *s = NULL;
337 
338 	a = toarray(interp, o);
339 	check_too_long(interp, a->length, 1);
340 	SEE_native_put(interp, o, intstr(interp, &s, a->length), v, 0);
341 	a->length++;
342 }
343 
344 SEE_uint32_t
SEE_Array_length(interp,o)345 SEE_Array_length(interp, o)
346 	struct SEE_interpreter *interp;
347 	struct SEE_object *o;
348 {
349 	struct array_object *a = toarray(interp, o);
350 	return a->length;
351 }
352 
353 /* helper function to build an array instance */
354 static void
array_init(ao,interp,length)355 array_init(ao, interp, length)
356 	struct array_object *ao;
357 	struct SEE_interpreter *interp;
358 	unsigned int length;
359 {
360 	SEE_native_init(&ao->native, interp, &array_inst_class,
361 	    interp->Array_prototype);
362 	ao->length = length;
363 }
364 
365 /* 15.4.4.2 */
366 static void
array_construct(interp,self,thisobj,argc,argv,res)367 array_construct(interp, self, thisobj, argc, argv, res)
368 	struct SEE_interpreter *interp;
369 	struct SEE_object *self, *thisobj;
370 	int argc;
371 	struct SEE_value **argv;
372 	struct SEE_value *res;
373 {
374 	struct array_object *ao;
375 	int i;
376 	SEE_uint32_t length;
377 	struct SEE_string *s = NULL;
378 
379 	if (argc == 1 && SEE_VALUE_GET_TYPE(argv[0]) == SEE_NUMBER &&
380 		!SEE_COMPAT_JS(interp, ==, JS12))
381 	{
382 	    length = SEE_ToUint32(interp, argv[0]);
383 	    if (argv[0]->u.number != length)
384 		SEE_error_throw_string(interp, interp->RangeError,
385 		   STR(array_badlen));
386 	    ao = SEE_NEW(interp, struct array_object);
387 	    array_init(ao, interp, length);
388 	} else {
389 	    ao = SEE_NEW(interp, struct array_object);
390 	    array_init(ao, interp, argc);
391 	    for (i = 0; i < argc; i++) {
392 		SEE_native_put(interp, (struct SEE_object *)&ao->native,
393 			intstr(interp, &s, i), argv[i], 0);
394 	    }
395 	}
396 	SEE_SET_OBJECT(res, (struct SEE_object *)ao);
397 }
398 
399 /* 15.4.4.2 */
400 static void
array_proto_toString(interp,self,thisobj,argc,argv,res)401 array_proto_toString(interp, self, thisobj, argc, argv, res)
402 	struct SEE_interpreter *interp;
403 	struct SEE_object *self, *thisobj;
404 	int argc;
405 	struct SEE_value **argv, *res;
406 {
407 	(void)toarray(interp, thisobj);
408 	if (SEE_COMPAT_JS(interp, ==, JS12)) {
409 		struct SEE_string *s = SEE_string_new(interp, 0);
410 		struct SEE_string *n = NULL;
411 		int lastundef = 0;
412 		SEE_uint32_t length, i;
413 		struct SEE_value v, vs;
414 		unsigned int j;
415 
416 		if (!thisobj)
417 		    SEE_error_throw_string(interp, interp->TypeError,
418 		       STR(null_thisobj));
419 
420 		SEE_string_addch(s, '[');
421 		SEE_OBJECT_GET(interp, thisobj, STR(length), &v);
422 		length = SEE_ToUint32(interp, &v);
423 		for (i = 0; i < length; i++) {
424 		    if (i) {
425 		        SEE_string_addch(s, ',');
426 		        SEE_string_addch(s, ' ');
427 		    }
428 		    SEE_OBJECT_GET(interp, thisobj, intstr(interp, &n, i), &v);
429 		    lastundef = 0;
430 		    switch (SEE_VALUE_GET_TYPE(&v)) {
431 		    case SEE_UNDEFINED:
432 		    	lastundef = 1;
433 			break;
434 		    case SEE_STRING:
435 			SEE_string_addch(s, '"');
436 			for (j = 0; j < v.u.string->length; j++) {
437 			    if (v.u.string->data[j] == '\"' ||
438 				v.u.string->data[j] == '\\')
439 				    SEE_string_addch(s, '\\');
440 			    SEE_string_addch(s, v.u.string->data[j]);
441 			}
442 			SEE_string_addch(s, '"');
443 			break;
444 		    default:
445 			SEE_ToString(interp, &v, &vs);
446 			SEE_string_append(s, vs.u.string);
447 			break;
448 		    }
449 		}
450 	        if (lastundef) {
451 		    SEE_string_addch(s, ',');
452 		    SEE_string_addch(s, ' ');
453 	        }
454 		SEE_string_addch(s, ']');
455 		SEE_SET_STRING(res, s);
456 	} else
457 		array_proto_join(interp, self, thisobj, 0, NULL, res);
458 }
459 
460 /* 15.4.4.3 */
461 static void
array_proto_toLocaleString(interp,self,thisobj,argc,argv,res)462 array_proto_toLocaleString(interp, self, thisobj, argc, argv, res)
463 	struct SEE_interpreter *interp;
464 	struct SEE_object *self, *thisobj;
465 	int argc;
466 	struct SEE_value **argv, *res;
467 {
468 	struct SEE_value v, r6, r7;
469 	struct SEE_string *separator, *s, *n = NULL;
470 	SEE_uint32_t length, i;
471 
472 	if (!thisobj)
473 	    SEE_error_throw_string(interp, interp->TypeError,
474 	       STR(null_thisobj));
475 
476 	SEE_OBJECT_GET(interp, thisobj, STR(length), &v);
477 	length = SEE_ToUint32(interp, &v);
478 
479 	separator = STR(comma);		/* TODO: should be locale-dependent */
480 
481 	if (length == 0) {
482 	    SEE_SET_STRING(res, STR(empty_string));
483 	    return;
484 	}
485 
486 	s = SEE_string_new(interp, 0);
487 	if (length) {
488 	    for (i = 0; i < length; i++) {
489 		if (i)
490 		    SEE_string_append(s, separator);
491 		SEE_OBJECT_GET(interp, thisobj, intstr(interp, &n, i), &r6);
492 		if (!(SEE_VALUE_GET_TYPE(&r6) == SEE_UNDEFINED ||
493 		      SEE_VALUE_GET_TYPE(&r6) == SEE_NULL))
494 		{
495 		    SEE_ToObject(interp, &r6, &r7);
496 		    SEE_OBJECT_GET(interp, r7.u.object,
497 		    	STR(toLocaleString), &v);
498 		    if (SEE_VALUE_GET_TYPE(&v) != SEE_OBJECT ||
499 				!SEE_OBJECT_HAS_CALL(v.u.object))
500 			SEE_error_throw_string(interp, interp->TypeError,
501 			    STR(toLocaleString_notfunc));
502 		    SEE_OBJECT_CALL(interp, v.u.object, r7.u.object,
503 			0, NULL, &v);
504 		    if (SEE_VALUE_GET_TYPE(&v) != SEE_STRING)
505 			SEE_error_throw_string(interp, interp->TypeError,
506 			    STR(toLocaleString_notstring));
507 		    SEE_string_append(s, v.u.string);
508 		}
509 	    }
510 	}
511 	SEE_SET_STRING(res, s);
512 }
513 
514 /* 15.4.4.4 */
515 static void
array_proto_concat(interp,self,thisobj,argc,argv,res)516 array_proto_concat(interp, self, thisobj, argc, argv, res)
517 	struct SEE_interpreter *interp;
518 	struct SEE_object *self, *thisobj;
519 	int argc;
520 	struct SEE_value **argv, *res;
521 {
522 	struct SEE_value v, *E, thisv;
523 	struct SEE_object *A;
524 	SEE_uint32_t n, k;
525 	int i;
526 	struct SEE_string *nsbuf = NULL, *ns;
527 
528 	if (!thisobj)
529 	    SEE_error_throw_string(interp, interp->TypeError,
530 	       STR(null_thisobj));
531 
532 	SEE_OBJECT_CONSTRUCT(interp, interp->Array, NULL, 0, NULL, &v);
533 	A = v.u.object;
534 	n = 0;
535 	SEE_SET_OBJECT(&thisv, thisobj);
536 	E = &thisv;
537 	i = 0;
538 	for(;;) {
539 	    if (SEE_VALUE_GET_TYPE(E) == SEE_OBJECT &&
540 	    	SEE_is_Array(E->u.object))
541 	    {
542 		struct array_object *Ea = (struct array_object *)E->u.object;
543 		for (k = 0; k < Ea->length; k++) {
544 		    check_too_long(interp, n, 1);
545 		    ns = intstr(interp, &nsbuf, k);
546 		    if (SEE_OBJECT_HASPROPERTY(interp, E->u.object, ns)) {
547 			SEE_OBJECT_GET(interp, E->u.object, ns, &v);
548 			SEE_OBJECT_PUT(interp, A, intstr(interp, &nsbuf, n),
549 			    &v, 0);
550 		    }
551 		    n++;
552 		}
553 	    } else {
554 	        check_too_long(interp, n, 1);
555 		SEE_OBJECT_PUT(interp, A, intstr(interp, &nsbuf, n), E, 0);
556 		n++;
557 	    }
558 	    if (i >= argc) break;
559 	    E = argv[i++];
560 	}
561 	SEE_SET_NUMBER(&v, n); SEE_OBJECT_PUT(interp, A, STR(length), &v, 0);
562 	SEE_SET_OBJECT(res, A);
563 }
564 
565 /* 15.4.4.5 */
566 static void
array_proto_join(interp,self,thisobj,argc,argv,res)567 array_proto_join(interp, self, thisobj, argc, argv, res)
568 	struct SEE_interpreter *interp;
569 	struct SEE_object *self, *thisobj;
570 	int argc;
571 	struct SEE_value **argv, *res;
572 {
573 	struct SEE_value v, r6, r7;
574 	struct SEE_string *separator, *s, *n = NULL;
575 	SEE_uint32_t length, i;
576 	int use_comma;
577 
578 	if (!thisobj)
579 	    SEE_error_throw_string(interp, interp->TypeError,
580 	       STR(null_thisobj));
581 
582 	SEE_OBJECT_GET(interp, thisobj, STR(length), &v);
583 	length = SEE_ToUint32(interp, &v);
584 
585 /* XXX fixme
586 	if (interp->compatibility & SEE_COMPAT_ARRAYJOIN1)  EXT:16
587 		use_comma = (argc == 0);
588 	else
589 */
590 		/* strict E262-3 behaviour: */
591 		use_comma = (argc == 0 ||
592 			     SEE_VALUE_GET_TYPE(argv[0]) == SEE_UNDEFINED);
593 
594 	if (use_comma)
595 		separator = STR(comma);
596 	else {
597 		SEE_ToString(interp, argv[0], &v);
598 		separator = v.u.string;
599 	}
600 
601 	s = SEE_string_new(interp, 0);
602 	if (length) {
603 	    for (i = 0; i < length; i++) {
604 		if (i)
605 		    SEE_string_append(s, separator);
606 		SEE_OBJECT_GET(interp, thisobj, intstr(interp, &n, i), &r6);
607 		if (!(SEE_VALUE_GET_TYPE(&r6) == SEE_UNDEFINED ||
608 		      SEE_VALUE_GET_TYPE(&r6) == SEE_NULL))
609 		{
610 		    SEE_ToString(interp, &r6, &r7);
611 		    SEE_string_append(s, r7.u.string);
612 		}
613 	    }
614 	}
615 	SEE_SET_STRING(res, s);
616 }
617 
618 /* 15.4.4.6 */
619 static void
array_proto_pop(interp,self,thisobj,argc,argv,res)620 array_proto_pop(interp, self, thisobj, argc, argv, res)
621 	struct SEE_interpreter *interp;
622 	struct SEE_object *self, *thisobj;
623 	int argc;
624 	struct SEE_value **argv, *res;
625 {
626 	struct SEE_value v;
627 	SEE_uint32_t i;
628 	struct SEE_string *s = NULL, *si;
629 
630 	if (!thisobj)
631 	    SEE_error_throw_string(interp, interp->TypeError,
632 	       STR(null_thisobj));
633 
634 	SEE_OBJECT_GET(interp, thisobj, STR(length), &v);
635 	i = SEE_ToUint32(interp, &v);
636 	if (i == 0) {
637 		SEE_SET_NUMBER(&v, i);
638 		SEE_OBJECT_PUT(interp, thisobj, STR(length), &v, 0);
639 		SEE_SET_UNDEFINED(res);
640 		return;
641 	}
642 	si = intstr(interp, &s, i - 1);
643 	SEE_OBJECT_GET(interp, thisobj, si, res);
644 	SEE_OBJECT_DELETE(interp, thisobj, si);
645 	SEE_SET_NUMBER(&v, i - 1);
646 	SEE_OBJECT_PUT(interp, thisobj, STR(length), &v, 0);
647 }
648 
649 /* 15.4.4.7 */
650 static void
array_proto_push(interp,self,thisobj,argc,argv,res)651 array_proto_push(interp, self, thisobj, argc, argv, res)
652 	struct SEE_interpreter *interp;
653 	struct SEE_object *self, *thisobj;
654 	int argc;
655 	struct SEE_value **argv, *res;
656 {
657 	int i;
658 	SEE_uint32_t n;
659 	struct SEE_value v;
660 	struct SEE_string *np = NULL;
661 
662 	if (!thisobj)
663 	    SEE_error_throw_string(interp, interp->TypeError,
664 	       STR(null_thisobj));
665 
666         SEE_OBJECT_GET(interp, thisobj, STR(length), &v);
667         n = SEE_ToUint32(interp, &v);
668 	for (i = 0; i < argc; i++) {
669 	    check_too_long(interp, n, 1);
670 	    SEE_OBJECT_PUT(interp, thisobj, intstr(interp, &np, n),
671 	        argv[i], 0);
672 	    n++;
673 	}
674 	SEE_SET_NUMBER(res, n);
675         SEE_OBJECT_PUT(interp, thisobj, STR(length), res, 0);
676 }
677 
678 /* 15.4.4.8 */
679 static void
array_proto_reverse(interp,self,thisobj,argc,argv,res)680 array_proto_reverse(interp, self, thisobj, argc, argv, res)
681 	struct SEE_interpreter *interp;
682 	struct SEE_object *self, *thisobj;
683 	int argc;
684 	struct SEE_value **argv, *res;
685 {
686 	struct SEE_value v, r9, r10;
687 	struct SEE_string *r7, *r7s = NULL, *r8, *r8s = NULL;
688 	SEE_uint32_t k, r2, r3, r6;
689 
690 	if (!thisobj)
691 	    SEE_error_throw_string(interp, interp->TypeError,
692 	       STR(null_thisobj));
693 
694 	SEE_OBJECT_GET(interp, thisobj, STR(length), &v);
695 	r2 = SEE_ToUint32(interp, &v);
696 	r3 = r2 / 2;	/* NB implicit floor() from integer div */
697 	for (k = 0; k < r3; k++) {
698 	    r6 = r2 - k - 1;
699 	    r7 = intstr(interp, &r7s, k);
700 	    r8 = intstr(interp, &r8s, r6);
701 	    SEE_OBJECT_GET(interp, thisobj, r7, &r9);
702 	    SEE_OBJECT_GET(interp, thisobj, r8, &r10);
703 	    if (SEE_OBJECT_HASPROPERTY(interp, thisobj, r8)) {
704 		if (SEE_OBJECT_HASPROPERTY(interp, thisobj, r7)) {
705 		    SEE_OBJECT_PUT(interp, thisobj, r7, &r10, 0);
706 		    SEE_OBJECT_PUT(interp, thisobj, r8, &r9, 0);
707 		} else {
708 		    SEE_OBJECT_PUT(interp, thisobj, r7, &r10, 0);
709 		    SEE_OBJECT_DELETE(interp, thisobj, r8);
710 		}
711 	    } else if (SEE_OBJECT_HASPROPERTY(interp, thisobj, r7)) {
712 		SEE_OBJECT_DELETE(interp, thisobj, r7);
713 		SEE_OBJECT_PUT(interp, thisobj, r8, &r9, 0);
714 	    } else {
715 		SEE_OBJECT_DELETE(interp, thisobj, r7);
716 		SEE_OBJECT_DELETE(interp, thisobj, r8);
717 	    }
718 	}
719 	SEE_SET_OBJECT(res, thisobj);
720 }
721 
722 /* 15.4.4.9 */
723 static void
array_proto_shift(interp,self,thisobj,argc,argv,res)724 array_proto_shift(interp, self, thisobj, argc, argv, res)
725 	struct SEE_interpreter *interp;
726 	struct SEE_object *self, *thisobj;
727 	int argc;
728 	struct SEE_value **argv, *res;
729 {
730 	struct SEE_value v;
731 	struct SEE_string *s = NULL, *p;
732 	SEE_uint32_t k, r2;
733 
734 	if (!thisobj)
735 	    SEE_error_throw_string(interp, interp->TypeError,
736 	       STR(null_thisobj));
737 
738 	SEE_OBJECT_GET(interp, thisobj, STR(length), &v);
739 	r2 = SEE_ToUint32(interp, &v);
740 	if (r2 == 0) {
741 	    SEE_SET_NUMBER(&v, r2);
742 	    SEE_OBJECT_PUT(interp, thisobj, STR(length), &v, 0);
743 	    SEE_SET_UNDEFINED(res);
744 	    return;
745 	}
746 	SEE_OBJECT_GET(interp, thisobj, STR(zero_digit), res);
747 	for (k = 1; k < r2; k++) {
748 	    p = intstr(interp, &s, k);
749 	    if (SEE_OBJECT_HASPROPERTY(interp, thisobj, p)) {
750 		SEE_OBJECT_GET(interp, thisobj, p, &v);
751 		SEE_OBJECT_PUT(interp, thisobj, intstr(interp, &s, k - 1),
752 		    &v, 0);
753 	    } else {
754 		SEE_OBJECT_DELETE(interp, thisobj, intstr(interp, &s, k - 1));
755 	    }
756 	}
757 	SEE_OBJECT_DELETE(interp, thisobj, intstr(interp, &s, r2 - 1));
758 	SEE_SET_NUMBER(&v, r2 - 1);
759 	SEE_OBJECT_PUT(interp, thisobj, STR(length), &v, 0);
760 }
761 
762 /* 15.4.4.10 */
763 static void
array_proto_slice(interp,self,thisobj,argc,argv,res)764 array_proto_slice(interp, self, thisobj, argc, argv, res)
765 	struct SEE_interpreter *interp;
766 	struct SEE_object *self, *thisobj;
767 	int argc;
768 	struct SEE_value **argv, *res;
769 {
770 	struct SEE_object *A;
771 	SEE_uint32_t r3, r5, r8, k, n;
772 	struct SEE_string *s = NULL, *p;
773 	struct SEE_value v;
774 
775 	if (argc < 1) {
776 		SEE_SET_UNDEFINED(res);
777 		return;
778 	}
779 
780 	if (!thisobj)
781 	    SEE_error_throw_string(interp, interp->TypeError,
782 	       STR(null_thisobj));
783 
784 	SEE_OBJECT_CONSTRUCT(interp, interp->Array, NULL, 0, NULL, &v);
785 	A = v.u.object;
786 
787 	SEE_OBJECT_GET(interp, thisobj, STR(length), &v);
788 	r3 = SEE_ToUint32(interp, &v);
789 
790 	SEE_ToInteger(interp, argv[0], &v);
791 	r5 = -v.u.number > r3 ? 0 :
792 	     v.u.number < 0   ? (SEE_uint32_t)(r3 + v.u.number) :
793 	     v.u.number < r3  ? (SEE_uint32_t)v.u.number :
794 	     			r3;
795 	if (argc < 2 || SEE_VALUE_GET_TYPE(argv[1]) == SEE_UNDEFINED)
796 		r8 = r3;
797 	else {
798 	    SEE_ToInteger(interp, argv[1], &v);
799 	    r8 = -v.u.number > r3 ? 0 :
800 	    	 v.u.number < 0   ? (SEE_uint32_t)(r3 + v.u.number) :
801 	    	 v.u.number < r3  ? (SEE_uint32_t)v.u.number :
802 		 		    r3;
803 	}
804 	for (k = r5, n = 0; k < r8; k++, n++) {
805 	    p = intstr(interp, &s, k);
806 	    if (SEE_OBJECT_HASPROPERTY(interp, thisobj, p)) {
807 		SEE_OBJECT_GET(interp, thisobj, p, &v);
808 		SEE_OBJECT_PUT(interp, A, intstr(interp, &s, n), &v, 0);
809 	    }
810 	}
811 	SEE_SET_NUMBER(&v, n);
812 	SEE_OBJECT_PUT(interp, A, STR(length), &v, 0);
813 	SEE_SET_OBJECT(res, A);
814 }
815 
816 /*
817  * A sort comparison function similar to that in 15.4.4.11,
818  * except that our quicksort has already used get/put/hasproperty
819  * on the array, and we represent this with pointers x and y.
820  * If the pointers are NULL, then the elements don't exist in the
821  * array, and should be sorted higher than anything else. If the
822  * pointers point to undefined, then they should be sorted second-highest.
823  */
824 static int
SortCompare(interp,x,y,cmpfn)825 SortCompare(interp, x, y, cmpfn)
826 	struct SEE_interpreter *interp;
827 	struct SEE_value *x, *y;
828 	struct SEE_object *cmpfn;
829 {
830 	if (!x && !y)   return 0;
831 	if (!x)		return 1;
832 	if (!y)		return -1;
833 	if (SEE_VALUE_GET_TYPE(x) == SEE_UNDEFINED &&
834 	    SEE_VALUE_GET_TYPE(y) == SEE_UNDEFINED) return 0;
835 	if (SEE_VALUE_GET_TYPE(x) == SEE_UNDEFINED) return 1;
836 	if (SEE_VALUE_GET_TYPE(y) == SEE_UNDEFINED) return -1;
837 	if (cmpfn) {
838 		struct SEE_value vn, *arg[2];
839 		arg[0] = x;
840 		arg[1] = y;
841 		SEE_OBJECT_CALL(interp, cmpfn, cmpfn, 2, arg, &vn);
842 		if (SEE_VALUE_GET_TYPE(&vn) != SEE_NUMBER ||
843 		    SEE_NUMBER_ISNAN(&vn))
844 			SEE_error_throw_string(interp, interp->TypeError,
845 			    STR(array_sort_error));
846 		if (vn.u.number < 0) return -1;
847 		if (vn.u.number > 0) return 1;
848 		return 0;
849 	} else {
850 		struct SEE_value xs, ys;
851 		SEE_ToString(interp, x, &xs);
852 		SEE_ToString(interp, y, &ys);
853 		return SEE_string_cmp(xs.u.string, ys.u.string);
854 	}
855 }
856 
857 /**
858  * Quicksort partition: partitions the given segment into numbers
859  * smaller, then larger than the first element, using swaps.
860  * Returns the index of the pivot point.
861  */
862 static int
qs_partition(interp,thisobj,lo,hi,cmpfn,s1,s2)863 qs_partition(interp, thisobj, lo, hi, cmpfn, s1, s2)
864 	struct SEE_interpreter *interp;
865 	struct SEE_object *thisobj;
866 	SEE_uint32_t lo, hi;
867 	struct SEE_object *cmpfn;
868 	struct SEE_string **s1, **s2;
869 {
870 	struct SEE_value xv, iv, jv;
871 	struct SEE_value *xvp = NULL, *ivp = NULL, *jvp = NULL;
872 	struct SEE_string *s1p, *s2p = NULL;
873 	SEE_uint32_t i = lo - 1;
874 	SEE_uint32_t j = hi + 1;
875 
876 	s1p = intstr(interp, s1, lo - 1);
877 	if (SEE_OBJECT_HASPROPERTY(interp, thisobj, s1p)) {
878 		SEE_OBJECT_GET(interp, thisobj, s1p, &xv);
879 		xvp = &xv;
880 	} else
881 		xvp = NULL;
882 
883 	for (;;) {
884 	    do {
885 		if (j == lo) break;
886 		j--;
887 		s2p = intstr(interp, s2, j - 1);
888 		if (SEE_OBJECT_HASPROPERTY(interp, thisobj, s2p)) {
889 			SEE_OBJECT_GET(interp, thisobj, s2p, &jv);
890 			jvp = &jv;
891 		} else
892 			jvp = NULL;
893 	    } while (SortCompare(interp, xvp, jvp, cmpfn) < 0);
894 	    do {
895 		if (i == hi) break;
896 		i++;
897 		s1p = intstr(interp, s1, i - 1);
898 		if (SEE_OBJECT_HASPROPERTY(interp, thisobj, s1p)) {
899 			SEE_OBJECT_GET(interp, thisobj, s1p, &iv);
900 			ivp = &iv;
901 		} else
902 			ivp = NULL;
903 	    } while (SortCompare(interp, ivp, xvp, cmpfn) < 0);
904 	    if (i < j) {
905 		/*
906 		 * At this stage, s1p will always be "i" and s2p will
907 		 * always be "j".
908 		 */
909 
910 		if (ivp) SEE_OBJECT_PUT(interp, thisobj, s2p, ivp, 0);
911 		else	 SEE_OBJECT_DELETE(interp, thisobj, s2p);
912 		if (jvp) SEE_OBJECT_PUT(interp, thisobj, s1p, &jv, 0);
913 		else     SEE_OBJECT_DELETE(interp, thisobj, s1p);
914 	    } else
915 		return j;
916 	}
917 }
918 
919 /**
920  * Sorts the array segment by partitioning, and then sorting the
921  * partitions. ("Quicksort", Cormen et al "Introduction to Algorithms").
922  */
923 static void
qs_sort(interp,thisobj,lo,hi,cmpfn,s1,s2)924 qs_sort(interp, thisobj, lo, hi, cmpfn, s1, s2)
925 	struct SEE_interpreter *interp;
926 	struct SEE_object *thisobj;
927 	SEE_uint32_t lo, hi;
928 	struct SEE_object *cmpfn;
929 	struct SEE_string **s1, **s2;
930 {
931 	SEE_uint32_t q;
932 
933 	if (lo < hi) {
934 	    q = qs_partition(interp, thisobj, lo, hi, cmpfn, s1, s2);
935 	    qs_sort(interp, thisobj, lo, q, cmpfn, s1, s2);
936 	    qs_sort(interp, thisobj, q + 1, hi, cmpfn, s1, s2);
937 	}
938 }
939 
940 /* 15.4.4.11 */
941 static void
array_proto_sort(interp,self,thisobj,argc,argv,res)942 array_proto_sort(interp, self, thisobj, argc, argv, res)
943 	struct SEE_interpreter *interp;
944 	struct SEE_object *self, *thisobj;
945 	int argc;
946 	struct SEE_value **argv, *res;
947 {
948 	struct SEE_string *s1 = NULL, *s2 = NULL;
949 	SEE_uint32_t length;
950 	struct SEE_value v;
951 	struct SEE_object *cmpfn;
952 
953 	if (!thisobj)
954 	    SEE_error_throw_string(interp, interp->TypeError,
955 	       STR(null_thisobj));
956 
957 	SEE_OBJECT_GET(interp, thisobj, STR(length), &v);
958 	length = SEE_ToUint32(interp, &v);
959 
960 	if (argc < 1 || SEE_VALUE_GET_TYPE(argv[0]) == SEE_UNDEFINED)
961 		cmpfn = NULL;
962 	else if (SEE_VALUE_GET_TYPE(argv[0]) == SEE_OBJECT &&
963 		 SEE_OBJECT_HAS_CALL(argv[0]->u.object))
964 		cmpfn = argv[0]->u.object;
965 	else
966 		SEE_error_throw_string(interp, interp->TypeError,
967 			STR(bad_arg));
968 
969 	qs_sort(interp, thisobj, 1, length, cmpfn, &s1, &s2);
970 	/*
971 	 * NOTE: the standard does not say that the length
972 	 * of the array should be updated after sorting.
973 	 * i.e., even as all the non-existent entries get moved
974 	 * to the end of the array, the length property will remain
975 	 * unchanged. This remains consistent with 15.4.5.2.
976 	 */
977 	SEE_SET_OBJECT(res, thisobj);
978 }
979 
980 /* 15.4.4.12 */
981 static void
array_proto_splice(interp,self,thisobj,argc,argv,res)982 array_proto_splice(interp, self, thisobj, argc, argv, res)
983 	struct SEE_interpreter *interp;
984 	struct SEE_object *self, *thisobj;
985 	int argc;
986 	struct SEE_value **argv, *res;
987 {
988 	struct SEE_value v;
989 	struct SEE_object *A;
990 	SEE_uint32_t r3, r5, r6, r17, k;
991 	struct SEE_string *s = NULL, *s9, *s11, *s22, *s33, *s39;
992 
993 	if (!thisobj)
994 	    SEE_error_throw_string(interp, interp->TypeError,
995 	       STR(null_thisobj));
996 
997 /*1*/	SEE_OBJECT_CONSTRUCT(interp, interp->Array, NULL, 0, NULL, &v);
998 	A = v.u.object;
999 /*2*/	SEE_OBJECT_GET(interp, thisobj, STR(length), &v);
1000 /*3*/	r3 = SEE_ToUint32(interp, &v);
1001 /*4*/	if (argc < 1) SEE_SET_NUMBER(&v, 0);
1002 	else SEE_ToInteger(interp, argv[0], &v);
1003 /*5*/	r5 = -v.u.number > r3 ? 0 :
1004 	      v.u.number < 0  ? (SEE_uint32_t)(r3 + v.u.number) :
1005 	      v.u.number < r3 ? (SEE_uint32_t)v.u.number :
1006 	      		        r3;
1007 /*6*/	if (argc < 2) SEE_SET_NUMBER(&v, 0);
1008 	else SEE_ToInteger(interp, argv[1], &v);
1009 	r6 = MIN(v.u.number < 0 ? 0 : (SEE_uint32_t)v.u.number, r3 - r5);
1010 /*7*/	for (k = 0; k < r6; k++) {
1011 /*9*/	    s9 = intstr(interp, &s, r5 + k);
1012 /*10*/	    if (SEE_OBJECT_HASPROPERTY(interp, thisobj, s9)) {
1013 /*12*/		SEE_OBJECT_GET(interp, thisobj, s9, &v);
1014 /*11*/		s11 = intstr(interp, &s, k);
1015 /*13*/		SEE_OBJECT_PUT(interp, A, s11, &v, 0);
1016 	    }
1017 	}
1018 /*16*/	SEE_SET_NUMBER(&v, r6); SEE_OBJECT_PUT(interp, A, STR(length), &v, 0);
1019 /*17*/	r17 = argc < 2 ? 0 : argc - 2;
1020 /*18*/	if (r17 != r6) {
1021 /*19*/	    if (r17 <= r6) {
1022 /*20*/		for (k = r5; k < r3 - r6; k++) {
1023 /*22*/		    s22 = intstr(interp, &s, k + r6);
1024 /*23*/		    if (SEE_OBJECT_HASPROPERTY(interp, thisobj, s22)) {
1025 /*25*/			SEE_OBJECT_GET(interp, thisobj, s22, &v);
1026 /*26*/			SEE_OBJECT_PUT(interp, thisobj,
1027 			    intstr(interp, &s, k + r17), &v, 0);
1028 		    } else {
1029 /*28*/			SEE_OBJECT_DELETE(interp, thisobj,
1030 			    intstr(interp, &s, k + r17));
1031 		    }
1032 		}
1033 /*31*/		for (k = r3; k > r3-r6+r17; k--) {
1034 /*33*/		    s33 = intstr(interp, &s, k - 1);
1035 /*34*/		    SEE_OBJECT_DELETE(interp, thisobj, s33);
1036 		}
1037 	    } else
1038 /*37*/		for (k = r3 - r6; k > r5; k--) {
1039 /*39*/		    s39 = intstr(interp, &s, k + r6 - 1);
1040 /*41*/		    if (SEE_OBJECT_HASPROPERTY(interp, thisobj, s39)) {
1041 /*43*/			SEE_OBJECT_GET(interp, thisobj, s39, &v);
1042 /*44*/			SEE_OBJECT_PUT(interp, thisobj,
1043 			    intstr(interp, &s, k + r17 - 1), &v, 0);
1044 		    } else {
1045 /*45*/			SEE_OBJECT_DELETE(interp, thisobj,
1046 			    intstr(interp, &s, k + r17 - 1));
1047 		    }
1048 		}
1049 	}
1050 /*48*/	for (k = 2; k < (unsigned int)argc; k++) {
1051 /*50*/	    SEE_OBJECT_PUT(interp, thisobj, intstr(interp, &s, k - 2 + r5),
1052 		argv[k], 0);
1053 	}
1054 /*53*/	SEE_SET_NUMBER(&v, r3-r6+r17);
1055 	SEE_OBJECT_PUT(interp, thisobj, STR(length), &v, 0);
1056 /*54*/	SEE_SET_OBJECT(res, A);
1057 }
1058 
1059 /* 15.4.4.13 */
1060 static void
array_proto_unshift(interp,self,thisobj,argc,argv,res)1061 array_proto_unshift(interp, self, thisobj, argc, argv, res)
1062 	struct SEE_interpreter *interp;
1063 	struct SEE_object *self, *thisobj;
1064 	int argc;
1065 	struct SEE_value **argv, *res;
1066 {
1067 	SEE_uint32_t r2, r3, k;
1068 	struct SEE_value v;
1069 	struct SEE_string *s = NULL, *p;
1070 
1071 	if (!thisobj)
1072 	    SEE_error_throw_string(interp, interp->TypeError,
1073 	       STR(null_thisobj));
1074 
1075 	SEE_OBJECT_GET(interp, thisobj, STR(length), &v);
1076 	r2 = SEE_ToUint32(interp, &v);
1077 	r3 = argc;
1078 	check_too_long(interp, r2, r3);
1079 	for (k = r2; k > 0; k--) {
1080 	    p = intstr(interp, &s, k - 1);
1081 	    if (SEE_OBJECT_HASPROPERTY(interp, thisobj, p)) {
1082 		SEE_OBJECT_GET(interp, thisobj, p, &v);
1083 		SEE_OBJECT_PUT(interp, thisobj,
1084 		    intstr(interp, &s, k + r3 - 1), &v, 0);
1085 	    } else {
1086 		SEE_OBJECT_DELETE(interp, thisobj,
1087 		    intstr(interp, &s, k + r3 - 1));
1088 	    }
1089 	}
1090 	for (k = 0; k < r3; k++) {
1091 	    SEE_OBJECT_PUT(interp, thisobj, intstr(interp, &s, k),
1092 	        argv[k], 0);
1093 	}
1094 	SEE_SET_NUMBER(res, r2 + r3);
1095 	SEE_OBJECT_PUT(interp, thisobj, STR(length), res, 0);
1096 }
1097 
1098 /*------------------------------------------------------------
1099  * Array methods
1100  */
1101 
1102 /*
1103  * Modify the length of the array.
1104  * NB: this can be slow if the length is suddenly set
1105  * from 4,294,967,295 to 0 (because deletes occur).
1106  */
1107 static void
array_setlength(interp,ao,val)1108 array_setlength(interp, ao, val)
1109 	struct SEE_interpreter *interp;
1110 	struct array_object *ao;
1111 	struct SEE_value *val;
1112 {
1113 	SEE_uint32_t i, newlen;
1114 	struct SEE_string *s;
1115 	struct name {
1116 		struct SEE_string *s;
1117 		struct name *next;
1118 	} *name, *names = NULL;
1119 	struct SEE_enum *e;
1120 	int flags;
1121 
1122 	newlen = SEE_ToUint32(interp, val);
1123 	if (ao->length > newlen) {
1124 	    e = SEE_OBJECT_ENUMERATOR(interp,
1125 	    	(struct SEE_object *)&ao->native);
1126 	    while ((s = SEE_ENUM_NEXT(interp, e, &flags)))
1127 		if (SEE_to_array_index(s, &i) && i >= newlen) {
1128 		    name = SEE_NEW(interp, struct name);
1129 		    name->s = s;
1130 		    name->next = names;
1131 		    names = name;
1132 		}
1133 	    for (name = names; name; name = name->next)
1134 	        SEE_native_delete(interp, (struct SEE_object *)&ao->native,
1135 		    name->s);
1136 	}
1137 	ao->length = newlen;
1138 }
1139 
1140 static void
array_get(interp,o,p,res)1141 array_get(interp, o, p, res)
1142 	struct SEE_interpreter *interp;
1143 	struct SEE_object *o;
1144 	struct SEE_string *p;
1145 	struct SEE_value *res;
1146 {
1147 	struct array_object *ao = (struct array_object *)o;
1148 
1149 	if (p == STR(length))
1150 	    SEE_SET_NUMBER(res, ao->length);
1151 	else
1152 	    SEE_native_get(interp, o, p, res);
1153 }
1154 
1155 static void
array_put(interp,o,p,val,attr)1156 array_put(interp, o, p, val, attr)
1157 	struct SEE_interpreter *interp;
1158 	struct SEE_object *o;
1159 	struct SEE_string *p;
1160 	struct SEE_value *val;
1161 	int attr;
1162 {
1163 	struct array_object *ao = (struct array_object *)o;
1164 	SEE_uint32_t i;
1165 
1166 	if (p == STR(length))
1167 	    array_setlength(interp, ao, val);
1168 	else {
1169 	    SEE_native_put(interp, o, p, val, attr);
1170 	    if (SEE_to_array_index(p, &i))
1171 		if (i >= ao->length)
1172 		    ao->length = i + 1;
1173 	}
1174 }
1175 
1176 static int
array_hasproperty(interp,o,p)1177 array_hasproperty(interp, o, p)
1178 	struct SEE_interpreter *interp;
1179 	struct SEE_object *o;
1180 	struct SEE_string *p;
1181 {
1182 	if (p == STR(length))
1183 	    return 1;
1184 	else
1185 	    return SEE_native_hasproperty(interp, o, p);
1186 }
1187 
1188 static int
array_delete(interp,o,p)1189 array_delete(interp, o, p)
1190 	struct SEE_interpreter *interp;
1191 	struct SEE_object *o;
1192 	struct SEE_string *p;
1193 {
1194 	if (p == STR(length))
1195 	    return 0;
1196 	else
1197 	    return SEE_native_delete(interp, o, p);
1198 }
1199