2 * Copyright 2011 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
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript
);
27 static DISPID propput_dispid
= DISPID_PROPERTYPUT
;
39 dynamic_var_t
*dynamic_vars
;
51 typedef HRESULT (*instr_func_t
)(exec_ctx_t
*);
81 static BOOL
lookup_dynamic_vars(dynamic_var_t
*var
, const WCHAR
*name
, ref_t
*ref
)
84 if(!strcmpiW(var
->name
, name
)) {
85 ref
->type
= var
->is_const
? REF_CONST
: REF_VAR
;
96 static HRESULT
lookup_identifier(exec_ctx_t
*ctx
, BSTR name
, vbdisp_invoke_type_t invoke_type
, ref_t
*ref
)
104 static const WCHAR errW
[] = {'e','r','r',0};
106 if(invoke_type
== VBDISP_LET
107 && (ctx
->func
->type
== FUNC_FUNCTION
|| ctx
->func
->type
== FUNC_PROPGET
|| ctx
->func
->type
== FUNC_DEFGET
)
108 && !strcmpiW(name
, ctx
->func
->name
)) {
110 ref
->u
.v
= &ctx
->ret_val
;
114 for(i
=0; i
< ctx
->func
->var_cnt
; i
++) {
115 if(!strcmpiW(ctx
->func
->vars
[i
].name
, name
)) {
117 ref
->u
.v
= ctx
->vars
+i
;
122 for(i
=0; i
< ctx
->func
->arg_cnt
; i
++) {
123 if(!strcmpiW(ctx
->func
->args
[i
].name
, name
)) {
125 ref
->u
.v
= ctx
->args
+i
;
130 if(lookup_dynamic_vars(ctx
->func
->type
== FUNC_GLOBAL
? ctx
->script
->global_vars
: ctx
->dynamic_vars
, name
, ref
))
133 if(ctx
->func
->type
!= FUNC_GLOBAL
) {
134 hres
= disp_get_id(ctx
->this_obj
, name
, invoke_type
, TRUE
, &id
);
135 if(SUCCEEDED(hres
)) {
136 ref
->type
= REF_DISP
;
137 ref
->u
.d
.disp
= ctx
->this_obj
;
143 if(ctx
->func
->type
!= FUNC_GLOBAL
&& lookup_dynamic_vars(ctx
->script
->global_vars
, name
, ref
))
146 for(func
= ctx
->script
->global_funcs
; func
; func
= func
->next
) {
147 if(!strcmpiW(func
->name
, name
)) {
148 ref
->type
= REF_FUNC
;
154 if(!strcmpiW(name
, errW
)) {
156 ref
->u
.obj
= (IDispatch
*)&ctx
->script
->err_obj
->IDispatchEx_iface
;
160 hres
= vbdisp_get_id(ctx
->script
->global_obj
, name
, invoke_type
, TRUE
, &id
);
161 if(SUCCEEDED(hres
)) {
162 ref
->type
= REF_DISP
;
163 ref
->u
.d
.disp
= (IDispatch
*)&ctx
->script
->global_obj
->IDispatchEx_iface
;
168 LIST_FOR_EACH_ENTRY(item
, &ctx
->script
->named_items
, named_item_t
, entry
) {
169 if((item
->flags
& SCRIPTITEM_ISVISIBLE
) && !strcmpiW(item
->name
, name
)) {
173 hres
= IActiveScriptSite_GetItemInfo(ctx
->script
->site
, name
, SCRIPTINFO_IUNKNOWN
, &unk
, NULL
);
175 WARN("GetItemInfo failed: %08x\n", hres
);
179 hres
= IUnknown_QueryInterface(unk
, &IID_IDispatch
, (void**)&item
->disp
);
180 IUnknown_Release(unk
);
182 WARN("object does not implement IDispatch\n");
188 ref
->u
.obj
= item
->disp
;
193 LIST_FOR_EACH_ENTRY(item
, &ctx
->script
->named_items
, named_item_t
, entry
) {
194 if((item
->flags
& SCRIPTITEM_GLOBALMEMBERS
)) {
195 hres
= disp_get_id(item
->disp
, name
, invoke_type
, FALSE
, &id
);
196 if(SUCCEEDED(hres
)) {
197 ref
->type
= REF_DISP
;
198 ref
->u
.d
.disp
= item
->disp
;
205 ref
->type
= REF_NONE
;
209 static HRESULT
add_dynamic_var(exec_ctx_t
*ctx
, const WCHAR
*name
,
210 BOOL is_const
, VARIANT
*val
, BOOL own_val
, VARIANT
**out_var
)
212 dynamic_var_t
*new_var
;
218 heap
= ctx
->func
->type
== FUNC_GLOBAL
? &ctx
->script
->heap
: &ctx
->heap
;
220 new_var
= heap_pool_alloc(heap
, sizeof(*new_var
));
222 return E_OUTOFMEMORY
;
224 size
= (strlenW(name
)+1)*sizeof(WCHAR
);
225 str
= heap_pool_alloc(heap
, size
);
227 return E_OUTOFMEMORY
;
228 memcpy(str
, name
, size
);
230 new_var
->is_const
= is_const
;
235 V_VT(&new_var
->v
) = VT_EMPTY
;
236 hres
= VariantCopy(&new_var
->v
, val
);
241 if(ctx
->func
->type
== FUNC_GLOBAL
) {
242 new_var
->next
= ctx
->script
->global_vars
;
243 ctx
->script
->global_vars
= new_var
;
245 new_var
->next
= ctx
->dynamic_vars
;
246 ctx
->dynamic_vars
= new_var
;
250 *out_var
= &new_var
->v
;
255 static inline VARIANT
*stack_pop(exec_ctx_t
*ctx
)
258 return ctx
->stack
+ --ctx
->top
;
261 static inline VARIANT
*stack_top(exec_ctx_t
*ctx
, unsigned n
)
263 assert(ctx
->top
>= n
);
264 return ctx
->stack
+ (ctx
->top
-n
-1);
267 static HRESULT
stack_push(exec_ctx_t
*ctx
, VARIANT
*v
)
269 if(ctx
->stack_size
== ctx
->top
) {
272 new_stack
= heap_realloc(ctx
->stack
, ctx
->stack_size
*2*sizeof(*ctx
->stack
));
275 return E_OUTOFMEMORY
;
278 ctx
->stack
= new_stack
;
279 ctx
->stack_size
*= 2;
282 ctx
->stack
[ctx
->top
++] = *v
;
286 static inline HRESULT
stack_push_null(exec_ctx_t
*ctx
)
290 return stack_push(ctx
, &v
);
293 static void stack_popn(exec_ctx_t
*ctx
, unsigned n
)
296 VariantClear(stack_pop(ctx
));
299 static HRESULT
stack_pop_val(exec_ctx_t
*ctx
, variant_val_t
*v
)
303 var
= stack_pop(ctx
);
305 if(V_VT(var
) == (VT_BYREF
|VT_VARIANT
)) {
307 var
= V_VARIANTREF(var
);
312 if(V_VT(var
) == VT_DISPATCH
) {
316 hres
= disp_call(ctx
->script
, V_DISPATCH(var
), DISPID_VALUE
, &dp
, &v
->store
);
318 IDispatch_Release(V_DISPATCH(var
));
331 static HRESULT
stack_assume_val(exec_ctx_t
*ctx
, unsigned n
)
333 VARIANT
*v
= stack_top(ctx
, n
);
336 if(V_VT(v
) == (VT_BYREF
|VT_VARIANT
)) {
337 VARIANT
*ref
= V_VARIANTREF(v
);
340 hres
= VariantCopy(v
, ref
);
345 if(V_VT(v
) == VT_DISPATCH
) {
349 disp
= V_DISPATCH(v
);
351 hres
= disp_call(ctx
->script
, disp
, DISPID_VALUE
, &dp
, v
);
352 IDispatch_Release(disp
);
360 static inline void release_val(variant_val_t
*v
)
366 static int stack_pop_bool(exec_ctx_t
*ctx
, BOOL
*b
)
371 hres
= stack_pop_val(ctx
, &val
);
390 FIXME("unsupported for %s\n", debugstr_variant(val
.v
));
397 static HRESULT
stack_pop_disp(exec_ctx_t
*ctx
, IDispatch
**ret
)
399 VARIANT
*v
= stack_pop(ctx
);
401 if(V_VT(v
) == VT_DISPATCH
) {
402 *ret
= V_DISPATCH(v
);
406 if(V_VT(v
) != (VT_VARIANT
|VT_BYREF
)) {
407 FIXME("not supported type: %s\n", debugstr_variant(v
));
413 if(V_VT(v
) != VT_DISPATCH
) {
414 FIXME("not disp %s\n", debugstr_variant(v
));
419 IDispatch_AddRef(V_DISPATCH(v
));
420 *ret
= V_DISPATCH(v
);
424 static HRESULT
stack_assume_disp(exec_ctx_t
*ctx
, unsigned n
, IDispatch
**disp
)
426 VARIANT
*v
= stack_top(ctx
, n
), *ref
;
428 if(V_VT(v
) != VT_DISPATCH
) {
429 if(V_VT(v
) != (VT_VARIANT
|VT_BYREF
)) {
430 FIXME("not supported type: %s\n", debugstr_variant(v
));
434 ref
= V_VARIANTREF(v
);
435 if(V_VT(ref
) != VT_DISPATCH
) {
436 FIXME("not disp %s\n", debugstr_variant(ref
));
440 V_VT(v
) = VT_DISPATCH
;
441 V_DISPATCH(v
) = V_DISPATCH(ref
);
443 IDispatch_AddRef(V_DISPATCH(v
));
447 *disp
= V_DISPATCH(v
);
451 static inline void instr_jmp(exec_ctx_t
*ctx
, unsigned addr
)
453 ctx
->instr
= ctx
->code
->instrs
+ addr
;
456 static void vbstack_to_dp(exec_ctx_t
*ctx
, unsigned arg_cnt
, BOOL is_propput
, DISPPARAMS
*dp
)
458 dp
->cNamedArgs
= is_propput
? 1 : 0;
459 dp
->cArgs
= arg_cnt
+ dp
->cNamedArgs
;
460 dp
->rgdispidNamedArgs
= is_propput
? &propput_dispid
: NULL
;
466 assert(ctx
->top
>= arg_cnt
);
468 for(i
=1; i
*2 <= arg_cnt
; i
++) {
469 tmp
= ctx
->stack
[ctx
->top
-i
];
470 ctx
->stack
[ctx
->top
-i
] = ctx
->stack
[ctx
->top
-arg_cnt
+i
-1];
471 ctx
->stack
[ctx
->top
-arg_cnt
+i
-1] = tmp
;
474 dp
->rgvarg
= ctx
->stack
+ ctx
->top
-dp
->cArgs
;
476 dp
->rgvarg
= is_propput
? ctx
->stack
+ctx
->top
-1 : NULL
;
480 static HRESULT
do_icall(exec_ctx_t
*ctx
, VARIANT
*res
)
482 BSTR identifier
= ctx
->instr
->arg1
.bstr
;
483 const unsigned arg_cnt
= ctx
->instr
->arg2
.uint
;
488 hres
= lookup_identifier(ctx
, identifier
, VBDISP_CALLGET
, &ref
);
492 vbstack_to_dp(ctx
, arg_cnt
, FALSE
, &dp
);
498 FIXME("REF_VAR no res\n");
503 FIXME("arguments not implemented\n");
507 V_VT(res
) = VT_BYREF
|VT_VARIANT
;
508 V_BYREF(res
) = V_VT(ref
.u
.v
) == (VT_VARIANT
|VT_BYREF
) ? V_VARIANTREF(ref
.u
.v
) : ref
.u
.v
;
511 hres
= disp_call(ctx
->script
, ref
.u
.d
.disp
, ref
.u
.d
.id
, &dp
, res
);
516 hres
= exec_script(ctx
->script
, ref
.u
.f
, NULL
, &dp
, res
);
522 FIXME("arguments on object\n");
527 IDispatch_AddRef(ref
.u
.obj
);
528 V_VT(res
) = VT_DISPATCH
;
529 V_DISPATCH(res
) = ref
.u
.obj
;
533 if(res
&& !ctx
->func
->code_ctx
->option_explicit
&& arg_cnt
== 0) {
536 hres
= add_dynamic_var(ctx
, identifier
, FALSE
, &v
, FALSE
, &new);
539 V_VT(res
) = VT_BYREF
|VT_VARIANT
;
543 FIXME("%s not found\n", debugstr_w(identifier
));
544 return DISP_E_UNKNOWNNAME
;
547 stack_popn(ctx
, arg_cnt
);
551 static HRESULT
interp_icall(exec_ctx_t
*ctx
)
558 hres
= do_icall(ctx
, &v
);
562 return stack_push(ctx
, &v
);
565 static HRESULT
interp_icallv(exec_ctx_t
*ctx
)
568 return do_icall(ctx
, NULL
);
571 static HRESULT
do_mcall(exec_ctx_t
*ctx
, VARIANT
*res
)
573 const BSTR identifier
= ctx
->instr
->arg1
.bstr
;
574 const unsigned arg_cnt
= ctx
->instr
->arg2
.uint
;
580 hres
= stack_pop_disp(ctx
, &obj
);
589 vbstack_to_dp(ctx
, arg_cnt
, FALSE
, &dp
);
591 hres
= disp_get_id(obj
, identifier
, VBDISP_CALLGET
, FALSE
, &id
);
593 hres
= disp_call(ctx
->script
, obj
, id
, &dp
, res
);
594 IDispatch_Release(obj
);
598 stack_popn(ctx
, arg_cnt
);
602 static HRESULT
interp_mcall(exec_ctx_t
*ctx
)
609 hres
= do_mcall(ctx
, &res
);
613 return stack_push(ctx
, &res
);
616 static HRESULT
interp_mcallv(exec_ctx_t
*ctx
)
620 return do_mcall(ctx
, NULL
);
623 static HRESULT
assign_ident(exec_ctx_t
*ctx
, BSTR name
, DISPPARAMS
*dp
)
628 hres
= lookup_identifier(ctx
, name
, VBDISP_LET
, &ref
);
634 VARIANT
*v
= ref
.u
.v
;
637 FIXME("arg_cnt %d not supported\n", arg_cnt(dp
));
641 if(V_VT(v
) == (VT_VARIANT
|VT_BYREF
))
644 hres
= VariantCopy(v
, dp
->rgvarg
);
648 hres
= disp_propput(ctx
->script
, ref
.u
.d
.disp
, ref
.u
.d
.id
, dp
);
651 FIXME("functions not implemented\n");
657 FIXME("REF_CONST\n");
660 if(ctx
->func
->code_ctx
->option_explicit
) {
661 FIXME("throw exception\n");
665 FIXME("arg_cnt %d not supported\n", arg_cnt(dp
));
669 TRACE("creating variable %s\n", debugstr_w(name
));
670 hres
= add_dynamic_var(ctx
, name
, FALSE
, dp
->rgvarg
, FALSE
, NULL
);
677 static HRESULT
interp_assign_ident(exec_ctx_t
*ctx
)
679 const BSTR arg
= ctx
->instr
->arg1
.bstr
;
680 const unsigned arg_cnt
= ctx
->instr
->arg2
.uint
;
684 TRACE("%s\n", debugstr_w(arg
));
686 hres
= stack_assume_val(ctx
, arg_cnt
);
690 vbstack_to_dp(ctx
, arg_cnt
, TRUE
, &dp
);
691 hres
= assign_ident(ctx
, arg
, &dp
);
695 stack_popn(ctx
, arg_cnt
+1);
699 static HRESULT
interp_set_ident(exec_ctx_t
*ctx
)
701 const BSTR arg
= ctx
->instr
->arg1
.bstr
;
702 const unsigned arg_cnt
= ctx
->instr
->arg2
.uint
;
706 TRACE("%s\n", debugstr_w(arg
));
709 FIXME("arguments not supported\n");
713 hres
= stack_assume_disp(ctx
, 0, NULL
);
717 vbstack_to_dp(ctx
, 0, TRUE
, &dp
);
718 hres
= assign_ident(ctx
, ctx
->instr
->arg1
.bstr
, &dp
);
726 static HRESULT
interp_assign_member(exec_ctx_t
*ctx
)
728 BSTR identifier
= ctx
->instr
->arg1
.bstr
;
729 const unsigned arg_cnt
= ctx
->instr
->arg2
.uint
;
735 TRACE("%s\n", debugstr_w(identifier
));
737 hres
= stack_assume_disp(ctx
, arg_cnt
+1, &obj
);
746 hres
= stack_assume_val(ctx
, arg_cnt
);
750 hres
= disp_get_id(obj
, identifier
, VBDISP_LET
, FALSE
, &id
);
751 if(SUCCEEDED(hres
)) {
752 vbstack_to_dp(ctx
, arg_cnt
, TRUE
, &dp
);
753 hres
= disp_propput(ctx
->script
, obj
, id
, &dp
);
758 stack_popn(ctx
, arg_cnt
+2);
762 static HRESULT
interp_set_member(exec_ctx_t
*ctx
)
764 BSTR identifier
= ctx
->instr
->arg1
.bstr
;
765 const unsigned arg_cnt
= ctx
->instr
->arg2
.uint
;
771 TRACE("%s\n", debugstr_w(identifier
));
774 FIXME("arguments not supported\n");
778 hres
= stack_assume_disp(ctx
, 1, &obj
);
787 hres
= stack_assume_disp(ctx
, 0, NULL
);
791 hres
= disp_get_id(obj
, identifier
, VBDISP_SET
, FALSE
, &id
);
792 if(SUCCEEDED(hres
)) {
793 vbstack_to_dp(ctx
, arg_cnt
, TRUE
, &dp
);
794 hres
= disp_propput(ctx
->script
, obj
, id
, &dp
);
803 static HRESULT
interp_const(exec_ctx_t
*ctx
)
805 BSTR arg
= ctx
->instr
->arg1
.bstr
;
810 TRACE("%s\n", debugstr_w(arg
));
812 assert(ctx
->func
->type
== FUNC_GLOBAL
);
814 hres
= lookup_identifier(ctx
, arg
, VBDISP_CALLGET
, &ref
);
818 if(ref
.type
!= REF_NONE
) {
819 FIXME("%s already defined\n", debugstr_w(arg
));
823 hres
= stack_pop_val(ctx
, &val
);
827 return add_dynamic_var(ctx
, arg
, TRUE
, val
.v
, val
.owned
, NULL
);
830 static HRESULT
interp_val(exec_ctx_t
*ctx
)
838 hres
= stack_pop_val(ctx
, &val
);
844 hres
= VariantCopy(&v
, val
.v
);
849 return stack_push(ctx
, val
.owned
? val
.v
: &v
);
852 static HRESULT
interp_pop(exec_ctx_t
*ctx
)
854 const unsigned n
= ctx
->instr
->arg1
.uint
;
862 static HRESULT
interp_new(exec_ctx_t
*ctx
)
864 const WCHAR
*arg
= ctx
->instr
->arg1
.bstr
;
865 class_desc_t
*class_desc
;
870 TRACE("%s\n", debugstr_w(arg
));
872 for(class_desc
= ctx
->script
->classes
; class_desc
; class_desc
= class_desc
->next
) {
873 if(!strcmpiW(class_desc
->name
, arg
))
877 FIXME("Class %s not found\n", debugstr_w(arg
));
881 hres
= create_vbdisp(class_desc
, &obj
);
885 V_VT(&v
) = VT_DISPATCH
;
886 V_DISPATCH(&v
) = (IDispatch
*)&obj
->IDispatchEx_iface
;
887 return stack_push(ctx
, &v
);
890 static HRESULT
interp_step(exec_ctx_t
*ctx
)
892 const BSTR ident
= ctx
->instr
->arg2
.bstr
;
898 TRACE("%s\n", debugstr_w(ident
));
902 hres
= VarCmp(stack_top(ctx
, 0), &zero
, ctx
->script
->lcid
, 0);
906 gteq_zero
= hres
== VARCMP_GT
|| hres
== VARCMP_EQ
;
908 hres
= lookup_identifier(ctx
, ident
, VBDISP_ANY
, &ref
);
912 if(ref
.type
!= REF_VAR
) {
913 FIXME("%s is not REF_VAR\n", debugstr_w(ident
));
917 hres
= VarCmp(ref
.u
.v
, stack_top(ctx
, 1), ctx
->script
->lcid
, 0);
921 if(hres
== VARCMP_EQ
|| hres
== (gteq_zero
? VARCMP_LT
: VARCMP_GT
)) {
925 instr_jmp(ctx
, ctx
->instr
->arg1
.uint
);
930 static HRESULT
interp_newenum(exec_ctx_t
*ctx
)
944 hres
= disp_call(ctx
->script
, V_DISPATCH(v
), DISPID_NEWENUM
, &dp
, &iterv
);
949 if(V_VT(&iterv
) != VT_UNKNOWN
&& V_VT(&iterv
) != VT_DISPATCH
) {
950 FIXME("Unsupported iterv %s\n", debugstr_variant(&iterv
));
951 VariantClear(&iterv
);
955 hres
= IUnknown_QueryInterface(V_UNKNOWN(&iterv
), &IID_IEnumVARIANT
, (void**)&iter
);
956 IUnknown_Release(V_UNKNOWN(&iterv
));
958 FIXME("Could not get IEnumVARIANT iface: %08x\n", hres
);
962 V_VT(&r
) = VT_UNKNOWN
;
963 V_UNKNOWN(&r
) = (IUnknown
*)iter
;
967 FIXME("Unsupported for %s\n", debugstr_variant(v
));
972 return stack_push(ctx
, &r
);
975 static HRESULT
interp_enumnext(exec_ctx_t
*ctx
)
977 const unsigned loop_end
= ctx
->instr
->arg1
.uint
;
978 const BSTR ident
= ctx
->instr
->arg2
.bstr
;
980 DISPPARAMS dp
= {&v
, &propput_dispid
, 1, 1};
987 assert(V_VT(stack_top(ctx
, 0)) == VT_UNKNOWN
);
988 iter
= (IEnumVARIANT
*)V_UNKNOWN(stack_top(ctx
, 0));
991 hres
= IEnumVARIANT_Next(iter
, 1, &v
, NULL
);
995 do_continue
= hres
== S_OK
;
996 hres
= assign_ident(ctx
, ident
, &dp
);
1005 instr_jmp(ctx
, loop_end
);
1010 static HRESULT
interp_jmp(exec_ctx_t
*ctx
)
1012 const unsigned arg
= ctx
->instr
->arg1
.uint
;
1016 instr_jmp(ctx
, arg
);
1020 static HRESULT
interp_jmp_false(exec_ctx_t
*ctx
)
1022 const unsigned arg
= ctx
->instr
->arg1
.uint
;
1028 hres
= stack_pop_bool(ctx
, &b
);
1035 instr_jmp(ctx
, ctx
->instr
->arg1
.uint
);
1039 static HRESULT
interp_jmp_true(exec_ctx_t
*ctx
)
1041 const unsigned arg
= ctx
->instr
->arg1
.uint
;
1047 hres
= stack_pop_bool(ctx
, &b
);
1052 instr_jmp(ctx
, ctx
->instr
->arg1
.uint
);
1058 static HRESULT
interp_ret(exec_ctx_t
*ctx
)
1066 static HRESULT
interp_stop(exec_ctx_t
*ctx
)
1070 /* NOTE: this should have effect in debugging mode (that we don't support yet) */
1074 static HRESULT
interp_me(exec_ctx_t
*ctx
)
1080 IDispatch_AddRef(ctx
->this_obj
);
1081 V_VT(&v
) = VT_DISPATCH
;
1082 V_DISPATCH(&v
) = ctx
->this_obj
;
1083 return stack_push(ctx
, &v
);
1086 static HRESULT
interp_bool(exec_ctx_t
*ctx
)
1088 const VARIANT_BOOL arg
= ctx
->instr
->arg1
.lng
;
1091 TRACE("%s\n", arg
? "true" : "false");
1095 return stack_push(ctx
, &v
);
1098 static HRESULT
interp_errmode(exec_ctx_t
*ctx
)
1100 const int err_mode
= ctx
->instr
->arg1
.uint
;
1102 TRACE("%d\n", err_mode
);
1104 ctx
->resume_next
= err_mode
;
1108 static HRESULT
interp_string(exec_ctx_t
*ctx
)
1115 V_BSTR(&v
) = SysAllocString(ctx
->instr
->arg1
.str
);
1117 return E_OUTOFMEMORY
;
1119 return stack_push(ctx
, &v
);
1122 static HRESULT
interp_long(exec_ctx_t
*ctx
)
1124 const LONG arg
= ctx
->instr
->arg1
.lng
;
1131 return stack_push(ctx
, &v
);
1134 static HRESULT
interp_short(exec_ctx_t
*ctx
)
1136 const LONG arg
= ctx
->instr
->arg1
.lng
;
1143 return stack_push(ctx
, &v
);
1146 static HRESULT
interp_double(exec_ctx_t
*ctx
)
1148 const DOUBLE
*arg
= ctx
->instr
->arg1
.dbl
;
1151 TRACE("%lf\n", *arg
);
1155 return stack_push(ctx
, &v
);
1158 static HRESULT
interp_empty(exec_ctx_t
*ctx
)
1164 V_VT(&v
) = VT_EMPTY
;
1165 return stack_push(ctx
, &v
);
1168 static HRESULT
interp_null(exec_ctx_t
*ctx
)
1171 return stack_push_null(ctx
);
1174 static HRESULT
interp_nothing(exec_ctx_t
*ctx
)
1180 V_VT(&v
) = VT_DISPATCH
;
1181 V_DISPATCH(&v
) = NULL
;
1182 return stack_push(ctx
, &v
);
1185 static HRESULT
interp_not(exec_ctx_t
*ctx
)
1193 hres
= stack_pop_val(ctx
, &val
);
1197 hres
= VarNot(val
.v
, &v
);
1202 return stack_push(ctx
, &v
);
1205 static HRESULT
interp_and(exec_ctx_t
*ctx
)
1213 hres
= stack_pop_val(ctx
, &r
);
1217 hres
= stack_pop_val(ctx
, &l
);
1218 if(SUCCEEDED(hres
)) {
1219 hres
= VarAnd(l
.v
, r
.v
, &v
);
1226 return stack_push(ctx
, &v
);
1229 static HRESULT
interp_or(exec_ctx_t
*ctx
)
1237 hres
= stack_pop_val(ctx
, &r
);
1241 hres
= stack_pop_val(ctx
, &l
);
1242 if(SUCCEEDED(hres
)) {
1243 hres
= VarOr(l
.v
, r
.v
, &v
);
1250 return stack_push(ctx
, &v
);
1253 static HRESULT
interp_xor(exec_ctx_t
*ctx
)
1261 hres
= stack_pop_val(ctx
, &r
);
1265 hres
= stack_pop_val(ctx
, &l
);
1266 if(SUCCEEDED(hres
)) {
1267 hres
= VarXor(l
.v
, r
.v
, &v
);
1274 return stack_push(ctx
, &v
);
1277 static HRESULT
interp_eqv(exec_ctx_t
*ctx
)
1285 hres
= stack_pop_val(ctx
, &r
);
1289 hres
= stack_pop_val(ctx
, &l
);
1290 if(SUCCEEDED(hres
)) {
1291 hres
= VarEqv(l
.v
, r
.v
, &v
);
1298 return stack_push(ctx
, &v
);
1301 static HRESULT
interp_imp(exec_ctx_t
*ctx
)
1309 hres
= stack_pop_val(ctx
, &r
);
1313 hres
= stack_pop_val(ctx
, &l
);
1314 if(SUCCEEDED(hres
)) {
1315 hres
= VarImp(l
.v
, r
.v
, &v
);
1322 return stack_push(ctx
, &v
);
1325 static HRESULT
var_cmp(exec_ctx_t
*ctx
, VARIANT
*l
, VARIANT
*r
)
1327 TRACE("%s %s\n", debugstr_variant(l
), debugstr_variant(r
));
1329 /* FIXME: Fix comparing string to number */
1331 return VarCmp(l
, r
, ctx
->script
->lcid
, 0);
1334 static HRESULT
cmp_oper(exec_ctx_t
*ctx
)
1339 hres
= stack_pop_val(ctx
, &r
);
1343 hres
= stack_pop_val(ctx
, &l
);
1344 if(SUCCEEDED(hres
)) {
1345 hres
= var_cmp(ctx
, l
.v
, r
.v
);
1353 static HRESULT
interp_equal(exec_ctx_t
*ctx
)
1360 hres
= cmp_oper(ctx
);
1363 if(hres
== VARCMP_NULL
)
1364 return stack_push_null(ctx
);
1367 V_BOOL(&v
) = hres
== VARCMP_EQ
? VARIANT_TRUE
: VARIANT_FALSE
;
1368 return stack_push(ctx
, &v
);
1371 static HRESULT
interp_nequal(exec_ctx_t
*ctx
)
1378 hres
= cmp_oper(ctx
);
1381 if(hres
== VARCMP_NULL
)
1382 return stack_push_null(ctx
);
1385 V_BOOL(&v
) = hres
!= VARCMP_EQ
? VARIANT_TRUE
: VARIANT_FALSE
;
1386 return stack_push(ctx
, &v
);
1389 static HRESULT
interp_gt(exec_ctx_t
*ctx
)
1396 hres
= cmp_oper(ctx
);
1399 if(hres
== VARCMP_NULL
)
1400 return stack_push_null(ctx
);
1403 V_BOOL(&v
) = hres
== VARCMP_GT
? VARIANT_TRUE
: VARIANT_FALSE
;
1404 return stack_push(ctx
, &v
);
1407 static HRESULT
interp_gteq(exec_ctx_t
*ctx
)
1414 hres
= cmp_oper(ctx
);
1417 if(hres
== VARCMP_NULL
)
1418 return stack_push_null(ctx
);
1421 V_BOOL(&v
) = hres
== VARCMP_GT
|| hres
== VARCMP_EQ
? VARIANT_TRUE
: VARIANT_FALSE
;
1422 return stack_push(ctx
, &v
);
1425 static HRESULT
interp_lt(exec_ctx_t
*ctx
)
1432 hres
= cmp_oper(ctx
);
1435 if(hres
== VARCMP_NULL
)
1436 return stack_push_null(ctx
);
1439 V_BOOL(&v
) = hres
== VARCMP_LT
? VARIANT_TRUE
: VARIANT_FALSE
;
1440 return stack_push(ctx
, &v
);
1443 static HRESULT
interp_lteq(exec_ctx_t
*ctx
)
1450 hres
= cmp_oper(ctx
);
1453 if(hres
== VARCMP_NULL
)
1454 return stack_push_null(ctx
);
1457 V_BOOL(&v
) = hres
== VARCMP_LT
|| hres
== VARCMP_EQ
? VARIANT_TRUE
: VARIANT_FALSE
;
1458 return stack_push(ctx
, &v
);
1461 static HRESULT
interp_case(exec_ctx_t
*ctx
)
1463 const unsigned arg
= ctx
->instr
->arg1
.uint
;
1469 hres
= stack_pop_val(ctx
, &v
);
1473 hres
= var_cmp(ctx
, stack_top(ctx
, 0), v
.v
);
1478 if(hres
== VARCMP_EQ
) {
1480 instr_jmp(ctx
, arg
);
1488 static HRESULT
disp_cmp(IDispatch
*disp1
, IDispatch
*disp2
, VARIANT_BOOL
*ret
)
1490 IObjectIdentity
*identity
;
1491 IUnknown
*unk1
, *unk2
;
1494 if(disp1
== disp2
) {
1495 *ret
= VARIANT_TRUE
;
1499 if(!disp1
|| !disp2
) {
1500 *ret
= VARIANT_FALSE
;
1504 hres
= IDispatch_QueryInterface(disp1
, &IID_IUnknown
, (void**)&unk1
);
1508 hres
= IDispatch_QueryInterface(disp2
, &IID_IUnknown
, (void**)&unk2
);
1510 IUnknown_Release(unk1
);
1515 *ret
= VARIANT_TRUE
;
1517 hres
= IUnknown_QueryInterface(unk1
, &IID_IObjectIdentity
, (void**)&identity
);
1518 if(SUCCEEDED(hres
)) {
1519 hres
= IObjectIdentity_IsEqualObject(identity
, unk2
);
1520 IObjectIdentity_Release(identity
);
1521 *ret
= hres
== S_OK
? VARIANT_TRUE
: VARIANT_FALSE
;
1523 *ret
= VARIANT_FALSE
;
1527 IUnknown_Release(unk1
);
1528 IUnknown_Release(unk2
);
1532 static HRESULT
interp_is(exec_ctx_t
*ctx
)
1540 hres
= stack_pop_disp(ctx
, &r
);
1544 hres
= stack_pop_disp(ctx
, &l
);
1545 if(SUCCEEDED(hres
)) {
1547 hres
= disp_cmp(l
, r
, &V_BOOL(&v
));
1549 IDispatch_Release(l
);
1552 IDispatch_Release(r
);
1556 return stack_push(ctx
, &v
);
1559 static HRESULT
interp_concat(exec_ctx_t
*ctx
)
1567 hres
= stack_pop_val(ctx
, &r
);
1571 hres
= stack_pop_val(ctx
, &l
);
1572 if(SUCCEEDED(hres
)) {
1573 hres
= VarCat(l
.v
, r
.v
, &v
);
1580 return stack_push(ctx
, &v
);
1583 static HRESULT
interp_add(exec_ctx_t
*ctx
)
1591 hres
= stack_pop_val(ctx
, &r
);
1595 hres
= stack_pop_val(ctx
, &l
);
1596 if(SUCCEEDED(hres
)) {
1597 hres
= VarAdd(l
.v
, r
.v
, &v
);
1604 return stack_push(ctx
, &v
);
1607 static HRESULT
interp_sub(exec_ctx_t
*ctx
)
1615 hres
= stack_pop_val(ctx
, &r
);
1619 hres
= stack_pop_val(ctx
, &l
);
1620 if(SUCCEEDED(hres
)) {
1621 hres
= VarSub(l
.v
, r
.v
, &v
);
1628 return stack_push(ctx
, &v
);
1631 static HRESULT
interp_mod(exec_ctx_t
*ctx
)
1639 hres
= stack_pop_val(ctx
, &r
);
1643 hres
= stack_pop_val(ctx
, &l
);
1644 if(SUCCEEDED(hres
)) {
1645 hres
= VarMod(l
.v
, r
.v
, &v
);
1652 return stack_push(ctx
, &v
);
1655 static HRESULT
interp_idiv(exec_ctx_t
*ctx
)
1663 hres
= stack_pop_val(ctx
, &r
);
1667 hres
= stack_pop_val(ctx
, &l
);
1668 if(SUCCEEDED(hres
)) {
1669 hres
= VarIdiv(l
.v
, r
.v
, &v
);
1676 return stack_push(ctx
, &v
);
1679 static HRESULT
interp_div(exec_ctx_t
*ctx
)
1687 hres
= stack_pop_val(ctx
, &r
);
1691 hres
= stack_pop_val(ctx
, &l
);
1692 if(SUCCEEDED(hres
)) {
1693 hres
= VarDiv(l
.v
, r
.v
, &v
);
1700 return stack_push(ctx
, &v
);
1703 static HRESULT
interp_mul(exec_ctx_t
*ctx
)
1711 hres
= stack_pop_val(ctx
, &r
);
1715 hres
= stack_pop_val(ctx
, &l
);
1716 if(SUCCEEDED(hres
)) {
1717 hres
= VarMul(l
.v
, r
.v
, &v
);
1724 return stack_push(ctx
, &v
);
1727 static HRESULT
interp_exp(exec_ctx_t
*ctx
)
1735 hres
= stack_pop_val(ctx
, &r
);
1739 hres
= stack_pop_val(ctx
, &l
);
1740 if(SUCCEEDED(hres
)) {
1741 hres
= VarPow(l
.v
, r
.v
, &v
);
1748 return stack_push(ctx
, &v
);
1751 static HRESULT
interp_neg(exec_ctx_t
*ctx
)
1757 hres
= stack_pop_val(ctx
, &val
);
1761 hres
= VarNeg(val
.v
, &v
);
1766 return stack_push(ctx
, &v
);
1769 static HRESULT
interp_incc(exec_ctx_t
*ctx
)
1771 const BSTR ident
= ctx
->instr
->arg1
.bstr
;
1778 hres
= lookup_identifier(ctx
, ident
, VBDISP_LET
, &ref
);
1782 if(ref
.type
!= REF_VAR
) {
1783 FIXME("ref.type is not REF_VAR\n");
1787 hres
= VarAdd(stack_top(ctx
, 0), ref
.u
.v
, &v
);
1791 VariantClear(ref
.u
.v
);
1796 static const instr_func_t op_funcs
[] = {
1797 #define X(x,n,a,b) interp_ ## x,
1802 static const unsigned op_move
[] = {
1803 #define X(x,n,a,b) n,
1808 void release_dynamic_vars(dynamic_var_t
*var
)
1811 VariantClear(&var
->v
);
1816 static void release_exec(exec_ctx_t
*ctx
)
1820 VariantClear(&ctx
->ret_val
);
1821 release_dynamic_vars(ctx
->dynamic_vars
);
1824 IDispatch_Release(ctx
->this_obj
);
1827 for(i
=0; i
< ctx
->func
->arg_cnt
; i
++)
1828 VariantClear(ctx
->args
+i
);
1832 for(i
=0; i
< ctx
->func
->var_cnt
; i
++)
1833 VariantClear(ctx
->vars
+i
);
1836 heap_pool_free(&ctx
->heap
);
1837 heap_free(ctx
->args
);
1838 heap_free(ctx
->vars
);
1839 heap_free(ctx
->stack
);
1842 HRESULT
exec_script(script_ctx_t
*ctx
, function_t
*func
, IDispatch
*this_obj
, DISPPARAMS
*dp
, VARIANT
*res
)
1844 exec_ctx_t exec
= {func
->code_ctx
};
1846 HRESULT hres
= S_OK
;
1848 exec
.code
= func
->code_ctx
;
1850 if(dp
? func
->arg_cnt
!= arg_cnt(dp
) : func
->arg_cnt
) {
1851 FIXME("wrong arg_cnt %d, expected %d\n", dp
? arg_cnt(dp
) : 0, func
->arg_cnt
);
1855 heap_pool_init(&exec
.heap
);
1861 exec
.args
= heap_alloc_zero(func
->arg_cnt
* sizeof(VARIANT
));
1863 release_exec(&exec
);
1864 return E_OUTOFMEMORY
;
1867 for(i
=0; i
< func
->arg_cnt
; i
++) {
1869 if(V_VT(v
) == (VT_VARIANT
|VT_BYREF
)) {
1870 if(func
->args
[i
].by_ref
)
1873 hres
= VariantCopy(exec
.args
+i
, V_VARIANTREF(v
));
1875 hres
= VariantCopy(exec
.args
+i
, v
);
1878 release_exec(&exec
);
1887 exec
.vars
= heap_alloc_zero(func
->var_cnt
* sizeof(VARIANT
));
1889 release_exec(&exec
);
1890 return E_OUTOFMEMORY
;
1896 exec
.stack_size
= 16;
1898 exec
.stack
= heap_alloc(exec
.stack_size
* sizeof(VARIANT
));
1900 release_exec(&exec
);
1901 return E_OUTOFMEMORY
;
1905 exec
.this_obj
= this_obj
;
1906 else if (ctx
->host_global
)
1907 exec
.this_obj
= ctx
->host_global
;
1909 exec
.this_obj
= (IDispatch
*)&ctx
->script_obj
->IDispatchEx_iface
;
1910 IDispatch_AddRef(exec
.this_obj
);
1912 exec
.instr
= exec
.code
->instrs
+ func
->code_off
;
1917 op
= exec
.instr
->op
;
1918 hres
= op_funcs
[op
](&exec
);
1920 if(exec
.resume_next
)
1921 FIXME("Failed %08x in resume next mode\n", hres
);
1923 WARN("Failed %08x\n", hres
);
1924 stack_popn(&exec
, exec
.top
);
1928 exec
.instr
+= op_move
[op
];
1932 if(func
->type
!= FUNC_FUNCTION
&& func
->type
!= FUNC_PROPGET
&& func
->type
!= FUNC_DEFGET
)
1933 assert(V_VT(&exec
.ret_val
) == VT_EMPTY
);
1935 if(SUCCEEDED(hres
) && res
) {
1936 *res
= exec
.ret_val
;
1937 V_VT(&exec
.ret_val
) = VT_EMPTY
;
1940 release_exec(&exec
);