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
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(jscript
);
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
)
59 hres
= to_object(ctx
, vthis
, &disp
);
63 jsdisp
= iface_to_jsdisp(disp
);
64 IDispatch_Release(disp
);
66 return JS_E_JSCRIPT_EXPECTED
;
69 if(is_class(jsdisp
, JSCLASS_ARRAY
)) {
70 *ret
= array_from_jsdisp(jsdisp
)->length
;
74 hres
= jsdisp_propget_name(jsdisp
, L
"length", &val
);
76 hres
= to_uint32(ctx
, val
, ret
);
82 jsdisp_release(jsdisp
);
86 static HRESULT
set_length(jsdisp_t
*obj
, DWORD length
)
88 if(is_class(obj
, JSCLASS_ARRAY
)) {
89 array_from_jsdisp(obj
)->length
= length
;
93 return jsdisp_propput_name(obj
, L
"length", jsval_number(length
));
96 static WCHAR
*idx_to_str(DWORD idx
, WCHAR
*ptr
)
104 *ptr
-- = '0' + (idx
%10);
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
);
119 static HRESULT
Array_set_length(script_ctx_t
*ctx
, jsdisp_t
*jsthis
, jsval_t value
)
121 ArrayInstance
*This
= array_from_jsdisp(jsthis
);
126 TRACE("%p %ld\n", This
, This
->length
);
128 hres
= to_number(ctx
, value
, &len
);
134 return JS_E_INVALID_LENGTH
;
136 for(i
=len
; i
< This
->length
; i
++) {
137 hres
= jsdisp_delete_idx(&This
->dispex
, i
);
146 static HRESULT
concat_array(jsdisp_t
*array
, ArrayInstance
*obj
, DWORD
*len
)
152 for(i
=0; i
< obj
->length
; i
++) {
153 hres
= jsdisp_get_idx(&obj
->dispex
, i
, &val
);
154 if(hres
== DISP_E_UNKNOWNNAME
)
159 hres
= jsdisp_propput_idx(array
, *len
+i
, val
);
169 static HRESULT
concat_obj(jsdisp_t
*array
, IDispatch
*obj
, DWORD
*len
)
174 jsobj
= iface_to_jsdisp(obj
);
176 if(is_class(jsobj
, JSCLASS_ARRAY
)) {
177 hres
= concat_array(array
, array_from_jsdisp(jsobj
), len
);
178 jsdisp_release(jsobj
);
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
,
197 hres
= to_object(ctx
, vthis
, &jsthis
);
201 hres
= create_array(ctx
, 0, &ret
);
205 hres
= concat_obj(ret
, jsthis
, &len
);
206 if(SUCCEEDED(hres
)) {
209 for(i
=0; i
< argc
; i
++) {
210 if(is_object_instance(argv
[i
]))
211 hres
= concat_obj(ret
, get_object(argv
[i
]), &len
);
213 hres
= jsdisp_propput_idx(ret
, len
++, argv
[i
]);
227 IDispatch_Release(jsthis
);
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
;
237 HRESULT hres
= E_FAIL
;
241 *r
= jsval_string(jsstr_empty());
245 str_tab
= heap_alloc_zero(length
* sizeof(*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
) {
254 } else if(FAILED(hres
))
257 if(!is_undefined(val
) && !is_null(val
)) {
258 hres
= to_string(ctx
, val
, str_tab
+i
);
265 if(SUCCEEDED(hres
)) {
269 len
= jsstr_length(str_tab
[0]);
270 for(i
=1; i
< length
; i
++) {
273 len
+= jsstr_length(str_tab
[i
]);
274 if(len
> JSSTR_MAX_LENGTH
) {
275 hres
= E_OUTOFMEMORY
;
280 if(SUCCEEDED(hres
)) {
283 ret
= jsstr_alloc_buf(len
, &ptr
);
286 ptr
+= jsstr_flush(str_tab
[0], ptr
);
288 for(i
=1; i
< length
; i
++) {
290 memcpy(ptr
, sep
, seplen
*sizeof(WCHAR
));
295 ptr
+= jsstr_flush(str_tab
[i
], ptr
);
298 hres
= E_OUTOFMEMORY
;
303 for(i
=0; i
< length
; i
++) {
305 jsstr_release(str_tab
[i
]);
311 TRACE("= %s\n", debugstr_jsstr(ret
));
314 *r
= jsval_string(ret
);
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
,
330 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
338 hres
= to_flat_string(ctx
, argv
[0], &sep_str
, &sep
);
342 hres
= array_join(ctx
, jsthis
, length
, sep
, jsstr_length(sep_str
), to_string
, r
);
344 jsstr_release(sep_str
);
346 hres
= array_join(ctx
, jsthis
, length
, L
",", 1, to_string
, r
);
350 jsdisp_release(jsthis
);
354 static HRESULT
Array_pop(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
364 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
369 hres
= set_length(jsthis
, 0);
374 *r
= jsval_undefined();
379 hres
= jsdisp_get_idx(jsthis
, length
, &val
);
381 hres
= jsdisp_delete_idx(jsthis
, length
);
382 else if(hres
== DISP_E_UNKNOWNNAME
) {
383 val
= jsval_undefined();
389 hres
= set_length(jsthis
, length
);
401 jsdisp_release(jsthis
);
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
,
416 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
420 for(i
=0; i
< argc
; i
++) {
421 hres
= jsdisp_propput_idx(jsthis
, length
+i
, argv
[i
]);
426 hres
= set_length(jsthis
, length
+argc
);
431 *r
= jsval_number(length
+argc
);
433 jsdisp_release(jsthis
);
437 static HRESULT
Array_reverse(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
443 HRESULT hres1
, hres2
;
447 hres1
= get_length(ctx
, vthis
, &jsthis
, &length
);
451 for(k
=0; k
<length
/2; k
++) {
454 hres1
= jsdisp_get_idx(jsthis
, k
, &v1
);
455 if(FAILED(hres1
) && hres1
!=DISP_E_UNKNOWNNAME
)
458 hres2
= jsdisp_get_idx(jsthis
, l
, &v2
);
459 if(FAILED(hres2
) && hres2
!=DISP_E_UNKNOWNNAME
) {
465 if(hres1
== DISP_E_UNKNOWNNAME
)
466 hres1
= jsdisp_delete_idx(jsthis
, l
);
468 hres1
= jsdisp_propput_idx(jsthis
, l
, v1
);
476 if(hres2
== DISP_E_UNKNOWNNAME
)
477 hres2
= jsdisp_delete_idx(jsthis
, k
);
479 hres2
= jsdisp_propput_idx(jsthis
, k
, v2
);
489 *r
= jsval_obj(jsdisp_addref(jsthis
));
491 jsdisp_release(jsthis
);
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
,
500 UINT32 length
= 0, i
;
506 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
511 hres
= set_length(jsthis
, 0);
516 *r
= jsval_undefined();
520 hres
= jsdisp_get_idx(jsthis
, 0, &ret
);
521 if(hres
== DISP_E_UNKNOWNNAME
) {
522 ret
= jsval_undefined();
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);
537 hres
= set_length(jsthis
, length
-1);
548 jsdisp_release(jsthis
);
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
;
557 UINT32 length
, start
, end
, idx
;
562 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
567 hres
= to_number(ctx
, argv
[0], &range
);
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
;
580 hres
= to_number(ctx
, argv
[1], &range
);
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
;
592 hres
= create_array(ctx
, (end
>start
)?end
-start
:0, &arr
);
596 for(idx
=start
; idx
<end
; idx
++) {
599 hres
= jsdisp_get_idx(jsthis
, idx
, &v
);
600 if(hres
== DISP_E_UNKNOWNNAME
)
603 if(SUCCEEDED(hres
)) {
604 hres
= jsdisp_propput_idx(arr
, idx
-start
, v
);
621 jsdisp_release(jsthis
);
625 static HRESULT
sort_cmp(script_ctx_t
*ctx
, jsdisp_t
*cmp_func
, jsval_t v1
, jsval_t v2
, INT
*cmp
)
630 jsval_t args
[2] = {v1
, v2
};
634 hres
= jsdisp_call_value(cmp_func
, NULL
, DISPATCH_METHOD
, 2, args
, &res
);
638 hres
= to_number(ctx
, res
, &n
);
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
)) {
650 }else if(is_number(v1
) && is_number(v2
)) {
651 double d
= get_number(v1
)-get_number(v2
);
655 *cmp
= d
< -0.0 ? -1 : 0;
659 hres
= to_string(ctx
, v1
, &x
);
663 hres
= to_string(ctx
, v2
, &y
);
664 if(SUCCEEDED(hres
)) {
665 *cmp
= jsstr_cmp(x
, y
);
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
,
680 jsdisp_t
*jsthis
, *cmp_func
= NULL
;
681 jsval_t
*vtab
, **sorttab
= NULL
;
688 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
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
;
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");
703 jsdisp_release(cmp_func
);
704 hres
= JS_E_JSCRIPT_EXPECTED
;
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
;
717 jsdisp_release(cmp_func
);
719 *r
= jsval_obj(jsdisp_addref(jsthis
));
723 vtab
= heap_alloc_zero(length
* sizeof(*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();
730 } else if(FAILED(hres
)) {
731 WARN("Could not get elem %ld: %08lx\n", i
, hres
);
736 hres
= E_OUTOFMEMORY
;
739 if(SUCCEEDED(hres
)) {
740 sorttab
= heap_alloc(length
*2*sizeof(*sorttab
));
742 hres
= E_OUTOFMEMORY
;
746 if(SUCCEEDED(hres
)) {
747 jsval_t
*tmpv
, **tmpbuf
;
750 tmpbuf
= sorttab
+ length
;
751 for(i
=0; i
< length
; i
++)
754 for(i
=0; i
< length
/2; i
++) {
755 hres
= sort_cmp(ctx
, cmp_func
, *sorttab
[2*i
+1], *sorttab
[2*i
], &cmp
);
761 sorttab
[2*i
] = sorttab
[2*i
+1];
762 sorttab
[2*i
+1] = tmpv
;
766 if(SUCCEEDED(hres
)) {
769 for(k
=2; k
< length
; k
*= 2) {
770 for(i
=0; i
+k
< length
; i
+= 2*k
) {
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
);
785 sorttab
[i
+a
+b
] = tmpbuf
[a
];
788 sorttab
[i
+a
+b
] = sorttab
[i
+k
+b
];
797 memcpy(sorttab
+i
+a
+b
, tmpbuf
+a
, (k
-a
)*sizeof(jsval_t
*));
805 for(i
=0; SUCCEEDED(hres
) && i
< length
; i
++)
806 hres
= jsdisp_propput_idx(jsthis
, i
, *sorttab
[i
]);
810 for(i
=0; i
< length
; i
++)
811 jsval_release(vtab
[i
]);
816 jsdisp_release(cmp_func
);
822 *r
= jsval_obj(jsdisp_addref(jsthis
));
824 jsdisp_release(jsthis
);
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
,
832 UINT32 length
, start
=0, delete_cnt
=0, i
, add_args
= 0;
833 jsdisp_t
*ret_array
= NULL
, *jsthis
;
841 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
846 hres
= to_integer(ctx
, argv
[0], &d
);
852 start
= min(n
, length
);
854 start
= -n
> length
? 0 : length
+ n
;
856 start
= d
< 0.0 ? 0 : length
;
861 hres
= to_integer(ctx
, argv
[1], &d
);
867 delete_cnt
= min(n
, length
-start
);
869 delete_cnt
= length
-start
;
876 hres
= create_array(ctx
, 0, &ret_array
);
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
) {
884 }else if(SUCCEEDED(hres
)) {
885 hres
= jsdisp_propput_idx(ret_array
, i
, val
);
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
);
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
);
919 for(i
=0; SUCCEEDED(hres
) && i
< add_args
; i
++)
920 hres
= jsdisp_propput_idx(jsthis
, start
+i
, argv
[i
+2]);
923 hres
= jsdisp_propput_name(jsthis
, L
"length", jsval_number(length
-delete_cnt
+add_args
));
927 jsdisp_release(ret_array
);
932 *r
= jsval_obj(ret_array
);
934 jsdisp_release(jsthis
);
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
,
942 ArrayInstance
*array
;
946 array
= array_this(vthis
);
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
)
959 switch(jsval_type(val
)) {
961 hres
= disp_call_name(ctx
, get_object(val
), L
"toLocaleString", DISPATCH_METHOD
, 0, NULL
, &val
);
963 if(hres
== JS_E_INVALID_PROPERTY
&& ctx
->version
>= SCRIPTLANGUAGEVERSION_ES5
)
964 hres
= JS_E_FUNCTION_EXPECTED
;
969 if(ctx
->version
>= SCRIPTLANGUAGEVERSION_ES5
)
970 return localize_number(ctx
, get_number(val
), FALSE
, str
);
973 if(ctx
->version
>= SCRIPTLANGUAGEVERSION_ES5
)
976 hres
= to_object(ctx
, val
, &obj
);
980 jsdisp
= as_jsdisp(obj
);
981 hres
= jsdisp_call_name(jsdisp
, L
"toLocaleString", DISPATCH_METHOD
, 0, NULL
, &val
);
982 jsdisp_release(jsdisp
);
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
,
1002 if(ctx
->version
< SCRIPTLANGUAGEVERSION_ES5
) {
1003 ArrayInstance
*array
= array_this(vthis
);
1005 return JS_E_ARRAY_EXPECTED
;
1006 jsthis
= jsdisp_addref(&array
->dispex
);
1007 length
= array
->length
;
1009 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1014 if(!(len
= GetLocaleInfoW(ctx
->lcid
, LOCALE_SLIST
, buf
, ARRAY_SIZE(buf
) - 1))) {
1021 hres
= array_join(ctx
, jsthis
, length
, buf
, len
, to_locale_string
, r
);
1022 jsdisp_release(jsthis
);
1026 static HRESULT
Array_every(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1029 IDispatch
*context_obj
= NULL
, *callback
;
1030 jsval_t value
, args
[3], res
;
1031 BOOL boolval
, ret
= TRUE
;
1038 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1042 /* FIXME: check IsCallable */
1043 if(!argc
|| !is_object_instance(argv
[0])) {
1044 FIXME("Invalid arg %s\n", debugstr_jsval(argc
? argv
[0] : jsval_undefined()));
1045 hres
= E_INVALIDARG
;
1048 callback
= get_object(argv
[0]);
1050 if(argc
> 1 && !is_undefined(argv
[1])) {
1051 if(!is_object_instance(argv
[1])) {
1052 FIXME("Unsupported context this %s\n", debugstr_jsval(argv
[1]));
1056 context_obj
= get_object(argv
[1]);
1059 for(i
= 0; i
< length
; i
++) {
1060 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1062 if(hres
== DISP_E_UNKNOWNNAME
)
1067 args
[1] = jsval_number(i
);
1068 args
[2] = jsval_obj(jsthis
);
1069 hres
= disp_call_value(ctx
, callback
, context_obj
, DISPATCH_METHOD
, ARRAY_SIZE(args
), args
, &res
);
1070 jsval_release(value
);
1074 hres
= to_boolean(res
, &boolval
);
1085 *r
= jsval_bool(ret
);
1088 jsdisp_release(jsthis
);
1092 static HRESULT
Array_filter(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1095 IDispatch
*context_obj
= NULL
, *callback
;
1096 jsval_t value
, args
[3], res
;
1097 unsigned length
, i
, j
= 0;
1098 jsdisp_t
*jsthis
, *arr
;
1104 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1108 /* FIXME: check IsCallable */
1109 if(!argc
|| !is_object_instance(argv
[0])) {
1110 FIXME("Invalid arg %s\n", debugstr_jsval(argc
? argv
[0] : jsval_undefined()));
1111 hres
= E_INVALIDARG
;
1114 callback
= get_object(argv
[0]);
1116 if(argc
> 1 && !is_undefined(argv
[1])) {
1117 if(!is_object_instance(argv
[1])) {
1118 FIXME("Unsupported context this %s\n", debugstr_jsval(argv
[1]));
1122 context_obj
= get_object(argv
[1]);
1125 hres
= create_array(ctx
, 0, &arr
);
1129 for(i
= 0; i
< length
; i
++) {
1130 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1132 if(hres
== DISP_E_UNKNOWNNAME
) {
1139 args
[1] = jsval_number(i
);
1140 args
[2] = jsval_obj(jsthis
);
1141 hres
= disp_call_value(ctx
, callback
, context_obj
, DISPATCH_METHOD
, ARRAY_SIZE(args
), args
, &res
);
1142 if(SUCCEEDED(hres
)) {
1143 hres
= to_boolean(res
, &boolval
);
1145 if(SUCCEEDED(hres
) && boolval
)
1146 hres
= jsdisp_propput_idx(arr
, j
++, value
);
1148 jsval_release(value
);
1154 jsdisp_release(arr
);
1160 *r
= jsval_obj(arr
);
1162 jsdisp_release(jsthis
);
1166 static HRESULT
Array_forEach(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1169 IDispatch
*context_obj
= NULL
, *callback
;
1170 jsval_t value
, args
[3], res
;
1177 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1181 /* Fixme check IsCallable */
1182 if(!argc
|| !is_object_instance(argv
[0])) {
1183 FIXME("Invalid arg %s\n", debugstr_jsval(argc
? argv
[0] : jsval_undefined()));
1184 hres
= E_INVALIDARG
;
1187 callback
= get_object(argv
[0]);
1189 if(argc
> 1 && !is_undefined(argv
[1])) {
1190 if(!is_object_instance(argv
[1])) {
1191 FIXME("Unsupported context this %s\n", debugstr_jsval(argv
[1]));
1195 context_obj
= get_object(argv
[1]);
1198 for(i
= 0; i
< length
; i
++) {
1199 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1200 if(hres
== DISP_E_UNKNOWNNAME
)
1206 args
[1] = jsval_number(i
);
1207 args
[2] = jsval_obj(jsthis
);
1208 hres
= disp_call_value(ctx
, callback
, context_obj
, DISPATCH_METHOD
, ARRAY_SIZE(args
), args
, &res
);
1209 jsval_release(value
);
1215 if(r
) *r
= jsval_undefined();
1218 jsdisp_release(jsthis
);
1222 static HRESULT
Array_indexOf(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1226 unsigned length
, i
, from
= 0;
1227 jsval_t search
, value
;
1233 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1237 if(r
) *r
= jsval_number(-1);
1241 search
= argc
? argv
[0] : jsval_undefined();
1246 hres
= to_integer(ctx
, argv
[1], &from_arg
);
1251 from
= min(from_arg
, length
);
1253 from
= max(from_arg
+ length
, 0);
1256 for(i
= from
; i
< length
; i
++) {
1257 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1258 if(hres
== DISP_E_UNKNOWNNAME
)
1263 hres
= jsval_strict_equal(value
, search
, &eq
);
1264 jsval_release(value
);
1268 if(r
) *r
= jsval_number(i
);
1273 if(r
) *r
= jsval_number(-1);
1276 jsdisp_release(jsthis
);
1280 static HRESULT
Array_lastIndexOf(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1283 jsval_t search
, value
;
1291 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1297 search
= argc
? argv
[0] : jsval_undefined();
1303 hres
= to_integer(ctx
, argv
[1], &from_arg
);
1308 i
= min(from_arg
, i
);
1318 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1319 if(hres
== DISP_E_UNKNOWNNAME
)
1324 hres
= jsval_strict_equal(value
, search
, &eq
);
1325 jsval_release(value
);
1329 if(r
) *r
= jsval_number(i
);
1335 if(r
) *r
= jsval_number(-1);
1338 jsdisp_release(jsthis
);
1342 static HRESULT
Array_map(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1344 IDispatch
*context_this
= NULL
, *callback
;
1345 jsval_t callback_args
[3], mapped_value
;
1346 jsdisp_t
*jsthis
, *array
;
1352 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1354 FIXME("Could not get length\n");
1358 /* FIXME: check IsCallable */
1359 if(!argc
|| !is_object_instance(argv
[0])) {
1360 FIXME("Invalid arg %s\n", debugstr_jsval(argc
? argv
[0] : jsval_undefined()));
1361 hres
= E_INVALIDARG
;
1364 callback
= get_object(argv
[0]);
1367 if(is_object_instance(argv
[1])) {
1368 context_this
= get_object(argv
[1]);
1369 }else if(!is_undefined(argv
[1])) {
1370 FIXME("Unsupported context this %s\n", debugstr_jsval(argv
[1]));
1376 hres
= create_array(ctx
, length
, &array
);
1380 for(k
= 0; k
< length
; k
++) {
1381 hres
= jsdisp_get_idx(jsthis
, k
, &callback_args
[0]);
1382 if(hres
== DISP_E_UNKNOWNNAME
)
1387 callback_args
[1] = jsval_number(k
);
1388 callback_args
[2] = jsval_obj(jsthis
);
1389 hres
= disp_call_value(ctx
, callback
, context_this
, DISPATCH_METHOD
, 3, callback_args
, &mapped_value
);
1390 jsval_release(callback_args
[0]);
1394 hres
= jsdisp_propput_idx(array
, k
, mapped_value
);
1399 if(SUCCEEDED(hres
) && r
)
1400 *r
= jsval_obj(array
);
1402 jsdisp_release(array
);
1404 jsdisp_release(jsthis
);
1408 static HRESULT
Array_reduce(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1410 IDispatch
*context_this
= NULL
, *callback
;
1411 jsval_t callback_args
[4], acc
, new_acc
;
1412 BOOL have_value
= FALSE
;
1419 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1421 FIXME("Could not get length\n");
1425 /* Fixme check IsCallable */
1426 if(!argc
|| !is_object_instance(argv
[0])) {
1427 FIXME("Invalid arg %s\n", debugstr_jsval(argc
? argv
[0] : jsval_undefined()));
1428 hres
= E_INVALIDARG
;
1431 callback
= get_object(argv
[0]);
1435 hres
= jsval_copy(argv
[1], &acc
);
1440 for(k
= 0; k
< length
; k
++) {
1441 hres
= jsdisp_get_idx(jsthis
, k
, &callback_args
[1]);
1442 if(hres
== DISP_E_UNKNOWNNAME
)
1449 acc
= callback_args
[1];
1453 callback_args
[0] = acc
;
1454 callback_args
[2] = jsval_number(k
);
1455 callback_args
[3] = jsval_obj(jsthis
);
1456 hres
= disp_call_value(ctx
, callback
, context_this
, DISPATCH_METHOD
, ARRAY_SIZE(callback_args
), callback_args
, &new_acc
);
1457 jsval_release(callback_args
[1]);
1465 if(SUCCEEDED(hres
) && !have_value
) {
1466 WARN("No array element\n");
1467 hres
= JS_E_INVALID_ACTION
;
1470 if(SUCCEEDED(hres
) && r
)
1475 jsdisp_release(jsthis
);
1479 static HRESULT
Array_some(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1482 IDispatch
*context_obj
= NULL
, *callback
;
1483 jsval_t value
, args
[3], res
;
1484 BOOL boolval
, ret
= FALSE
;
1491 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1495 /* FIXME: check IsCallable */
1496 if(!argc
|| !is_object_instance(argv
[0])) {
1497 FIXME("Invalid arg %s\n", debugstr_jsval(argc
? argv
[0] : jsval_undefined()));
1498 hres
= E_INVALIDARG
;
1501 callback
= get_object(argv
[0]);
1503 if(argc
> 1 && !is_undefined(argv
[1])) {
1504 if(!is_object_instance(argv
[1])) {
1505 FIXME("Unsupported context this %s\n", debugstr_jsval(argv
[1]));
1509 context_obj
= get_object(argv
[1]);
1512 for(i
= 0; i
< length
; i
++) {
1513 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1515 if(hres
== DISP_E_UNKNOWNNAME
)
1520 args
[1] = jsval_number(i
);
1521 args
[2] = jsval_obj(jsthis
);
1522 hres
= disp_call_value(ctx
, callback
, context_obj
, DISPATCH_METHOD
, ARRAY_SIZE(args
), args
, &res
);
1523 jsval_release(value
);
1527 hres
= to_boolean(res
, &boolval
);
1538 *r
= jsval_bool(ret
);
1541 jsdisp_release(jsthis
);
1545 /* ECMA-262 3rd Edition 15.4.4.13 */
1546 static HRESULT
Array_unshift(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1550 WCHAR buf
[14], *buf_end
, *str
;
1558 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1563 buf_end
= buf
+ ARRAY_SIZE(buf
)-1;
1568 str
= idx_to_str(i
, buf_end
);
1570 hres
= jsdisp_get_id(jsthis
, str
, 0, &id
);
1571 if(SUCCEEDED(hres
)) {
1572 hres
= jsdisp_propget(jsthis
, id
, &val
);
1576 hres
= jsdisp_propput_idx(jsthis
, i
+argc
, val
);
1578 }else if(hres
== DISP_E_UNKNOWNNAME
) {
1579 hres
= IDispatchEx_DeleteMemberByDispID(&jsthis
->IDispatchEx_iface
, id
);
1587 for(i
=0; i
<argc
; i
++) {
1588 hres
= jsdisp_propput_idx(jsthis
, i
, argv
[i
]);
1595 hres
= set_length(jsthis
, length
);
1601 *r
= ctx
->version
< 2 ? jsval_undefined() : jsval_number(length
);
1604 jsdisp_release(jsthis
);
1608 static void Array_destructor(jsdisp_t
*dispex
)
1613 static void Array_on_put(jsdisp_t
*dispex
, const WCHAR
*name
)
1615 ArrayInstance
*array
= array_from_jsdisp(dispex
);
1616 const WCHAR
*ptr
= name
;
1622 while(*ptr
&& is_digit(*ptr
)) {
1623 id
= id
*10 + (*ptr
-'0');
1630 if(id
>= array
->length
)
1631 array
->length
= id
+1;
1634 static const builtin_prop_t Array_props
[] = {
1635 {L
"concat", Array_concat
, PROPF_METHOD
|1},
1636 {L
"every", Array_every
, PROPF_METHOD
|PROPF_ES5
|1},
1637 {L
"filter", Array_filter
, PROPF_METHOD
|PROPF_ES5
|1},
1638 {L
"forEach", Array_forEach
, PROPF_METHOD
|PROPF_ES5
|1},
1639 {L
"indexOf", Array_indexOf
, PROPF_METHOD
|PROPF_ES5
|1},
1640 {L
"join", Array_join
, PROPF_METHOD
|1},
1641 {L
"lastIndexOf", Array_lastIndexOf
, PROPF_METHOD
|PROPF_ES5
|1},
1642 {L
"length", NULL
,0, Array_get_length
, Array_set_length
},
1643 {L
"map", Array_map
, PROPF_METHOD
|PROPF_ES5
|1},
1644 {L
"pop", Array_pop
, PROPF_METHOD
},
1645 {L
"push", Array_push
, PROPF_METHOD
|1},
1646 {L
"reduce", Array_reduce
, PROPF_METHOD
|PROPF_ES5
|1},
1647 {L
"reverse", Array_reverse
, PROPF_METHOD
},
1648 {L
"shift", Array_shift
, PROPF_METHOD
},
1649 {L
"slice", Array_slice
, PROPF_METHOD
|2},
1650 {L
"some", Array_some
, PROPF_METHOD
|PROPF_ES5
|1},
1651 {L
"sort", Array_sort
, PROPF_METHOD
|1},
1652 {L
"splice", Array_splice
, PROPF_METHOD
|2},
1653 {L
"toLocaleString", Array_toLocaleString
, PROPF_METHOD
},
1654 {L
"toString", Array_toString
, PROPF_METHOD
},
1655 {L
"unshift", Array_unshift
, PROPF_METHOD
|1},
1658 static const builtin_info_t Array_info
= {
1661 ARRAY_SIZE(Array_props
),
1667 static const builtin_prop_t ArrayInst_props
[] = {
1668 {L
"length", NULL
,0, Array_get_length
, Array_set_length
}
1671 static const builtin_info_t ArrayInst_info
= {
1674 ARRAY_SIZE(ArrayInst_props
),
1680 /* ECMA-262 5.1 Edition 15.4.3.2 */
1681 static HRESULT
ArrayConstr_isArray(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1687 if(!argc
|| !is_object_instance(argv
[0])) {
1688 if(r
) *r
= jsval_bool(FALSE
);
1692 obj
= iface_to_jsdisp(get_object(argv
[0]));
1693 if(r
) *r
= jsval_bool(obj
&& is_class(obj
, JSCLASS_ARRAY
));
1694 if(obj
) jsdisp_release(obj
);
1698 static HRESULT
ArrayConstr_value(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1708 case DISPATCH_METHOD
:
1709 case DISPATCH_CONSTRUCT
: {
1710 if(argc
== 1 && is_number(argv
[0])) {
1711 double n
= get_number(argv
[0]);
1713 if(n
< 0 || !is_int32(n
))
1714 return JS_E_INVALID_LENGTH
;
1718 hres
= create_array(ctx
, n
, &obj
);
1722 *r
= jsval_obj(obj
);
1728 hres
= create_array(ctx
, argc
, &obj
);
1732 for(i
=0; i
< argc
; i
++) {
1733 hres
= jsdisp_propput_idx(obj
, i
, argv
[i
]);
1738 jsdisp_release(obj
);
1742 *r
= jsval_obj(obj
);
1746 FIXME("unimplemented flags: %x\n", flags
);
1753 static HRESULT
alloc_array(script_ctx_t
*ctx
, jsdisp_t
*object_prototype
, ArrayInstance
**ret
)
1755 ArrayInstance
*array
;
1758 array
= heap_alloc_zero(sizeof(ArrayInstance
));
1760 return E_OUTOFMEMORY
;
1762 if(object_prototype
)
1763 hres
= init_dispex(&array
->dispex
, ctx
, &Array_info
, object_prototype
);
1765 hres
= init_dispex_from_constr(&array
->dispex
, ctx
, &ArrayInst_info
, ctx
->array_constr
);
1776 static const builtin_prop_t ArrayConstr_props
[] = {
1777 {L
"isArray", ArrayConstr_isArray
, PROPF_ES5
|PROPF_METHOD
|1}
1780 static const builtin_info_t ArrayConstr_info
= {
1783 ARRAY_SIZE(ArrayConstr_props
),
1789 HRESULT
create_array_constr(script_ctx_t
*ctx
, jsdisp_t
*object_prototype
, jsdisp_t
**ret
)
1791 ArrayInstance
*array
;
1794 hres
= alloc_array(ctx
, object_prototype
, &array
);
1798 hres
= create_builtin_constructor(ctx
, ArrayConstr_value
, L
"Array", &ArrayConstr_info
, PROPF_CONSTR
|1, &array
->dispex
, ret
);
1800 jsdisp_release(&array
->dispex
);
1804 HRESULT
create_array(script_ctx_t
*ctx
, DWORD length
, jsdisp_t
**ret
)
1806 ArrayInstance
*array
;
1809 hres
= alloc_array(ctx
, NULL
, &array
);
1813 array
->length
= length
;
1815 *ret
= &array
->dispex
;