include: Add missing enum XHR_PROP_ values.
[wine.git] / dlls / jscript / array.c
blob341505a335c7e96b3d222e48777c4f11f12a6ef1
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <math.h>
21 #include <assert.h>
23 #include "jscript.h"
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
29 typedef struct {
30 jsdisp_t dispex;
32 DWORD length;
33 } ArrayInstance;
35 static inline ArrayInstance *array_from_jsdisp(jsdisp_t *jsdisp)
37 return CONTAINING_RECORD(jsdisp, ArrayInstance, dispex);
40 static inline ArrayInstance *array_this(jsval_t vthis)
42 jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL;
43 return (jsdisp && is_class(jsdisp, JSCLASS_ARRAY)) ? array_from_jsdisp(jsdisp) : NULL;
46 unsigned array_get_length(jsdisp_t *array)
48 assert(is_class(array, JSCLASS_ARRAY));
49 return array_from_jsdisp(array)->length;
52 static HRESULT get_length(script_ctx_t *ctx, jsval_t vthis, jsdisp_t **jsthis, UINT32 *ret)
54 jsdisp_t *jsdisp;
55 IDispatch *disp;
56 jsval_t val;
57 HRESULT hres;
59 hres = to_object(ctx, vthis, &disp);
60 if(FAILED(hres))
61 return hres;
63 jsdisp = iface_to_jsdisp(disp);
64 IDispatch_Release(disp);
65 if(!jsdisp)
66 return JS_E_JSCRIPT_EXPECTED;
67 *jsthis = jsdisp;
69 if(is_class(jsdisp, JSCLASS_ARRAY)) {
70 *ret = array_from_jsdisp(jsdisp)->length;
71 return S_OK;
74 hres = jsdisp_propget_name(jsdisp, L"length", &val);
75 if(SUCCEEDED(hres)) {
76 hres = to_uint32(ctx, val, ret);
77 jsval_release(val);
78 if(SUCCEEDED(hres))
79 return hres;
82 jsdisp_release(jsdisp);
83 return hres;
86 static HRESULT set_length(jsdisp_t *obj, DWORD length)
88 if(is_class(obj, JSCLASS_ARRAY)) {
89 array_from_jsdisp(obj)->length = length;
90 return S_OK;
93 return jsdisp_propput_name(obj, L"length", jsval_number(length));
96 WCHAR *idx_to_str(DWORD idx, WCHAR *ptr)
98 if(!idx) {
99 *ptr = '0';
100 return ptr;
103 while(idx) {
104 *ptr-- = '0' + (idx%10);
105 idx /= 10;
108 return ptr+1;
111 static HRESULT Array_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
113 TRACE("%p\n", jsthis);
115 *r = jsval_number(array_from_jsdisp(jsthis)->length);
116 return S_OK;
119 static HRESULT Array_set_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
121 ArrayInstance *This = array_from_jsdisp(jsthis);
122 DOUBLE len = -1;
123 DWORD i;
124 HRESULT hres;
126 TRACE("%p %ld\n", This, This->length);
128 hres = to_number(ctx, value, &len);
129 if(FAILED(hres))
130 return hres;
132 len = floor(len);
133 if(len!=(DWORD)len)
134 return JS_E_INVALID_LENGTH;
136 for(i=len; i < This->length; i++) {
137 hres = jsdisp_delete_idx(&This->dispex, i);
138 if(FAILED(hres))
139 return hres;
142 This->length = len;
143 return S_OK;
146 static HRESULT concat_array(jsdisp_t *array, ArrayInstance *obj, DWORD *len)
148 jsval_t val;
149 DWORD i;
150 HRESULT hres;
152 for(i=0; i < obj->length; i++) {
153 hres = jsdisp_get_idx(&obj->dispex, i, &val);
154 if(hres == DISP_E_UNKNOWNNAME)
155 continue;
156 if(FAILED(hres))
157 return hres;
159 hres = jsdisp_propput_idx(array, *len+i, val);
160 jsval_release(val);
161 if(FAILED(hres))
162 return hres;
165 *len += obj->length;
166 return S_OK;
169 static HRESULT concat_obj(jsdisp_t *array, IDispatch *obj, DWORD *len)
171 jsdisp_t *jsobj;
172 HRESULT hres;
174 jsobj = iface_to_jsdisp(obj);
175 if(jsobj) {
176 if(is_class(jsobj, JSCLASS_ARRAY)) {
177 hres = concat_array(array, array_from_jsdisp(jsobj), len);
178 jsdisp_release(jsobj);
179 return hres;
181 jsdisp_release(jsobj);
184 return jsdisp_propput_idx(array, (*len)++, jsval_disp(obj));
187 static HRESULT Array_concat(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
188 jsval_t *r)
190 IDispatch *jsthis;
191 jsdisp_t *ret;
192 DWORD len = 0;
193 HRESULT hres;
195 TRACE("\n");
197 hres = to_object(ctx, vthis, &jsthis);
198 if(FAILED(hres))
199 return hres;
201 hres = create_array(ctx, 0, &ret);
202 if(FAILED(hres))
203 goto done;
205 hres = concat_obj(ret, jsthis, &len);
206 if(SUCCEEDED(hres)) {
207 DWORD i;
209 for(i=0; i < argc; i++) {
210 if(is_object_instance(argv[i]))
211 hres = concat_obj(ret, get_object(argv[i]), &len);
212 else
213 hres = jsdisp_propput_idx(ret, len++, argv[i]);
214 if(FAILED(hres))
215 break;
219 if(FAILED(hres))
220 goto done;
222 if(r)
223 *r = jsval_obj(ret);
224 else
225 jsdisp_release(ret);
226 done:
227 IDispatch_Release(jsthis);
228 return S_OK;
231 static HRESULT array_join(script_ctx_t *ctx, jsdisp_t *array, DWORD length, const WCHAR *sep,
232 unsigned seplen, HRESULT (*to_string)(script_ctx_t*,jsval_t,jsstr_t**), jsval_t *r)
234 jsstr_t **str_tab, *ret = NULL;
235 jsval_t val;
236 DWORD i;
237 HRESULT hres = E_FAIL;
239 if(!length) {
240 if(r)
241 *r = jsval_string(jsstr_empty());
242 return S_OK;
245 str_tab = calloc(length, sizeof(*str_tab));
246 if(!str_tab)
247 return E_OUTOFMEMORY;
249 for(i=0; i < length; i++) {
250 hres = jsdisp_get_idx(array, i, &val);
251 if(hres == DISP_E_UNKNOWNNAME) {
252 hres = S_OK;
253 continue;
254 } else if(FAILED(hres))
255 break;
257 if(!is_undefined(val) && !is_null(val)) {
258 hres = to_string(ctx, val, str_tab+i);
259 jsval_release(val);
260 if(FAILED(hres))
261 break;
265 if(SUCCEEDED(hres)) {
266 DWORD len = 0;
268 if(str_tab[0])
269 len = jsstr_length(str_tab[0]);
270 for(i=1; i < length; i++) {
271 len += seplen;
272 if(str_tab[i])
273 len += jsstr_length(str_tab[i]);
274 if(len > JSSTR_MAX_LENGTH) {
275 hres = E_OUTOFMEMORY;
276 break;
280 if(SUCCEEDED(hres)) {
281 WCHAR *ptr = NULL;
283 ret = jsstr_alloc_buf(len, &ptr);
284 if(ret) {
285 if(str_tab[0])
286 ptr += jsstr_flush(str_tab[0], ptr);
288 for(i=1; i < length; i++) {
289 if(seplen) {
290 memcpy(ptr, sep, seplen*sizeof(WCHAR));
291 ptr += seplen;
294 if(str_tab[i])
295 ptr += jsstr_flush(str_tab[i], ptr);
297 }else {
298 hres = E_OUTOFMEMORY;
303 for(i=0; i < length; i++) {
304 if(str_tab[i])
305 jsstr_release(str_tab[i]);
307 free(str_tab);
308 if(FAILED(hres))
309 return hres;
311 TRACE("= %s\n", debugstr_jsstr(ret));
313 if(r)
314 *r = jsval_string(ret);
315 else
316 jsstr_release(ret);
317 return S_OK;
320 /* ECMA-262 3rd Edition 15.4.4.5 */
321 static HRESULT Array_join(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
322 jsval_t *r)
324 jsdisp_t *jsthis;
325 UINT32 length;
326 HRESULT hres;
328 TRACE("\n");
330 hres = get_length(ctx, vthis, &jsthis, &length);
331 if(FAILED(hres))
332 return hres;
334 if(argc) {
335 const WCHAR *sep;
336 jsstr_t *sep_str;
338 hres = to_flat_string(ctx, argv[0], &sep_str, &sep);
339 if(FAILED(hres))
340 goto done;
342 hres = array_join(ctx, jsthis, length, sep, jsstr_length(sep_str), to_string, r);
344 jsstr_release(sep_str);
345 }else {
346 hres = array_join(ctx, jsthis, length, L",", 1, to_string, r);
349 done:
350 jsdisp_release(jsthis);
351 return hres;
354 static HRESULT Array_pop(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
355 jsval_t *r)
357 jsdisp_t *jsthis;
358 jsval_t val;
359 UINT32 length;
360 HRESULT hres;
362 TRACE("\n");
364 hres = get_length(ctx, vthis, &jsthis, &length);
365 if(FAILED(hres))
366 return hres;
368 if(!length) {
369 hres = set_length(jsthis, 0);
370 if(FAILED(hres))
371 goto done;
373 if(r)
374 *r = jsval_undefined();
375 goto done;
378 length--;
379 hres = jsdisp_get_idx(jsthis, length, &val);
380 if(SUCCEEDED(hres))
381 hres = jsdisp_delete_idx(jsthis, length);
382 else if(hres == DISP_E_UNKNOWNNAME) {
383 val = jsval_undefined();
384 hres = S_OK;
385 }else
386 goto done;
388 if(SUCCEEDED(hres))
389 hres = set_length(jsthis, length);
391 if(FAILED(hres)) {
392 jsval_release(val);
393 goto done;
396 if(r)
397 *r = val;
398 else
399 jsval_release(val);
400 done:
401 jsdisp_release(jsthis);
402 return hres;
405 /* ECMA-262 3rd Edition 15.4.4.7 */
406 static HRESULT Array_push(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
407 jsval_t *r)
409 jsdisp_t *jsthis;
410 UINT32 length = 0;
411 unsigned i;
412 HRESULT hres;
414 TRACE("\n");
416 hres = get_length(ctx, vthis, &jsthis, &length);
417 if(FAILED(hres))
418 return hres;
420 for(i=0; i < argc; i++) {
421 hres = jsdisp_propput_idx(jsthis, length+i, argv[i]);
422 if(FAILED(hres))
423 goto done;
426 hres = set_length(jsthis, length+argc);
427 if(FAILED(hres))
428 goto done;
430 if(r)
431 *r = jsval_number(length+argc);
432 done:
433 jsdisp_release(jsthis);
434 return hres;
437 static HRESULT Array_reverse(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
438 jsval_t *r)
440 jsdisp_t *jsthis;
441 UINT32 length, k, l;
442 jsval_t v1, v2;
443 HRESULT hres1, hres2;
445 TRACE("\n");
447 hres1 = get_length(ctx, vthis, &jsthis, &length);
448 if(FAILED(hres1))
449 return hres1;
451 for(k=0; k<length/2; k++) {
452 l = length-k-1;
454 hres1 = jsdisp_get_idx(jsthis, k, &v1);
455 if(FAILED(hres1) && hres1!=DISP_E_UNKNOWNNAME)
456 goto done;
458 hres2 = jsdisp_get_idx(jsthis, l, &v2);
459 if(FAILED(hres2) && hres2!=DISP_E_UNKNOWNNAME) {
460 jsval_release(v1);
461 hres1 = hres2;
462 goto done;
465 if(hres1 == DISP_E_UNKNOWNNAME)
466 hres1 = jsdisp_delete_idx(jsthis, l);
467 else
468 hres1 = jsdisp_propput_idx(jsthis, l, v1);
470 if(FAILED(hres1)) {
471 jsval_release(v1);
472 jsval_release(v2);
473 goto done;
476 if(hres2 == DISP_E_UNKNOWNNAME)
477 hres2 = jsdisp_delete_idx(jsthis, k);
478 else
479 hres2 = jsdisp_propput_idx(jsthis, k, v2);
481 if(FAILED(hres2)) {
482 jsval_release(v2);
483 hres1 = hres2;
484 goto done;
488 if(r)
489 *r = jsval_obj(jsdisp_addref(jsthis));
490 done:
491 jsdisp_release(jsthis);
492 return hres1;
495 /* ECMA-262 3rd Edition 15.4.4.9 */
496 static HRESULT Array_shift(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
497 jsval_t *r)
499 jsdisp_t *jsthis;
500 UINT32 length = 0, i;
501 jsval_t v, ret;
502 HRESULT hres;
504 TRACE("\n");
506 hres = get_length(ctx, vthis, &jsthis, &length);
507 if(FAILED(hres))
508 return hres;
510 if(!length) {
511 hres = set_length(jsthis, 0);
512 if(FAILED(hres))
513 goto done;
515 if(r)
516 *r = jsval_undefined();
517 goto done;
520 hres = jsdisp_get_idx(jsthis, 0, &ret);
521 if(hres == DISP_E_UNKNOWNNAME) {
522 ret = jsval_undefined();
523 hres = S_OK;
526 for(i=1; SUCCEEDED(hres) && i<length; i++) {
527 hres = jsdisp_get_idx(jsthis, i, &v);
528 if(hres == DISP_E_UNKNOWNNAME)
529 hres = jsdisp_delete_idx(jsthis, i-1);
530 else if(SUCCEEDED(hres))
531 hres = jsdisp_propput_idx(jsthis, i-1, v);
534 if(SUCCEEDED(hres)) {
535 hres = jsdisp_delete_idx(jsthis, length-1);
536 if(SUCCEEDED(hres))
537 hres = set_length(jsthis, length-1);
540 if(FAILED(hres))
541 goto done;
543 if(r)
544 *r = ret;
545 else
546 jsval_release(ret);
547 done:
548 jsdisp_release(jsthis);
549 return hres;
552 /* ECMA-262 3rd Edition 15.4.4.10 */
553 static HRESULT Array_slice(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
555 jsdisp_t *arr, *jsthis;
556 DOUBLE range;
557 UINT32 length, start, end, idx;
558 HRESULT hres;
560 TRACE("\n");
562 hres = get_length(ctx, vthis, &jsthis, &length);
563 if(FAILED(hres))
564 return hres;
566 if(argc) {
567 hres = to_number(ctx, argv[0], &range);
568 if(FAILED(hres))
569 goto done;
571 range = floor(range);
572 if(-range>length || isnan(range)) start = 0;
573 else if(range < 0) start = range+length;
574 else if(range <= length) start = range;
575 else start = length;
577 else start = 0;
579 if(argc > 1) {
580 hres = to_number(ctx, argv[1], &range);
581 if(FAILED(hres))
582 goto done;
584 range = floor(range);
585 if(-range>length) end = 0;
586 else if(range < 0) end = range+length;
587 else if(range <= length) end = range;
588 else end = length;
590 else end = length;
592 hres = create_array(ctx, (end>start)?end-start:0, &arr);
593 if(FAILED(hres))
594 goto done;
596 for(idx=start; idx<end; idx++) {
597 jsval_t v;
599 hres = jsdisp_get_idx(jsthis, idx, &v);
600 if(hres == DISP_E_UNKNOWNNAME)
601 continue;
603 if(SUCCEEDED(hres)) {
604 hres = jsdisp_propput_idx(arr, idx-start, v);
605 jsval_release(v);
608 if(FAILED(hres)) {
609 jsdisp_release(arr);
610 goto done;
614 if(r)
615 *r = jsval_obj(arr);
616 else
617 jsdisp_release(arr);
618 hres = S_OK;
620 done:
621 jsdisp_release(jsthis);
622 return hres;
625 static HRESULT sort_cmp(script_ctx_t *ctx, jsdisp_t *cmp_func, jsval_t v1, jsval_t v2, INT *cmp)
627 HRESULT hres;
629 if(cmp_func) {
630 jsval_t args[2] = {v1, v2};
631 jsval_t res;
632 double n;
634 hres = jsdisp_call_value(cmp_func, jsval_undefined(), DISPATCH_METHOD, 2, args, &res);
635 if(FAILED(hres))
636 return hres;
638 hres = to_number(ctx, res, &n);
639 jsval_release(res);
640 if(FAILED(hres))
641 return hres;
643 if(n == 0)
644 *cmp = 0;
645 *cmp = n > 0.0 ? 1 : -1;
646 }else if(is_undefined(v1)) {
647 *cmp = is_undefined(v2) ? 0 : 1;
648 }else if(is_undefined(v2)) {
649 *cmp = -1;
650 }else if(is_number(v1) && is_number(v2)) {
651 double d = get_number(v1)-get_number(v2);
652 if(d > 0.0)
653 *cmp = 1;
654 else
655 *cmp = d < -0.0 ? -1 : 0;
656 }else {
657 jsstr_t *x, *y;
659 hres = to_string(ctx, v1, &x);
660 if(FAILED(hres))
661 return hres;
663 hres = to_string(ctx, v2, &y);
664 if(SUCCEEDED(hres)) {
665 *cmp = jsstr_cmp(x, y);
666 jsstr_release(y);
668 jsstr_release(x);
669 if(FAILED(hres))
670 return hres;
673 return S_OK;
676 /* ECMA-262 3rd Edition 15.4.4.11 */
677 static HRESULT Array_sort(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
678 jsval_t *r)
680 jsdisp_t *jsthis, *cmp_func = NULL;
681 jsval_t *vtab, **sorttab = NULL;
682 UINT32 length;
683 DWORD i;
684 HRESULT hres = S_OK;
686 TRACE("\n");
688 hres = get_length(ctx, vthis, &jsthis, &length);
689 if(FAILED(hres))
690 return hres;
692 if(argc >= 1) {
693 if(is_object_instance(argv[0])) {
694 if(argc > 1 && ctx->version < SCRIPTLANGUAGEVERSION_ES5) {
695 WARN("invalid arg_cnt %d\n", argc);
696 hres = JS_E_JSCRIPT_EXPECTED;
697 goto done;
699 cmp_func = iface_to_jsdisp(get_object(argv[0]));
700 if(!cmp_func || !is_class(cmp_func, JSCLASS_FUNCTION)) {
701 WARN("cmp_func is not a function\n");
702 if(cmp_func)
703 jsdisp_release(cmp_func);
704 hres = JS_E_JSCRIPT_EXPECTED;
705 goto done;
707 }else if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5 ? !is_undefined(argv[0]) :
708 (!is_null(argv[0]) || is_null_disp(argv[0]))) {
709 WARN("invalid arg %s\n", debugstr_jsval(argv[0]));
710 hres = JS_E_JSCRIPT_EXPECTED;
711 goto done;
715 if(!length) {
716 if(cmp_func)
717 jsdisp_release(cmp_func);
718 if(r)
719 *r = jsval_obj(jsdisp_addref(jsthis));
720 goto done;
723 vtab = calloc(length, sizeof(*vtab));
724 if(vtab) {
725 for(i=0; i<length; i++) {
726 hres = jsdisp_get_idx(jsthis, i, vtab+i);
727 if(hres == DISP_E_UNKNOWNNAME) {
728 vtab[i] = jsval_undefined();
729 hres = S_OK;
730 } else if(FAILED(hres)) {
731 WARN("Could not get elem %ld: %08lx\n", i, hres);
732 break;
735 }else {
736 hres = E_OUTOFMEMORY;
739 if(SUCCEEDED(hres)) {
740 sorttab = malloc(length*2*sizeof(*sorttab));
741 if(!sorttab)
742 hres = E_OUTOFMEMORY;
745 /* merge-sort */
746 if(SUCCEEDED(hres)) {
747 jsval_t *tmpv, **tmpbuf;
748 INT cmp;
750 tmpbuf = sorttab + length;
751 for(i=0; i < length; i++)
752 sorttab[i] = vtab+i;
754 for(i=0; i < length/2; i++) {
755 hres = sort_cmp(ctx, cmp_func, *sorttab[2*i+1], *sorttab[2*i], &cmp);
756 if(FAILED(hres))
757 break;
759 if(cmp < 0) {
760 tmpv = sorttab[2*i];
761 sorttab[2*i] = sorttab[2*i+1];
762 sorttab[2*i+1] = tmpv;
766 if(SUCCEEDED(hres)) {
767 DWORD k, a, b, bend;
769 for(k=2; k < length; k *= 2) {
770 for(i=0; i+k < length; i += 2*k) {
771 a = b = 0;
772 if(i+2*k <= length)
773 bend = k;
774 else
775 bend = length - (i+k);
777 memcpy(tmpbuf, sorttab+i, k*sizeof(jsval_t*));
779 while(a < k && b < bend) {
780 hres = sort_cmp(ctx, cmp_func, *tmpbuf[a], *sorttab[i+k+b], &cmp);
781 if(FAILED(hres))
782 break;
784 if(cmp < 0) {
785 sorttab[i+a+b] = tmpbuf[a];
786 a++;
787 }else {
788 sorttab[i+a+b] = sorttab[i+k+b];
789 b++;
793 if(FAILED(hres))
794 break;
796 if(a < k)
797 memcpy(sorttab+i+a+b, tmpbuf+a, (k-a)*sizeof(jsval_t*));
800 if(FAILED(hres))
801 break;
805 for(i=0; SUCCEEDED(hres) && i < length; i++)
806 hres = jsdisp_propput_idx(jsthis, i, *sorttab[i]);
809 if(vtab) {
810 for(i=0; i < length; i++)
811 jsval_release(vtab[i]);
812 free(vtab);
814 free(sorttab);
815 if(cmp_func)
816 jsdisp_release(cmp_func);
818 if(FAILED(hres))
819 goto done;
821 if(r)
822 *r = jsval_obj(jsdisp_addref(jsthis));
823 done:
824 jsdisp_release(jsthis);
825 return hres;
828 /* ECMA-262 3rd Edition 15.4.4.12 */
829 static HRESULT Array_splice(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
830 jsval_t *r)
832 UINT32 length, start=0, delete_cnt=0, i, add_args = 0;
833 jsdisp_t *ret_array = NULL, *jsthis;
834 jsval_t val;
835 double d;
836 int n;
837 HRESULT hres = S_OK;
839 TRACE("\n");
841 hres = get_length(ctx, vthis, &jsthis, &length);
842 if(FAILED(hres))
843 return hres;
845 if(argc) {
846 hres = to_integer(ctx, argv[0], &d);
847 if(FAILED(hres))
848 goto done;
850 if(is_int32(d)) {
851 if((n = d) >= 0)
852 start = min(n, length);
853 else
854 start = -n > length ? 0 : length + n;
855 }else {
856 start = d < 0.0 ? 0 : length;
860 if(argc >= 2) {
861 hres = to_integer(ctx, argv[1], &d);
862 if(FAILED(hres))
863 goto done;
865 if(is_int32(d)) {
866 if((n = d) > 0)
867 delete_cnt = min(n, length-start);
868 }else if(d > 0.0) {
869 delete_cnt = length-start;
872 add_args = argc-2;
875 if(r) {
876 hres = create_array(ctx, 0, &ret_array);
877 if(FAILED(hres))
878 goto done;
880 for(i=0; SUCCEEDED(hres) && i < delete_cnt; i++) {
881 hres = jsdisp_get_idx(jsthis, start+i, &val);
882 if(hres == DISP_E_UNKNOWNNAME) {
883 hres = S_OK;
884 }else if(SUCCEEDED(hres)) {
885 hres = jsdisp_propput_idx(ret_array, i, val);
886 jsval_release(val);
890 if(SUCCEEDED(hres))
891 hres = jsdisp_propput_name(ret_array, L"length", jsval_number(delete_cnt));
894 if(add_args < delete_cnt) {
895 for(i = start; SUCCEEDED(hres) && i < length-delete_cnt; i++) {
896 hres = jsdisp_get_idx(jsthis, i+delete_cnt, &val);
897 if(hres == DISP_E_UNKNOWNNAME) {
898 hres = jsdisp_delete_idx(jsthis, i+add_args);
899 }else if(SUCCEEDED(hres)) {
900 hres = jsdisp_propput_idx(jsthis, i+add_args, val);
901 jsval_release(val);
905 for(i=length; SUCCEEDED(hres) && i != length-delete_cnt+add_args; i--)
906 hres = jsdisp_delete_idx(jsthis, i-1);
907 }else if(add_args > delete_cnt) {
908 for(i=length-delete_cnt; SUCCEEDED(hres) && i != start; i--) {
909 hres = jsdisp_get_idx(jsthis, i+delete_cnt-1, &val);
910 if(hres == DISP_E_UNKNOWNNAME) {
911 hres = jsdisp_delete_idx(jsthis, i+add_args-1);
912 }else if(SUCCEEDED(hres)) {
913 hres = jsdisp_propput_idx(jsthis, i+add_args-1, val);
914 jsval_release(val);
919 for(i=0; SUCCEEDED(hres) && i < add_args; i++)
920 hres = jsdisp_propput_idx(jsthis, start+i, argv[i+2]);
922 if(SUCCEEDED(hres))
923 hres = jsdisp_propput_name(jsthis, L"length", jsval_number(length-delete_cnt+add_args));
925 if(FAILED(hres)) {
926 if(ret_array)
927 jsdisp_release(ret_array);
928 goto done;
931 if(r)
932 *r = jsval_obj(ret_array);
933 done:
934 jsdisp_release(jsthis);
935 return hres;
938 /* ECMA-262 3rd Edition 15.4.4.2 */
939 static HRESULT Array_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
940 jsval_t *r)
942 ArrayInstance *array;
944 TRACE("\n");
946 array = array_this(vthis);
947 if(!array)
948 return JS_E_ARRAY_EXPECTED;
950 return array_join(ctx, &array->dispex, array->length, L",", 1, to_string, r);
953 static HRESULT to_locale_string(script_ctx_t *ctx, jsval_t val, jsstr_t **str)
955 jsdisp_t *jsdisp;
956 IDispatch *obj;
957 HRESULT hres;
959 switch(jsval_type(val)) {
960 case JSV_OBJECT:
961 hres = disp_call_name(ctx, get_object(val), L"toLocaleString", DISPATCH_METHOD, 0, NULL, &val);
962 if(FAILED(hres)) {
963 if(hres == JS_E_INVALID_PROPERTY && ctx->version >= SCRIPTLANGUAGEVERSION_ES5)
964 hres = JS_E_FUNCTION_EXPECTED;
965 return hres;
967 break;
968 case JSV_NUMBER:
969 if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5)
970 return localize_number(ctx, get_number(val), FALSE, str);
971 /* fall through */
972 default:
973 if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5)
974 break;
976 hres = to_object(ctx, val, &obj);
977 if(FAILED(hres))
978 return hres;
980 jsdisp = as_jsdisp(obj);
981 hres = jsdisp_call_name(jsdisp, L"toLocaleString", DISPATCH_METHOD, 0, NULL, &val);
982 jsdisp_release(jsdisp);
983 if(FAILED(hres))
984 return hres;
985 break;
988 return to_string(ctx, val, str);
991 static HRESULT Array_toLocaleString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
992 jsval_t *r)
994 jsdisp_t *jsthis;
995 UINT32 length;
996 HRESULT hres;
997 WCHAR buf[5];
998 int len;
1000 TRACE("\n");
1002 if(ctx->version < SCRIPTLANGUAGEVERSION_ES5) {
1003 ArrayInstance *array = array_this(vthis);
1004 if(!array)
1005 return JS_E_ARRAY_EXPECTED;
1006 jsthis = jsdisp_addref(&array->dispex);
1007 length = array->length;
1008 }else {
1009 hres = get_length(ctx, vthis, &jsthis, &length);
1010 if(FAILED(hres))
1011 return hres;
1014 if(!(len = GetLocaleInfoW(ctx->lcid, LOCALE_SLIST, buf, ARRAY_SIZE(buf) - 1))) {
1015 buf[len++] = ',';
1016 len++;
1018 buf[len - 1] = ' ';
1019 buf[len] = '\0';
1021 hres = array_join(ctx, jsthis, length, buf, len, to_locale_string, r);
1022 jsdisp_release(jsthis);
1023 return hres;
1026 static HRESULT Array_every(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1027 jsval_t *r)
1029 jsval_t context_this = jsval_undefined();
1030 jsval_t value, args[3], res;
1031 BOOL boolval, ret = TRUE;
1032 IDispatch *callback;
1033 unsigned length, i;
1034 jsdisp_t *jsthis;
1035 HRESULT hres;
1037 TRACE("\n");
1039 hres = get_length(ctx, vthis, &jsthis, &length);
1040 if(FAILED(hres))
1041 return hres;
1043 /* FIXME: check IsCallable */
1044 if(!argc || !is_object_instance(argv[0])) {
1045 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
1046 hres = E_INVALIDARG;
1047 goto done;
1049 callback = get_object(argv[0]);
1051 if(argc > 1)
1052 context_this = argv[1];
1054 for(i = 0; i < length; i++) {
1055 hres = jsdisp_get_idx(jsthis, i, &value);
1056 if(FAILED(hres)) {
1057 if(hres == DISP_E_UNKNOWNNAME)
1058 continue;
1059 goto done;
1061 args[0] = value;
1062 args[1] = jsval_number(i);
1063 args[2] = jsval_obj(jsthis);
1064 hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res);
1065 jsval_release(value);
1066 if(FAILED(hres))
1067 goto done;
1069 hres = to_boolean(res, &boolval);
1070 jsval_release(res);
1071 if(FAILED(hres))
1072 goto done;
1073 if(!boolval) {
1074 ret = FALSE;
1075 break;
1079 if(r)
1080 *r = jsval_bool(ret);
1081 hres = S_OK;
1082 done:
1083 jsdisp_release(jsthis);
1084 return hres;
1087 static HRESULT Array_filter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1088 jsval_t *r)
1090 jsval_t context_this = jsval_undefined();
1091 jsval_t value, args[3], res;
1092 unsigned length, i, j = 0;
1093 jsdisp_t *jsthis, *arr;
1094 IDispatch *callback;
1095 HRESULT hres;
1096 BOOL boolval;
1098 TRACE("\n");
1100 hres = get_length(ctx, vthis, &jsthis, &length);
1101 if(FAILED(hres))
1102 return hres;
1104 /* FIXME: check IsCallable */
1105 if(!argc || !is_object_instance(argv[0])) {
1106 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
1107 hres = E_INVALIDARG;
1108 goto done;
1110 callback = get_object(argv[0]);
1112 if(argc > 1)
1113 context_this = argv[1];
1115 hres = create_array(ctx, 0, &arr);
1116 if(FAILED(hres))
1117 goto done;
1119 for(i = 0; i < length; i++) {
1120 hres = jsdisp_get_idx(jsthis, i, &value);
1121 if(FAILED(hres)) {
1122 if(hres == DISP_E_UNKNOWNNAME) {
1123 hres = S_OK;
1124 continue;
1126 break;
1128 args[0] = value;
1129 args[1] = jsval_number(i);
1130 args[2] = jsval_obj(jsthis);
1131 hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res);
1132 if(SUCCEEDED(hres)) {
1133 hres = to_boolean(res, &boolval);
1134 jsval_release(res);
1135 if(SUCCEEDED(hres) && boolval)
1136 hres = jsdisp_propput_idx(arr, j++, value);
1138 jsval_release(value);
1139 if(FAILED(hres))
1140 break;
1143 if(FAILED(hres)) {
1144 jsdisp_release(arr);
1145 goto done;
1147 set_length(arr, j);
1149 if(r)
1150 *r = jsval_obj(arr);
1151 done:
1152 jsdisp_release(jsthis);
1153 return hres;
1156 static HRESULT Array_forEach(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1157 jsval_t *r)
1159 jsval_t context_this = jsval_undefined();
1160 jsval_t value, args[3], res;
1161 IDispatch *callback;
1162 jsdisp_t *jsthis;
1163 unsigned length, i;
1164 HRESULT hres;
1166 TRACE("\n");
1168 hres = get_length(ctx, vthis, &jsthis, &length);
1169 if(FAILED(hres))
1170 return hres;
1172 /* Fixme check IsCallable */
1173 if(!argc || !is_object_instance(argv[0])) {
1174 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
1175 hres = E_INVALIDARG;
1176 goto done;
1178 callback = get_object(argv[0]);
1180 if(argc > 1)
1181 context_this = argv[1];
1183 for(i = 0; i < length; i++) {
1184 hres = jsdisp_get_idx(jsthis, i, &value);
1185 if(hres == DISP_E_UNKNOWNNAME)
1186 continue;
1187 if(FAILED(hres))
1188 goto done;
1190 args[0] = value;
1191 args[1] = jsval_number(i);
1192 args[2] = jsval_obj(jsthis);
1193 hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res);
1194 jsval_release(value);
1195 if(FAILED(hres))
1196 goto done;
1197 jsval_release(res);
1200 if(r) *r = jsval_undefined();
1201 hres = S_OK;
1202 done:
1203 jsdisp_release(jsthis);
1204 return hres;
1207 static HRESULT Array_indexOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1208 jsval_t *r)
1210 jsdisp_t *jsthis;
1211 unsigned length, i, from = 0;
1212 jsval_t search, value;
1213 BOOL eq;
1214 HRESULT hres;
1216 TRACE("\n");
1218 hres = get_length(ctx, vthis, &jsthis, &length);
1219 if(FAILED(hres))
1220 return hres;
1221 if(!length) {
1222 if(r) *r = jsval_number(-1);
1223 goto done;
1226 search = argc ? argv[0] : jsval_undefined();
1228 if(argc > 1) {
1229 double from_arg;
1231 hres = to_integer(ctx, argv[1], &from_arg);
1232 if(FAILED(hres))
1233 goto done;
1235 if(from_arg >= 0)
1236 from = min(from_arg, length);
1237 else
1238 from = max(from_arg + length, 0);
1241 for(i = from; i < length; i++) {
1242 hres = jsdisp_get_idx(jsthis, i, &value);
1243 if(hres == DISP_E_UNKNOWNNAME)
1244 continue;
1245 if(FAILED(hres))
1246 goto done;
1248 hres = jsval_strict_equal(value, search, &eq);
1249 jsval_release(value);
1250 if(FAILED(hres))
1251 goto done;
1252 if(eq) {
1253 if(r) *r = jsval_number(i);
1254 goto done;
1258 if(r) *r = jsval_number(-1);
1259 hres = S_OK;
1260 done:
1261 jsdisp_release(jsthis);
1262 return hres;
1265 static HRESULT Array_lastIndexOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1266 jsval_t *r)
1268 jsval_t search, value;
1269 unsigned i, length;
1270 jsdisp_t *jsthis;
1271 HRESULT hres;
1272 BOOL eq;
1274 TRACE("\n");
1276 hres = get_length(ctx, vthis, &jsthis, &length);
1277 if(FAILED(hres))
1278 return hres;
1279 if(!length)
1280 goto notfound;
1282 search = argc ? argv[0] : jsval_undefined();
1284 i = length - 1;
1285 if(argc > 1) {
1286 double from_arg;
1288 hres = to_integer(ctx, argv[1], &from_arg);
1289 if(FAILED(hres))
1290 goto done;
1292 if(from_arg >= 0.0)
1293 i = min(from_arg, i);
1294 else {
1295 from_arg += length;
1296 if(from_arg < 0.0)
1297 goto notfound;
1298 i = from_arg;
1302 do {
1303 hres = jsdisp_get_idx(jsthis, i, &value);
1304 if(hres == DISP_E_UNKNOWNNAME)
1305 continue;
1306 if(FAILED(hres))
1307 goto done;
1309 hres = jsval_strict_equal(value, search, &eq);
1310 jsval_release(value);
1311 if(FAILED(hres))
1312 goto done;
1313 if(eq) {
1314 if(r) *r = jsval_number(i);
1315 goto done;
1317 } while(i--);
1319 notfound:
1320 if(r) *r = jsval_number(-1);
1321 hres = S_OK;
1322 done:
1323 jsdisp_release(jsthis);
1324 return hres;
1327 static HRESULT Array_map(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1329 jsval_t context_this = jsval_undefined();
1330 jsval_t callback_args[3], mapped_value;
1331 jsdisp_t *jsthis, *array;
1332 IDispatch *callback;
1333 UINT32 length, k;
1334 HRESULT hres;
1336 TRACE("\n");
1338 hres = get_length(ctx, vthis, &jsthis, &length);
1339 if(FAILED(hres)) {
1340 FIXME("Could not get length\n");
1341 return hres;
1344 /* FIXME: check IsCallable */
1345 if(!argc || !is_object_instance(argv[0])) {
1346 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
1347 hres = E_INVALIDARG;
1348 goto done;
1350 callback = get_object(argv[0]);
1352 if(argc > 1)
1353 context_this = argv[1];
1355 hres = create_array(ctx, length, &array);
1356 if(FAILED(hres))
1357 goto done;
1359 for(k = 0; k < length; k++) {
1360 hres = jsdisp_get_idx(jsthis, k, &callback_args[0]);
1361 if(hres == DISP_E_UNKNOWNNAME)
1362 continue;
1363 if(FAILED(hres))
1364 break;
1366 callback_args[1] = jsval_number(k);
1367 callback_args[2] = jsval_obj(jsthis);
1368 hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, 3, callback_args, &mapped_value);
1369 jsval_release(callback_args[0]);
1370 if(FAILED(hres))
1371 break;
1373 hres = jsdisp_propput_idx(array, k, mapped_value);
1374 if(FAILED(hres))
1375 break;
1378 if(SUCCEEDED(hres) && r)
1379 *r = jsval_obj(array);
1380 else
1381 jsdisp_release(array);
1382 done:
1383 jsdisp_release(jsthis);
1384 return hres;
1387 static HRESULT Array_reduce(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1389 jsval_t callback_args[4], acc, new_acc;
1390 BOOL have_value = FALSE;
1391 IDispatch *callback;
1392 jsdisp_t *jsthis;
1393 UINT32 length, k;
1394 HRESULT hres;
1396 TRACE("\n");
1398 hres = get_length(ctx, vthis, &jsthis, &length);
1399 if(FAILED(hres)) {
1400 FIXME("Could not get length\n");
1401 return hres;
1404 /* Fixme check IsCallable */
1405 if(!argc || !is_object_instance(argv[0])) {
1406 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
1407 hres = E_INVALIDARG;
1408 goto done;
1410 callback = get_object(argv[0]);
1412 if(argc > 1) {
1413 have_value = TRUE;
1414 hres = jsval_copy(argv[1], &acc);
1415 if(FAILED(hres))
1416 goto done;
1419 for(k = 0; k < length; k++) {
1420 hres = jsdisp_get_idx(jsthis, k, &callback_args[1]);
1421 if(hres == DISP_E_UNKNOWNNAME)
1422 continue;
1423 if(FAILED(hres))
1424 break;
1426 if(!have_value) {
1427 have_value = TRUE;
1428 acc = callback_args[1];
1429 continue;
1432 callback_args[0] = acc;
1433 callback_args[2] = jsval_number(k);
1434 callback_args[3] = jsval_obj(jsthis);
1435 hres = disp_call_value(ctx, callback, jsval_undefined(), DISPATCH_METHOD, ARRAY_SIZE(callback_args), callback_args, &new_acc);
1436 jsval_release(callback_args[1]);
1437 if(FAILED(hres))
1438 break;
1440 jsval_release(acc);
1441 acc = new_acc;
1444 if(SUCCEEDED(hres) && !have_value) {
1445 WARN("No array element\n");
1446 hres = JS_E_INVALID_ACTION;
1449 if(SUCCEEDED(hres) && r)
1450 *r = acc;
1451 else if(have_value)
1452 jsval_release(acc);
1453 done:
1454 jsdisp_release(jsthis);
1455 return hres;
1458 static HRESULT Array_some(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1459 jsval_t *r)
1461 jsval_t context_this = jsval_undefined();
1462 jsval_t value, args[3], res;
1463 BOOL boolval, ret = FALSE;
1464 IDispatch *callback;
1465 unsigned length, i;
1466 jsdisp_t *jsthis;
1467 HRESULT hres;
1469 TRACE("\n");
1471 hres = get_length(ctx, vthis, &jsthis, &length);
1472 if(FAILED(hres))
1473 return hres;
1475 /* FIXME: check IsCallable */
1476 if(!argc || !is_object_instance(argv[0])) {
1477 FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
1478 hres = E_INVALIDARG;
1479 goto done;
1481 callback = get_object(argv[0]);
1483 if(argc > 1)
1484 context_this = argv[1];
1486 for(i = 0; i < length; i++) {
1487 hres = jsdisp_get_idx(jsthis, i, &value);
1488 if(FAILED(hres)) {
1489 if(hres == DISP_E_UNKNOWNNAME)
1490 continue;
1491 goto done;
1493 args[0] = value;
1494 args[1] = jsval_number(i);
1495 args[2] = jsval_obj(jsthis);
1496 hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res);
1497 jsval_release(value);
1498 if(FAILED(hres))
1499 goto done;
1501 hres = to_boolean(res, &boolval);
1502 jsval_release(res);
1503 if(FAILED(hres))
1504 goto done;
1505 if(boolval) {
1506 ret = TRUE;
1507 break;
1511 if(r)
1512 *r = jsval_bool(ret);
1513 hres = S_OK;
1514 done:
1515 jsdisp_release(jsthis);
1516 return hres;
1519 /* ECMA-262 3rd Edition 15.4.4.13 */
1520 static HRESULT Array_unshift(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1521 jsval_t *r)
1523 jsdisp_t *jsthis;
1524 WCHAR buf[14], *buf_end, *str;
1525 UINT32 i, length;
1526 jsval_t val;
1527 DISPID id;
1528 HRESULT hres;
1530 TRACE("\n");
1532 hres = get_length(ctx, vthis, &jsthis, &length);
1533 if(FAILED(hres))
1534 return hres;
1536 if(argc) {
1537 buf_end = buf + ARRAY_SIZE(buf)-1;
1538 *buf_end-- = 0;
1539 i = length;
1541 while(i--) {
1542 str = idx_to_str(i, buf_end);
1544 hres = jsdisp_get_id(jsthis, str, 0, &id);
1545 if(SUCCEEDED(hres)) {
1546 hres = jsdisp_propget(jsthis, id, &val);
1547 if(FAILED(hres))
1548 goto done;
1550 hres = jsdisp_propput_idx(jsthis, i+argc, val);
1551 jsval_release(val);
1552 }else if(hres == DISP_E_UNKNOWNNAME) {
1553 hres = IDispatchEx_DeleteMemberByDispID(&jsthis->IDispatchEx_iface, id);
1557 if(FAILED(hres))
1558 goto done;
1561 for(i=0; i<argc; i++) {
1562 hres = jsdisp_propput_idx(jsthis, i, argv[i]);
1563 if(FAILED(hres))
1564 goto done;
1567 if(argc) {
1568 length += argc;
1569 hres = set_length(jsthis, length);
1570 if(FAILED(hres))
1571 goto done;
1574 if(r)
1575 *r = ctx->version < 2 ? jsval_undefined() : jsval_number(length);
1576 hres = S_OK;
1577 done:
1578 jsdisp_release(jsthis);
1579 return hres;
1582 static void Array_destructor(jsdisp_t *dispex)
1584 free(dispex);
1587 static void Array_on_put(jsdisp_t *dispex, const WCHAR *name)
1589 ArrayInstance *array = array_from_jsdisp(dispex);
1590 const WCHAR *ptr = name;
1591 DWORD id = 0;
1593 if(!is_digit(*ptr))
1594 return;
1596 while(*ptr && is_digit(*ptr)) {
1597 id = id*10 + (*ptr-'0');
1598 ptr++;
1601 if(*ptr)
1602 return;
1604 if(id >= array->length)
1605 array->length = id+1;
1608 static const builtin_prop_t Array_props[] = {
1609 {L"concat", Array_concat, PROPF_METHOD|1},
1610 {L"every", Array_every, PROPF_METHOD|PROPF_ES5|1},
1611 {L"filter", Array_filter, PROPF_METHOD|PROPF_ES5|1},
1612 {L"forEach", Array_forEach, PROPF_METHOD|PROPF_ES5|1},
1613 {L"indexOf", Array_indexOf, PROPF_METHOD|PROPF_ES5|1},
1614 {L"join", Array_join, PROPF_METHOD|1},
1615 {L"lastIndexOf", Array_lastIndexOf, PROPF_METHOD|PROPF_ES5|1},
1616 {L"length", NULL,0, Array_get_length, Array_set_length},
1617 {L"map", Array_map, PROPF_METHOD|PROPF_ES5|1},
1618 {L"pop", Array_pop, PROPF_METHOD},
1619 {L"push", Array_push, PROPF_METHOD|1},
1620 {L"reduce", Array_reduce, PROPF_METHOD|PROPF_ES5|1},
1621 {L"reverse", Array_reverse, PROPF_METHOD},
1622 {L"shift", Array_shift, PROPF_METHOD},
1623 {L"slice", Array_slice, PROPF_METHOD|2},
1624 {L"some", Array_some, PROPF_METHOD|PROPF_ES5|1},
1625 {L"sort", Array_sort, PROPF_METHOD|1},
1626 {L"splice", Array_splice, PROPF_METHOD|2},
1627 {L"toLocaleString", Array_toLocaleString, PROPF_METHOD},
1628 {L"toString", Array_toString, PROPF_METHOD},
1629 {L"unshift", Array_unshift, PROPF_METHOD|1},
1632 static const builtin_info_t Array_info = {
1633 JSCLASS_ARRAY,
1634 NULL,
1635 ARRAY_SIZE(Array_props),
1636 Array_props,
1637 Array_destructor,
1638 Array_on_put
1641 static const builtin_prop_t ArrayInst_props[] = {
1642 {L"length", NULL,0, Array_get_length, Array_set_length}
1645 static const builtin_info_t ArrayInst_info = {
1646 JSCLASS_ARRAY,
1647 NULL,
1648 ARRAY_SIZE(ArrayInst_props),
1649 ArrayInst_props,
1650 Array_destructor,
1651 Array_on_put
1654 /* ECMA-262 5.1 Edition 15.4.3.2 */
1655 static HRESULT ArrayConstr_isArray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1657 jsdisp_t *obj;
1659 TRACE("\n");
1661 if(!argc || !is_object_instance(argv[0])) {
1662 if(r) *r = jsval_bool(FALSE);
1663 return S_OK;
1666 obj = iface_to_jsdisp(get_object(argv[0]));
1667 if(r) *r = jsval_bool(obj && is_class(obj, JSCLASS_ARRAY));
1668 if(obj) jsdisp_release(obj);
1669 return S_OK;
1672 static HRESULT ArrayConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1673 jsval_t *r)
1675 jsdisp_t *obj;
1676 DWORD i;
1677 HRESULT hres;
1679 TRACE("\n");
1681 switch(flags) {
1682 case DISPATCH_METHOD:
1683 case DISPATCH_CONSTRUCT: {
1684 if(argc == 1 && is_number(argv[0])) {
1685 double n = get_number(argv[0]);
1687 if(n < 0 || !is_int32(n))
1688 return JS_E_INVALID_LENGTH;
1689 if(!r)
1690 return S_OK;
1692 hres = create_array(ctx, n, &obj);
1693 if(FAILED(hres))
1694 return hres;
1696 *r = jsval_obj(obj);
1697 return S_OK;
1700 if(!r)
1701 return S_OK;
1702 hres = create_array(ctx, argc, &obj);
1703 if(FAILED(hres))
1704 return hres;
1706 for(i=0; i < argc; i++) {
1707 hres = jsdisp_propput_idx(obj, i, argv[i]);
1708 if(FAILED(hres))
1709 break;
1711 if(FAILED(hres)) {
1712 jsdisp_release(obj);
1713 return hres;
1716 *r = jsval_obj(obj);
1717 break;
1719 default:
1720 FIXME("unimplemented flags: %x\n", flags);
1721 return E_NOTIMPL;
1724 return S_OK;
1727 static HRESULT alloc_array(script_ctx_t *ctx, jsdisp_t *object_prototype, ArrayInstance **ret)
1729 ArrayInstance *array;
1730 HRESULT hres;
1732 array = calloc(1, sizeof(ArrayInstance));
1733 if(!array)
1734 return E_OUTOFMEMORY;
1736 if(object_prototype)
1737 hres = init_dispex(&array->dispex, ctx, &Array_info, object_prototype);
1738 else
1739 hres = init_dispex_from_constr(&array->dispex, ctx, &ArrayInst_info, ctx->array_constr);
1741 if(FAILED(hres)) {
1742 free(array);
1743 return hres;
1746 *ret = array;
1747 return S_OK;
1750 static const builtin_prop_t ArrayConstr_props[] = {
1751 {L"isArray", ArrayConstr_isArray, PROPF_ES5|PROPF_METHOD|1}
1754 static const builtin_info_t ArrayConstr_info = {
1755 JSCLASS_FUNCTION,
1756 Function_value,
1757 ARRAY_SIZE(ArrayConstr_props),
1758 ArrayConstr_props,
1759 NULL,
1760 NULL
1763 HRESULT create_array_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
1765 ArrayInstance *array;
1766 HRESULT hres;
1768 hres = alloc_array(ctx, object_prototype, &array);
1769 if(FAILED(hres))
1770 return hres;
1772 hres = create_builtin_constructor(ctx, ArrayConstr_value, L"Array", &ArrayConstr_info, PROPF_CONSTR|1, &array->dispex, ret);
1774 jsdisp_release(&array->dispex);
1775 return hres;
1778 HRESULT create_array(script_ctx_t *ctx, DWORD length, jsdisp_t **ret)
1780 ArrayInstance *array;
1781 HRESULT hres;
1783 hres = alloc_array(ctx, NULL, &array);
1784 if(FAILED(hres))
1785 return hres;
1787 array->length = length;
1789 *ret = &array->dispex;
1790 return S_OK;