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
);
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
, jsval_undefined(), 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
= calloc(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
= malloc(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 jsval_t context_this
= jsval_undefined();
1030 jsval_t value
, args
[3], res
;
1031 BOOL boolval
, ret
= TRUE
;
1032 IDispatch
*callback
;
1039 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
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
;
1049 callback
= get_object(argv
[0]);
1052 context_this
= argv
[1];
1054 for(i
= 0; i
< length
; i
++) {
1055 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1057 if(hres
== DISP_E_UNKNOWNNAME
)
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
);
1069 hres
= to_boolean(res
, &boolval
);
1080 *r
= jsval_bool(ret
);
1083 jsdisp_release(jsthis
);
1087 static HRESULT
Array_filter(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
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
;
1100 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
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
;
1110 callback
= get_object(argv
[0]);
1113 context_this
= argv
[1];
1115 hres
= create_array(ctx
, 0, &arr
);
1119 for(i
= 0; i
< length
; i
++) {
1120 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1122 if(hres
== DISP_E_UNKNOWNNAME
) {
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
);
1135 if(SUCCEEDED(hres
) && boolval
)
1136 hres
= jsdisp_propput_idx(arr
, j
++, value
);
1138 jsval_release(value
);
1144 jsdisp_release(arr
);
1150 *r
= jsval_obj(arr
);
1152 jsdisp_release(jsthis
);
1156 static HRESULT
Array_forEach(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1159 jsval_t context_this
= jsval_undefined();
1160 jsval_t value
, args
[3], res
;
1161 IDispatch
*callback
;
1168 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
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
;
1178 callback
= get_object(argv
[0]);
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
)
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
);
1200 if(r
) *r
= jsval_undefined();
1203 jsdisp_release(jsthis
);
1207 static HRESULT
Array_indexOf(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1211 unsigned length
, i
, from
= 0;
1212 jsval_t search
, value
;
1218 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1222 if(r
) *r
= jsval_number(-1);
1226 search
= argc
? argv
[0] : jsval_undefined();
1231 hres
= to_integer(ctx
, argv
[1], &from_arg
);
1236 from
= min(from_arg
, length
);
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
)
1248 hres
= jsval_strict_equal(value
, search
, &eq
);
1249 jsval_release(value
);
1253 if(r
) *r
= jsval_number(i
);
1258 if(r
) *r
= jsval_number(-1);
1261 jsdisp_release(jsthis
);
1265 static HRESULT
Array_lastIndexOf(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1268 jsval_t search
, value
;
1276 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1282 search
= argc
? argv
[0] : jsval_undefined();
1288 hres
= to_integer(ctx
, argv
[1], &from_arg
);
1293 i
= min(from_arg
, i
);
1303 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1304 if(hres
== DISP_E_UNKNOWNNAME
)
1309 hres
= jsval_strict_equal(value
, search
, &eq
);
1310 jsval_release(value
);
1314 if(r
) *r
= jsval_number(i
);
1320 if(r
) *r
= jsval_number(-1);
1323 jsdisp_release(jsthis
);
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
;
1338 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1340 FIXME("Could not get length\n");
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
;
1350 callback
= get_object(argv
[0]);
1353 context_this
= argv
[1];
1355 hres
= create_array(ctx
, length
, &array
);
1359 for(k
= 0; k
< length
; k
++) {
1360 hres
= jsdisp_get_idx(jsthis
, k
, &callback_args
[0]);
1361 if(hres
== DISP_E_UNKNOWNNAME
)
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]);
1373 hres
= jsdisp_propput_idx(array
, k
, mapped_value
);
1378 if(SUCCEEDED(hres
) && r
)
1379 *r
= jsval_obj(array
);
1381 jsdisp_release(array
);
1383 jsdisp_release(jsthis
);
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
;
1398 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1400 FIXME("Could not get length\n");
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
;
1410 callback
= get_object(argv
[0]);
1414 hres
= jsval_copy(argv
[1], &acc
);
1419 for(k
= 0; k
< length
; k
++) {
1420 hres
= jsdisp_get_idx(jsthis
, k
, &callback_args
[1]);
1421 if(hres
== DISP_E_UNKNOWNNAME
)
1428 acc
= callback_args
[1];
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]);
1444 if(SUCCEEDED(hres
) && !have_value
) {
1445 WARN("No array element\n");
1446 hres
= JS_E_INVALID_ACTION
;
1449 if(SUCCEEDED(hres
) && r
)
1454 jsdisp_release(jsthis
);
1458 static HRESULT
Array_some(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1461 jsval_t context_this
= jsval_undefined();
1462 jsval_t value
, args
[3], res
;
1463 BOOL boolval
, ret
= FALSE
;
1464 IDispatch
*callback
;
1471 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
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
;
1481 callback
= get_object(argv
[0]);
1484 context_this
= argv
[1];
1486 for(i
= 0; i
< length
; i
++) {
1487 hres
= jsdisp_get_idx(jsthis
, i
, &value
);
1489 if(hres
== DISP_E_UNKNOWNNAME
)
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
);
1501 hres
= to_boolean(res
, &boolval
);
1512 *r
= jsval_bool(ret
);
1515 jsdisp_release(jsthis
);
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
,
1524 WCHAR buf
[14], *buf_end
, *str
;
1532 hres
= get_length(ctx
, vthis
, &jsthis
, &length
);
1537 buf_end
= buf
+ ARRAY_SIZE(buf
)-1;
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
);
1550 hres
= jsdisp_propput_idx(jsthis
, i
+argc
, val
);
1552 }else if(hres
== DISP_E_UNKNOWNNAME
) {
1553 hres
= IDispatchEx_DeleteMemberByDispID(&jsthis
->IDispatchEx_iface
, id
);
1561 for(i
=0; i
<argc
; i
++) {
1562 hres
= jsdisp_propput_idx(jsthis
, i
, argv
[i
]);
1569 hres
= set_length(jsthis
, length
);
1575 *r
= ctx
->version
< 2 ? jsval_undefined() : jsval_number(length
);
1578 jsdisp_release(jsthis
);
1582 static void Array_destructor(jsdisp_t
*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
;
1596 while(*ptr
&& is_digit(*ptr
)) {
1597 id
= id
*10 + (*ptr
-'0');
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
= {
1635 ARRAY_SIZE(Array_props
),
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
= {
1648 ARRAY_SIZE(ArrayInst_props
),
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
)
1661 if(!argc
|| !is_object_instance(argv
[0])) {
1662 if(r
) *r
= jsval_bool(FALSE
);
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
);
1672 static HRESULT
ArrayConstr_value(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
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
;
1692 hres
= create_array(ctx
, n
, &obj
);
1696 *r
= jsval_obj(obj
);
1702 hres
= create_array(ctx
, argc
, &obj
);
1706 for(i
=0; i
< argc
; i
++) {
1707 hres
= jsdisp_propput_idx(obj
, i
, argv
[i
]);
1712 jsdisp_release(obj
);
1716 *r
= jsval_obj(obj
);
1720 FIXME("unimplemented flags: %x\n", flags
);
1727 static HRESULT
alloc_array(script_ctx_t
*ctx
, jsdisp_t
*object_prototype
, ArrayInstance
**ret
)
1729 ArrayInstance
*array
;
1732 array
= calloc(1, sizeof(ArrayInstance
));
1734 return E_OUTOFMEMORY
;
1736 if(object_prototype
)
1737 hres
= init_dispex(&array
->dispex
, ctx
, &Array_info
, object_prototype
);
1739 hres
= init_dispex_from_constr(&array
->dispex
, ctx
, &ArrayInst_info
, ctx
->array_constr
);
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
= {
1757 ARRAY_SIZE(ArrayConstr_props
),
1763 HRESULT
create_array_constr(script_ctx_t
*ctx
, jsdisp_t
*object_prototype
, jsdisp_t
**ret
)
1765 ArrayInstance
*array
;
1768 hres
= alloc_array(ctx
, object_prototype
, &array
);
1772 hres
= create_builtin_constructor(ctx
, ArrayConstr_value
, L
"Array", &ArrayConstr_info
, PROPF_CONSTR
|1, &array
->dispex
, ret
);
1774 jsdisp_release(&array
->dispex
);
1778 HRESULT
create_array(script_ctx_t
*ctx
, DWORD length
, jsdisp_t
**ret
)
1780 ArrayInstance
*array
;
1783 hres
= alloc_array(ctx
, NULL
, &array
);
1787 array
->length
= length
;
1789 *ret
= &array
->dispex
;