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 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
= calloc(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
);
536 if(SUCCEEDED(hres
)) {
537 hres
= jsdisp_delete_idx(jsthis
, length
-1);
539 hres
= set_length(jsthis
, length
-1);
550 jsdisp_release(jsthis
);
554 /* ECMA-262 3rd Edition 15.4.4.10 */
555 static HRESULT
Array_slice(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
557 jsdisp_t
*arr
, *jsthis
;
559 UINT32 length
, start
, end
, idx
;
564 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
569 hres
= to_number(ctx
, argv
[0], &range
);
573 range
= floor(range
);
574 if(-range
>length
|| isnan(range
)) start
= 0;
575 else if(range
< 0) start
= range
+length
;
576 else if(range
<= length
) start
= range
;
582 hres
= to_number(ctx
, argv
[1], &range
);
586 range
= floor(range
);
587 if(-range
>length
) end
= 0;
588 else if(range
< 0) end
= range
+length
;
589 else if(range
<= length
) end
= range
;
594 hres
= create_array(ctx
, (end
>start
)?end
-start
:0, &arr
);
598 for(idx
=start
; idx
<end
; idx
++) {
601 hres
= jsdisp_get_idx(jsthis
, idx
, &v
);
602 if(hres
== DISP_E_UNKNOWNNAME
)
605 if(SUCCEEDED(hres
)) {
606 hres
= jsdisp_propput_idx(arr
, idx
-start
, v
);
623 jsdisp_release(jsthis
);
627 static HRESULT
sort_cmp(script_ctx_t
*ctx
, jsdisp_t
*cmp_func
, jsval_t v1
, jsval_t v2
, INT
*cmp
)
632 jsval_t args
[2] = {v1
, v2
};
636 hres
= jsdisp_call_value(cmp_func
, jsval_undefined(), DISPATCH_METHOD
, 2, args
, &res
);
640 hres
= to_number(ctx
, res
, &n
);
647 *cmp
= n
> 0.0 ? 1 : -1;
648 }else if(is_undefined(v1
)) {
649 *cmp
= is_undefined(v2
) ? 0 : 1;
650 }else if(is_undefined(v2
)) {
652 }else if(is_number(v1
) && is_number(v2
)) {
653 double d
= get_number(v1
)-get_number(v2
);
657 *cmp
= d
< -0.0 ? -1 : 0;
661 hres
= to_string(ctx
, v1
, &x
);
665 hres
= to_string(ctx
, v2
, &y
);
666 if(SUCCEEDED(hres
)) {
667 *cmp
= jsstr_cmp(x
, y
);
678 /* ECMA-262 3rd Edition 15.4.4.11 */
679 static HRESULT
Array_sort(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
682 jsdisp_t
*jsthis
, *cmp_func
= NULL
;
683 jsval_t
*vtab
, **sorttab
= NULL
;
690 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
695 if(is_object_instance(argv
[0])) {
696 if(argc
> 1 && ctx
->version
< SCRIPTLANGUAGEVERSION_ES5
) {
697 WARN("invalid arg_cnt %d\n", argc
);
698 hres
= JS_E_JSCRIPT_EXPECTED
;
701 cmp_func
= iface_to_jsdisp(get_object(argv
[0]));
702 if(!cmp_func
|| !is_class(cmp_func
, JSCLASS_FUNCTION
)) {
703 WARN("cmp_func is not a function\n");
705 jsdisp_release(cmp_func
);
706 hres
= JS_E_JSCRIPT_EXPECTED
;
709 }else if(ctx
->version
>= SCRIPTLANGUAGEVERSION_ES5
? !is_undefined(argv
[0]) :
710 (!is_null(argv
[0]) || is_null_disp(argv
[0]))) {
711 WARN("invalid arg %s\n", debugstr_jsval(argv
[0]));
712 hres
= JS_E_JSCRIPT_EXPECTED
;
719 jsdisp_release(cmp_func
);
721 *r
= jsval_obj(jsdisp_addref(jsthis
));
725 vtab
= calloc(length
, sizeof(*vtab
));
727 for(i
=0; i
<length
; i
++) {
728 hres
= jsdisp_get_idx(jsthis
, i
, vtab
+i
);
729 if(hres
== DISP_E_UNKNOWNNAME
) {
730 vtab
[i
] = jsval_undefined();
732 } else if(FAILED(hres
)) {
733 WARN("Could not get elem %ld: %08lx\n", i
, hres
);
738 hres
= E_OUTOFMEMORY
;
741 if(SUCCEEDED(hres
)) {
742 sorttab
= malloc(length
*2*sizeof(*sorttab
));
744 hres
= E_OUTOFMEMORY
;
748 if(SUCCEEDED(hres
)) {
749 jsval_t
*tmpv
, **tmpbuf
;
752 tmpbuf
= sorttab
+ length
;
753 for(i
=0; i
< length
; i
++)
756 for(i
=0; i
< length
/2; i
++) {
757 hres
= sort_cmp(ctx
, cmp_func
, *sorttab
[2*i
+1], *sorttab
[2*i
], &cmp
);
763 sorttab
[2*i
] = sorttab
[2*i
+1];
764 sorttab
[2*i
+1] = tmpv
;
768 if(SUCCEEDED(hres
)) {
771 for(k
=2; k
< length
; k
*= 2) {
772 for(i
=0; i
+k
< length
; i
+= 2*k
) {
777 bend
= length
- (i
+k
);
779 memcpy(tmpbuf
, sorttab
+i
, k
*sizeof(jsval_t
*));
781 while(a
< k
&& b
< bend
) {
782 hres
= sort_cmp(ctx
, cmp_func
, *tmpbuf
[a
], *sorttab
[i
+k
+b
], &cmp
);
787 sorttab
[i
+a
+b
] = tmpbuf
[a
];
790 sorttab
[i
+a
+b
] = sorttab
[i
+k
+b
];
799 memcpy(sorttab
+i
+a
+b
, tmpbuf
+a
, (k
-a
)*sizeof(jsval_t
*));
807 for(i
=0; SUCCEEDED(hres
) && i
< length
; i
++)
808 hres
= jsdisp_propput_idx(jsthis
, i
, *sorttab
[i
]);
812 for(i
=0; i
< length
; i
++)
813 jsval_release(vtab
[i
]);
818 jsdisp_release(cmp_func
);
824 *r
= jsval_obj(jsdisp_addref(jsthis
));
826 jsdisp_release(jsthis
);
830 /* ECMA-262 3rd Edition 15.4.4.12 */
831 static HRESULT
Array_splice(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
834 UINT32 length
, start
=0, delete_cnt
=0, i
, add_args
= 0;
835 jsdisp_t
*ret_array
= NULL
, *jsthis
;
843 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
848 hres
= to_integer(ctx
, argv
[0], &d
);
854 start
= min(n
, length
);
856 start
= -n
> length
? 0 : length
+ n
;
858 start
= d
< 0.0 ? 0 : length
;
863 hres
= to_integer(ctx
, argv
[1], &d
);
869 delete_cnt
= min(n
, length
-start
);
871 delete_cnt
= length
-start
;
875 } else if (argc
&& ctx
->version
>= SCRIPTLANGUAGEVERSION_ES5
) {
876 delete_cnt
= length
-start
;
880 hres
= create_array(ctx
, 0, &ret_array
);
884 for(i
=0; SUCCEEDED(hres
) && i
< delete_cnt
; i
++) {
885 hres
= jsdisp_get_idx(jsthis
, start
+i
, &val
);
886 if(hres
== DISP_E_UNKNOWNNAME
) {
888 }else if(SUCCEEDED(hres
)) {
889 hres
= jsdisp_propput_idx(ret_array
, i
, val
);
895 hres
= jsdisp_propput_name(ret_array
, L
"length", jsval_number(delete_cnt
));
898 if(add_args
< delete_cnt
) {
899 for(i
= start
; SUCCEEDED(hres
) && i
< length
-delete_cnt
; i
++) {
900 hres
= jsdisp_get_idx(jsthis
, i
+delete_cnt
, &val
);
901 if(hres
== DISP_E_UNKNOWNNAME
) {
902 hres
= jsdisp_delete_idx(jsthis
, i
+add_args
);
903 }else if(SUCCEEDED(hres
)) {
904 hres
= jsdisp_propput_idx(jsthis
, i
+add_args
, val
);
909 for(i
=length
; SUCCEEDED(hres
) && i
!= length
-delete_cnt
+add_args
; i
--)
910 hres
= jsdisp_delete_idx(jsthis
, i
-1);
911 }else if(add_args
> delete_cnt
) {
912 for(i
=length
-delete_cnt
; SUCCEEDED(hres
) && i
!= start
; i
--) {
913 hres
= jsdisp_get_idx(jsthis
, i
+delete_cnt
-1, &val
);
914 if(hres
== DISP_E_UNKNOWNNAME
) {
915 hres
= jsdisp_delete_idx(jsthis
, i
+add_args
-1);
916 }else if(SUCCEEDED(hres
)) {
917 hres
= jsdisp_propput_idx(jsthis
, i
+add_args
-1, val
);
923 for(i
=0; SUCCEEDED(hres
) && i
< add_args
; i
++)
924 hres
= jsdisp_propput_idx(jsthis
, start
+i
, argv
[i
+2]);
927 hres
= jsdisp_propput_name(jsthis
, L
"length", jsval_number(length
-delete_cnt
+add_args
));
931 jsdisp_release(ret_array
);
936 *r
= jsval_obj(ret_array
);
938 jsdisp_release(jsthis
);
942 /* ECMA-262 3rd Edition 15.4.4.2 */
943 static HRESULT
Array_toString(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
946 ArrayInstance
*array
;
950 array
= array_this(vthis
);
952 return JS_E_ARRAY_EXPECTED
;
954 return array_join(ctx
, &array
->dispex
, array
->length
, L
",", 1, to_string
, r
);
957 static HRESULT
to_locale_string(script_ctx_t
*ctx
, jsval_t val
, jsstr_t
**str
)
963 switch(jsval_type(val
)) {
965 hres
= disp_call_name(ctx
, get_object(val
), L
"toLocaleString", DISPATCH_METHOD
, 0, NULL
, &val
);
967 if(hres
== JS_E_INVALID_PROPERTY
&& ctx
->version
>= SCRIPTLANGUAGEVERSION_ES5
)
968 hres
= JS_E_FUNCTION_EXPECTED
;
973 if(ctx
->version
>= SCRIPTLANGUAGEVERSION_ES5
)
974 return localize_number(ctx
, get_number(val
), FALSE
, str
);
977 if(ctx
->version
>= SCRIPTLANGUAGEVERSION_ES5
)
980 hres
= to_object(ctx
, val
, &obj
);
984 jsdisp
= as_jsdisp(obj
);
985 hres
= jsdisp_call_name(jsdisp
, L
"toLocaleString", DISPATCH_METHOD
, 0, NULL
, &val
);
986 jsdisp_release(jsdisp
);
992 return to_string(ctx
, val
, str
);
995 static HRESULT
Array_toLocaleString(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1006 if(ctx
->version
< SCRIPTLANGUAGEVERSION_ES5
) {
1007 ArrayInstance
*array
= array_this(vthis
);
1009 return JS_E_ARRAY_EXPECTED
;
1010 jsthis
= jsdisp_addref(&array
->dispex
);
1011 length
= array
->length
;
1013 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1018 if(!(len
= GetLocaleInfoW(ctx
->lcid
, LOCALE_SLIST
, buf
, ARRAY_SIZE(buf
) - 1))) {
1025 hres
= array_join(ctx
, jsthis
, length
, buf
, len
, to_locale_string
, r
);
1026 jsdisp_release(jsthis
);
1030 static HRESULT
Array_every(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1033 jsval_t context_this
= jsval_undefined();
1034 jsval_t value
, args
[3], res
;
1035 BOOL boolval
, ret
= TRUE
;
1036 IDispatch
*callback
;
1043 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1047 /* FIXME: check IsCallable */
1048 if(!argc
|| !is_object_instance(argv
[0])) {
1049 FIXME("Invalid arg %s\n", debugstr_jsval(argc
? argv
[0] : jsval_undefined()));
1050 hres
= E_INVALIDARG
;
1053 callback
= get_object(argv
[0]);
1056 context_this
= argv
[1];
1058 for(i
= 0; i
< length
; i
++) {
1059 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1061 if(hres
== DISP_E_UNKNOWNNAME
)
1066 args
[1] = jsval_number(i
);
1067 args
[2] = jsval_obj(jsthis
);
1068 hres
= disp_call_value(ctx
, callback
, context_this
, DISPATCH_METHOD
, ARRAY_SIZE(args
), args
, &res
);
1069 jsval_release(value
);
1073 hres
= to_boolean(res
, &boolval
);
1084 *r
= jsval_bool(ret
);
1087 jsdisp_release(jsthis
);
1091 static HRESULT
Array_filter(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1094 jsval_t context_this
= jsval_undefined();
1095 jsval_t value
, args
[3], res
;
1096 unsigned length
, i
, j
= 0;
1097 jsdisp_t
*jsthis
, *arr
;
1098 IDispatch
*callback
;
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]);
1117 context_this
= argv
[1];
1119 hres
= create_array(ctx
, 0, &arr
);
1123 for(i
= 0; i
< length
; i
++) {
1124 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1126 if(hres
== DISP_E_UNKNOWNNAME
) {
1133 args
[1] = jsval_number(i
);
1134 args
[2] = jsval_obj(jsthis
);
1135 hres
= disp_call_value(ctx
, callback
, context_this
, DISPATCH_METHOD
, ARRAY_SIZE(args
), args
, &res
);
1136 if(SUCCEEDED(hres
)) {
1137 hres
= to_boolean(res
, &boolval
);
1139 if(SUCCEEDED(hres
) && boolval
)
1140 hres
= jsdisp_propput_idx(arr
, j
++, value
);
1142 jsval_release(value
);
1148 jsdisp_release(arr
);
1154 *r
= jsval_obj(arr
);
1156 jsdisp_release(arr
);
1158 jsdisp_release(jsthis
);
1162 static HRESULT
Array_forEach(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1165 jsval_t context_this
= jsval_undefined();
1166 jsval_t value
, args
[3], res
;
1167 IDispatch
*callback
;
1174 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1178 /* Fixme check IsCallable */
1179 if(!argc
|| !is_object_instance(argv
[0])) {
1180 FIXME("Invalid arg %s\n", debugstr_jsval(argc
? argv
[0] : jsval_undefined()));
1181 hres
= E_INVALIDARG
;
1184 callback
= get_object(argv
[0]);
1187 context_this
= argv
[1];
1189 for(i
= 0; i
< length
; i
++) {
1190 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1191 if(hres
== DISP_E_UNKNOWNNAME
)
1197 args
[1] = jsval_number(i
);
1198 args
[2] = jsval_obj(jsthis
);
1199 hres
= disp_call_value(ctx
, callback
, context_this
, DISPATCH_METHOD
, ARRAY_SIZE(args
), args
, &res
);
1200 jsval_release(value
);
1206 if(r
) *r
= jsval_undefined();
1209 jsdisp_release(jsthis
);
1213 static HRESULT
Array_indexOf(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1217 unsigned length
, i
, from
= 0;
1218 jsval_t search
, value
;
1224 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1228 if(r
) *r
= jsval_number(-1);
1232 search
= argc
? argv
[0] : jsval_undefined();
1237 hres
= to_integer(ctx
, argv
[1], &from_arg
);
1242 from
= min(from_arg
, length
);
1244 from
= max(from_arg
+ length
, 0);
1247 for(i
= from
; i
< length
; i
++) {
1248 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1249 if(hres
== DISP_E_UNKNOWNNAME
)
1254 hres
= jsval_strict_equal(value
, search
, &eq
);
1255 jsval_release(value
);
1259 if(r
) *r
= jsval_number(i
);
1264 if(r
) *r
= jsval_number(-1);
1267 jsdisp_release(jsthis
);
1271 static HRESULT
Array_lastIndexOf(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1274 jsval_t search
, value
;
1282 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1288 search
= argc
? argv
[0] : jsval_undefined();
1294 hres
= to_integer(ctx
, argv
[1], &from_arg
);
1299 i
= min(from_arg
, i
);
1309 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1310 if(hres
== DISP_E_UNKNOWNNAME
)
1315 hres
= jsval_strict_equal(value
, search
, &eq
);
1316 jsval_release(value
);
1320 if(r
) *r
= jsval_number(i
);
1326 if(r
) *r
= jsval_number(-1);
1329 jsdisp_release(jsthis
);
1333 static HRESULT
Array_map(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1335 jsval_t context_this
= jsval_undefined();
1336 jsval_t callback_args
[3], mapped_value
;
1337 jsdisp_t
*jsthis
, *array
;
1338 IDispatch
*callback
;
1344 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1346 FIXME("Could not get length\n");
1350 /* FIXME: check IsCallable */
1351 if(!argc
|| !is_object_instance(argv
[0])) {
1352 FIXME("Invalid arg %s\n", debugstr_jsval(argc
? argv
[0] : jsval_undefined()));
1353 hres
= E_INVALIDARG
;
1356 callback
= get_object(argv
[0]);
1359 context_this
= argv
[1];
1361 hres
= create_array(ctx
, 0, &array
);
1365 for(k
= 0; k
< length
; k
++) {
1366 hres
= jsdisp_get_idx(jsthis
, k
, &callback_args
[0]);
1367 if(hres
== DISP_E_UNKNOWNNAME
) {
1374 callback_args
[1] = jsval_number(k
);
1375 callback_args
[2] = jsval_obj(jsthis
);
1376 hres
= disp_call_value(ctx
, callback
, context_this
, DISPATCH_METHOD
, 3, callback_args
, &mapped_value
);
1377 jsval_release(callback_args
[0]);
1381 hres
= jsdisp_propput_idx(array
, k
, mapped_value
);
1386 if(SUCCEEDED(hres
) && r
)
1387 *r
= jsval_obj(array
);
1389 jsdisp_release(array
);
1391 jsdisp_release(jsthis
);
1395 static HRESULT
Array_reduce(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1397 jsval_t callback_args
[4], acc
, new_acc
;
1398 BOOL have_value
= FALSE
;
1399 IDispatch
*callback
;
1406 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1408 FIXME("Could not get length\n");
1412 /* Fixme check IsCallable */
1413 if(!argc
|| !is_object_instance(argv
[0])) {
1414 FIXME("Invalid arg %s\n", debugstr_jsval(argc
? argv
[0] : jsval_undefined()));
1415 hres
= E_INVALIDARG
;
1418 callback
= get_object(argv
[0]);
1422 hres
= jsval_copy(argv
[1], &acc
);
1427 for(k
= 0; k
< length
; k
++) {
1428 hres
= jsdisp_get_idx(jsthis
, k
, &callback_args
[1]);
1429 if(hres
== DISP_E_UNKNOWNNAME
) {
1438 acc
= callback_args
[1];
1442 callback_args
[0] = acc
;
1443 callback_args
[2] = jsval_number(k
);
1444 callback_args
[3] = jsval_obj(jsthis
);
1445 hres
= disp_call_value(ctx
, callback
, jsval_undefined(), DISPATCH_METHOD
, ARRAY_SIZE(callback_args
), callback_args
, &new_acc
);
1446 jsval_release(callback_args
[1]);
1454 if(SUCCEEDED(hres
) && !have_value
) {
1455 WARN("No array element\n");
1456 hres
= JS_E_INVALID_ACTION
;
1459 if(SUCCEEDED(hres
) && r
)
1464 jsdisp_release(jsthis
);
1468 static HRESULT
Array_some(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1471 jsval_t context_this
= jsval_undefined();
1472 jsval_t value
, args
[3], res
;
1473 BOOL boolval
, ret
= FALSE
;
1474 IDispatch
*callback
;
1481 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1485 /* FIXME: check IsCallable */
1486 if(!argc
|| !is_object_instance(argv
[0])) {
1487 FIXME("Invalid arg %s\n", debugstr_jsval(argc
? argv
[0] : jsval_undefined()));
1488 hres
= E_INVALIDARG
;
1491 callback
= get_object(argv
[0]);
1494 context_this
= argv
[1];
1496 for(i
= 0; i
< length
; i
++) {
1497 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1499 if(hres
== DISP_E_UNKNOWNNAME
)
1504 args
[1] = jsval_number(i
);
1505 args
[2] = jsval_obj(jsthis
);
1506 hres
= disp_call_value(ctx
, callback
, context_this
, DISPATCH_METHOD
, ARRAY_SIZE(args
), args
, &res
);
1507 jsval_release(value
);
1511 hres
= to_boolean(res
, &boolval
);
1522 *r
= jsval_bool(ret
);
1525 jsdisp_release(jsthis
);
1529 /* ECMA-262 3rd Edition 15.4.4.13 */
1530 static HRESULT
Array_unshift(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1534 WCHAR buf
[14], *buf_end
, *str
;
1542 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1547 buf_end
= buf
+ ARRAY_SIZE(buf
)-1;
1552 str
= idx_to_str(i
, buf_end
);
1554 hres
= jsdisp_get_id(jsthis
, str
, 0, &id
);
1555 if(SUCCEEDED(hres
)) {
1556 hres
= jsdisp_propget(jsthis
, id
, &val
);
1560 hres
= jsdisp_propput_idx(jsthis
, i
+argc
, val
);
1562 }else if(hres
== DISP_E_UNKNOWNNAME
) {
1563 hres
= IDispatchEx_DeleteMemberByDispID(&jsthis
->IDispatchEx_iface
, id
);
1571 for(i
=0; i
<argc
; i
++) {
1572 hres
= jsdisp_propput_idx(jsthis
, i
, argv
[i
]);
1579 hres
= set_length(jsthis
, length
);
1585 *r
= ctx
->version
< 2 ? jsval_undefined() : jsval_number(length
);
1588 jsdisp_release(jsthis
);
1592 static void Array_destructor(jsdisp_t
*dispex
)
1597 static void Array_on_put(jsdisp_t
*dispex
, const WCHAR
*name
)
1599 ArrayInstance
*array
= array_from_jsdisp(dispex
);
1600 const WCHAR
*ptr
= name
;
1606 while(*ptr
&& is_digit(*ptr
)) {
1607 id
= id
*10 + (*ptr
-'0');
1614 if(id
>= array
->length
)
1615 array
->length
= id
+1;
1618 static const builtin_prop_t Array_props
[] = {
1619 {L
"concat", Array_concat
, PROPF_METHOD
|1},
1620 {L
"every", Array_every
, PROPF_METHOD
|PROPF_ES5
|1},
1621 {L
"filter", Array_filter
, PROPF_METHOD
|PROPF_ES5
|1},
1622 {L
"forEach", Array_forEach
, PROPF_METHOD
|PROPF_ES5
|1},
1623 {L
"indexOf", Array_indexOf
, PROPF_METHOD
|PROPF_ES5
|1},
1624 {L
"join", Array_join
, PROPF_METHOD
|1},
1625 {L
"lastIndexOf", Array_lastIndexOf
, PROPF_METHOD
|PROPF_ES5
|1},
1626 {L
"length", NULL
,0, Array_get_length
, Array_set_length
},
1627 {L
"map", Array_map
, PROPF_METHOD
|PROPF_ES5
|1},
1628 {L
"pop", Array_pop
, PROPF_METHOD
},
1629 {L
"push", Array_push
, PROPF_METHOD
|1},
1630 {L
"reduce", Array_reduce
, PROPF_METHOD
|PROPF_ES5
|1},
1631 {L
"reverse", Array_reverse
, PROPF_METHOD
},
1632 {L
"shift", Array_shift
, PROPF_METHOD
},
1633 {L
"slice", Array_slice
, PROPF_METHOD
|2},
1634 {L
"some", Array_some
, PROPF_METHOD
|PROPF_ES5
|1},
1635 {L
"sort", Array_sort
, PROPF_METHOD
|1},
1636 {L
"splice", Array_splice
, PROPF_METHOD
|2},
1637 {L
"toLocaleString", Array_toLocaleString
, PROPF_METHOD
},
1638 {L
"toString", Array_toString
, PROPF_METHOD
},
1639 {L
"unshift", Array_unshift
, PROPF_METHOD
|1},
1642 static const builtin_info_t Array_info
= {
1645 ARRAY_SIZE(Array_props
),
1651 static const builtin_prop_t ArrayInst_props
[] = {
1652 {L
"length", NULL
,0, Array_get_length
, Array_set_length
}
1655 static const builtin_info_t ArrayInst_info
= {
1658 ARRAY_SIZE(ArrayInst_props
),
1664 /* ECMA-262 5.1 Edition 15.4.3.2 */
1665 static HRESULT
ArrayConstr_isArray(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1671 if(!argc
|| !is_object_instance(argv
[0])) {
1672 if(r
) *r
= jsval_bool(FALSE
);
1676 obj
= to_jsdisp(get_object(argv
[0]));
1677 if(r
) *r
= jsval_bool(obj
&& is_class(obj
, JSCLASS_ARRAY
));
1681 static HRESULT
ArrayConstr_value(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1691 case DISPATCH_METHOD
:
1692 case DISPATCH_CONSTRUCT
: {
1693 if(argc
== 1 && is_number(argv
[0])) {
1694 double n
= get_number(argv
[0]);
1696 if(n
< 0 || !is_int32(n
))
1697 return JS_E_INVALID_LENGTH
;
1701 hres
= create_array(ctx
, n
, &obj
);
1705 *r
= jsval_obj(obj
);
1711 hres
= create_array(ctx
, argc
, &obj
);
1715 for(i
=0; i
< argc
; i
++) {
1716 hres
= jsdisp_propput_idx(obj
, i
, argv
[i
]);
1721 jsdisp_release(obj
);
1725 *r
= jsval_obj(obj
);
1729 FIXME("unimplemented flags: %x\n", flags
);
1736 static HRESULT
alloc_array(script_ctx_t
*ctx
, jsdisp_t
*object_prototype
, ArrayInstance
**ret
)
1738 ArrayInstance
*array
;
1741 array
= calloc(1, sizeof(ArrayInstance
));
1743 return E_OUTOFMEMORY
;
1745 if(object_prototype
)
1746 hres
= init_dispex(&array
->dispex
, ctx
, &Array_info
, object_prototype
);
1748 hres
= init_dispex_from_constr(&array
->dispex
, ctx
, &ArrayInst_info
, ctx
->array_constr
);
1759 static const builtin_prop_t ArrayConstr_props
[] = {
1760 {L
"isArray", ArrayConstr_isArray
, PROPF_ES5
|PROPF_METHOD
|1}
1763 static const builtin_info_t ArrayConstr_info
= {
1766 ARRAY_SIZE(ArrayConstr_props
),
1772 HRESULT
create_array_constr(script_ctx_t
*ctx
, jsdisp_t
*object_prototype
, jsdisp_t
**ret
)
1774 ArrayInstance
*array
;
1777 hres
= alloc_array(ctx
, object_prototype
, &array
);
1781 hres
= create_builtin_constructor(ctx
, ArrayConstr_value
, L
"Array", &ArrayConstr_info
, PROPF_CONSTR
|1, &array
->dispex
, ret
);
1783 jsdisp_release(&array
->dispex
);
1787 HRESULT
create_array(script_ctx_t
*ctx
, DWORD length
, jsdisp_t
**ret
)
1789 ArrayInstance
*array
;
1792 hres
= alloc_array(ctx
, NULL
, &array
);
1796 array
->length
= length
;
1798 *ret
= &array
->dispex
;