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