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
);
37 dynamic_var_t
*dynamic_vars
;
47 typedef HRESULT (*instr_func_t
)(exec_ctx_t
*);
77 static BOOL
lookup_dynamic_vars(dynamic_var_t
*var
, const WCHAR
*name
, ref_t
*ref
)
80 if(!strcmpiW(var
->name
, name
)) {
81 ref
->type
= var
->is_const
? REF_CONST
: REF_VAR
;
92 static HRESULT
lookup_identifier(exec_ctx_t
*ctx
, BSTR name
, vbdisp_invoke_type_t invoke_type
, ref_t
*ref
)
100 static const WCHAR errW
[] = {'e','r','r',0};
102 if(invoke_type
== VBDISP_LET
103 && (ctx
->func
->type
== FUNC_FUNCTION
|| ctx
->func
->type
== FUNC_PROPGET
|| ctx
->func
->type
== FUNC_DEFGET
)
104 && !strcmpiW(name
, ctx
->func
->name
)) {
106 ref
->u
.v
= &ctx
->ret_val
;
110 for(i
=0; i
< ctx
->func
->var_cnt
; i
++) {
111 if(!strcmpiW(ctx
->func
->vars
[i
].name
, name
)) {
113 ref
->u
.v
= ctx
->vars
+i
;
118 for(i
=0; i
< ctx
->func
->arg_cnt
; i
++) {
119 if(!strcmpiW(ctx
->func
->args
[i
].name
, name
)) {
121 ref
->u
.v
= ctx
->args
+i
;
126 if(lookup_dynamic_vars(ctx
->func
->type
== FUNC_GLOBAL
? ctx
->script
->global_vars
: ctx
->dynamic_vars
, name
, ref
))
129 hres
= disp_get_id(ctx
->this_obj
, name
, invoke_type
, TRUE
, &id
);
130 if(SUCCEEDED(hres
)) {
131 ref
->type
= REF_DISP
;
132 ref
->u
.d
.disp
= ctx
->this_obj
;
137 if(ctx
->func
->type
!= FUNC_GLOBAL
&& lookup_dynamic_vars(ctx
->script
->global_vars
, name
, ref
))
140 for(func
= ctx
->script
->global_funcs
; func
; func
= func
->next
) {
141 if(!strcmpiW(func
->name
, name
)) {
142 ref
->type
= REF_FUNC
;
148 LIST_FOR_EACH_ENTRY(item
, &ctx
->script
->named_items
, named_item_t
, entry
) {
149 if((item
->flags
& SCRIPTITEM_GLOBALMEMBERS
) && item
->disp
!= ctx
->this_obj
) {
150 hres
= disp_get_id(item
->disp
, name
, invoke_type
, FALSE
, &id
);
151 if(SUCCEEDED(hres
)) {
152 ref
->type
= REF_DISP
;
153 ref
->u
.d
.disp
= item
->disp
;
159 if((item
->flags
& SCRIPTITEM_ISVISIBLE
) && !strcmpiW(item
->name
, name
)) {
163 hres
= IActiveScriptSite_GetItemInfo(ctx
->script
->site
, name
, SCRIPTINFO_IUNKNOWN
, &unk
, NULL
);
165 WARN("GetItemInfo failed: %08x\n", hres
);
169 hres
= IUnknown_QueryInterface(unk
, &IID_IDispatch
, (void**)&item
->disp
);
170 IUnknown_Release(unk
);
172 WARN("object does not implement IDispatch\n");
178 ref
->u
.obj
= item
->disp
;
183 if(!strcmpiW(name
, errW
)) {
185 ref
->u
.obj
= (IDispatch
*)&ctx
->script
->err_obj
->IDispatchEx_iface
;
189 hres
= vbdisp_get_id(ctx
->script
->global_obj
, name
, invoke_type
, TRUE
, &id
);
190 if(SUCCEEDED(hres
)) {
191 ref
->type
= REF_DISP
;
192 ref
->u
.d
.disp
= (IDispatch
*)&ctx
->script
->global_obj
->IDispatchEx_iface
;
197 ref
->type
= REF_NONE
;
201 static HRESULT
add_dynamic_var(exec_ctx_t
*ctx
, const WCHAR
*name
, BOOL is_const
, VARIANT
*val
, BOOL own_val
)
203 dynamic_var_t
*new_var
;
209 heap
= ctx
->func
->type
== FUNC_GLOBAL
? &ctx
->script
->heap
: &ctx
->heap
;
211 new_var
= vbsheap_alloc(heap
, sizeof(*new_var
));
213 return E_OUTOFMEMORY
;
215 size
= (strlenW(name
)+1)*sizeof(WCHAR
);
216 str
= vbsheap_alloc(heap
, size
);
218 return E_OUTOFMEMORY
;
219 memcpy(str
, name
, size
);
221 new_var
->is_const
= is_const
;
226 hres
= VariantCopy(&new_var
->v
, val
);
231 if(ctx
->func
->type
== FUNC_GLOBAL
) {
232 new_var
->next
= ctx
->script
->global_vars
;
233 ctx
->script
->global_vars
= new_var
;
235 new_var
->next
= ctx
->dynamic_vars
;
236 ctx
->dynamic_vars
= new_var
;
242 static inline VARIANT
*stack_pop(exec_ctx_t
*ctx
)
245 return ctx
->stack
+ --ctx
->top
;
248 static inline VARIANT
*stack_top(exec_ctx_t
*ctx
, unsigned n
)
250 assert(ctx
->top
>= n
);
251 return ctx
->stack
+ (ctx
->top
-n
-1);
254 static HRESULT
stack_push(exec_ctx_t
*ctx
, VARIANT
*v
)
256 if(ctx
->stack_size
== ctx
->top
) {
259 new_stack
= heap_realloc(ctx
->stack
, ctx
->stack_size
*2);
262 return E_OUTOFMEMORY
;
265 ctx
->stack
= new_stack
;
266 ctx
->stack_size
*= 2;
269 ctx
->stack
[ctx
->top
++] = *v
;
273 static void stack_popn(exec_ctx_t
*ctx
, unsigned n
)
276 VariantClear(stack_pop(ctx
));
279 static HRESULT
stack_pop_val(exec_ctx_t
*ctx
, variant_val_t
*v
)
283 var
= stack_pop(ctx
);
285 if(V_VT(var
) == (VT_BYREF
|VT_VARIANT
)) {
287 var
= V_VARIANTREF(var
);
292 if(V_VT(var
) == VT_DISPATCH
) {
296 hres
= disp_call(ctx
->script
, V_DISPATCH(var
), DISPID_VALUE
, &dp
, &v
->store
);
298 IDispatch_Release(V_DISPATCH(var
));
311 static inline void release_val(variant_val_t
*v
)
317 static HRESULT
stack_pop_disp(exec_ctx_t
*ctx
, IDispatch
**ret
)
319 VARIANT
*v
= stack_pop(ctx
);
321 if(V_VT(v
) == VT_DISPATCH
) {
322 *ret
= V_DISPATCH(v
);
326 if(V_VT(v
) != (VT_VARIANT
|VT_BYREF
)) {
327 FIXME("not supported type: %s\n", debugstr_variant(v
));
333 if(V_VT(v
) != VT_DISPATCH
) {
334 FIXME("not disp %s\n", debugstr_variant(v
));
339 IDispatch_AddRef(V_DISPATCH(v
));
340 *ret
= V_DISPATCH(v
);
344 static inline void instr_jmp(exec_ctx_t
*ctx
, unsigned addr
)
346 ctx
->instr
= ctx
->code
->instrs
+ addr
;
349 static void vbstack_to_dp(exec_ctx_t
*ctx
, unsigned arg_cnt
, DISPPARAMS
*dp
)
352 dp
->rgdispidNamedArgs
= NULL
;
359 assert(ctx
->top
>= arg_cnt
);
361 for(i
=1; i
*2 <= arg_cnt
; i
++) {
362 tmp
= ctx
->stack
[ctx
->top
-i
];
363 ctx
->stack
[ctx
->top
-i
] = ctx
->stack
[ctx
->top
-arg_cnt
+i
-1];
364 ctx
->stack
[ctx
->top
-arg_cnt
+i
-1] = tmp
;
367 dp
->rgvarg
= ctx
->stack
+ ctx
->top
-arg_cnt
;
373 static HRESULT
do_icall(exec_ctx_t
*ctx
, VARIANT
*res
)
375 BSTR identifier
= ctx
->instr
->arg1
.bstr
;
376 const unsigned arg_cnt
= ctx
->instr
->arg2
.uint
;
381 hres
= lookup_identifier(ctx
, identifier
, VBDISP_CALLGET
, &ref
);
385 vbstack_to_dp(ctx
, arg_cnt
, &dp
);
391 FIXME("REF_VAR no res\n");
396 FIXME("arguments not implemented\n");
400 V_VT(res
) = VT_BYREF
|VT_VARIANT
;
401 V_BYREF(res
) = V_VT(ref
.u
.v
) == (VT_VARIANT
|VT_BYREF
) ? V_VARIANTREF(ref
.u
.v
) : ref
.u
.v
;
404 hres
= disp_call(ctx
->script
, ref
.u
.d
.disp
, ref
.u
.d
.id
, &dp
, res
);
409 hres
= exec_script(ctx
->script
, ref
.u
.f
, NULL
, &dp
, res
);
415 FIXME("arguments on object\n");
420 IDispatch_AddRef(ref
.u
.obj
);
421 V_VT(res
) = VT_DISPATCH
;
422 V_DISPATCH(res
) = ref
.u
.obj
;
426 FIXME("%s not found\n", debugstr_w(identifier
));
427 return DISP_E_UNKNOWNNAME
;
430 stack_popn(ctx
, arg_cnt
);
434 static HRESULT
interp_icall(exec_ctx_t
*ctx
)
441 hres
= do_icall(ctx
, &v
);
445 return stack_push(ctx
, &v
);
448 static HRESULT
interp_icallv(exec_ctx_t
*ctx
)
451 return do_icall(ctx
, NULL
);
454 static HRESULT
do_mcall(exec_ctx_t
*ctx
, VARIANT
*res
)
456 const BSTR identifier
= ctx
->instr
->arg1
.bstr
;
457 const unsigned arg_cnt
= ctx
->instr
->arg2
.uint
;
463 hres
= stack_pop_disp(ctx
, &obj
);
472 vbstack_to_dp(ctx
, arg_cnt
, &dp
);
474 hres
= disp_get_id(obj
, identifier
, VBDISP_CALLGET
, FALSE
, &id
);
476 hres
= disp_call(ctx
->script
, obj
, id
, &dp
, res
);
477 IDispatch_Release(obj
);
481 stack_popn(ctx
, arg_cnt
);
485 static HRESULT
interp_mcall(exec_ctx_t
*ctx
)
492 hres
= do_mcall(ctx
, &res
);
496 return stack_push(ctx
, &res
);
499 static HRESULT
interp_mcallv(exec_ctx_t
*ctx
)
503 return do_mcall(ctx
, NULL
);
506 static HRESULT
assign_ident(exec_ctx_t
*ctx
, BSTR name
, VARIANT
*val
, BOOL own_val
)
511 hres
= lookup_identifier(ctx
, name
, VBDISP_LET
, &ref
);
517 VARIANT
*v
= ref
.u
.v
;
519 if(V_VT(v
) == (VT_VARIANT
|VT_BYREF
))
527 hres
= VariantCopy(v
, val
);
532 hres
= disp_propput(ctx
->script
, ref
.u
.d
.disp
, ref
.u
.d
.id
, val
);
537 FIXME("functions not implemented\n");
543 FIXME("REF_CONST\n");
546 if(ctx
->func
->code_ctx
->option_explicit
) {
547 FIXME("throw exception\n");
550 TRACE("creating variable %s\n", debugstr_w(name
));
551 hres
= add_dynamic_var(ctx
, name
, FALSE
, val
, own_val
);
558 static HRESULT
interp_assign_ident(exec_ctx_t
*ctx
)
560 const BSTR arg
= ctx
->instr
->arg1
.bstr
;
564 TRACE("%s\n", debugstr_w(arg
));
566 hres
= stack_pop_val(ctx
, &v
);
570 return assign_ident(ctx
, arg
, v
.v
, v
.owned
);
573 static HRESULT
interp_set_ident(exec_ctx_t
*ctx
)
575 const BSTR arg
= ctx
->instr
->arg1
.bstr
;
580 TRACE("%s\n", debugstr_w(arg
));
582 hres
= stack_pop_disp(ctx
, &disp
);
586 V_VT(&v
) = VT_DISPATCH
;
587 V_DISPATCH(&v
) = disp
;
588 return assign_ident(ctx
, ctx
->instr
->arg1
.bstr
, &v
, TRUE
);
591 static HRESULT
interp_assign_member(exec_ctx_t
*ctx
)
593 BSTR identifier
= ctx
->instr
->arg1
.bstr
;
599 TRACE("%s\n", debugstr_w(identifier
));
601 hres
= stack_pop_disp(ctx
, &obj
);
610 hres
= stack_pop_val(ctx
, &val
);
612 IDispatch_Release(obj
);
616 hres
= disp_get_id(obj
, identifier
, VBDISP_LET
, FALSE
, &id
);
618 hres
= disp_propput(ctx
->script
, obj
, id
, val
.v
);
621 IDispatch_Release(obj
);
625 static HRESULT
interp_set_member(exec_ctx_t
*ctx
)
627 BSTR identifier
= ctx
->instr
->arg1
.bstr
;
628 IDispatch
*obj
, *val
;
632 TRACE("%s\n", debugstr_w(identifier
));
634 hres
= stack_pop_disp(ctx
, &obj
);
643 hres
= stack_pop_disp(ctx
, &val
);
645 IDispatch_Release(obj
);
649 hres
= disp_get_id(obj
, identifier
, VBDISP_SET
, FALSE
, &id
);
650 if(SUCCEEDED(hres
)) {
653 V_VT(&v
) = VT_DISPATCH
;
654 V_DISPATCH(&v
) = val
;
655 hres
= disp_propput(ctx
->script
, obj
, id
, &v
);
659 IDispatch_Release(val
);
660 IDispatch_Release(obj
);
664 static HRESULT
interp_const(exec_ctx_t
*ctx
)
666 BSTR arg
= ctx
->instr
->arg1
.bstr
;
671 TRACE("%s\n", debugstr_w(arg
));
673 assert(ctx
->func
->type
== FUNC_GLOBAL
);
675 hres
= lookup_identifier(ctx
, arg
, VBDISP_CALLGET
, &ref
);
679 if(ref
.type
!= REF_NONE
) {
680 FIXME("%s already defined\n", debugstr_w(arg
));
684 hres
= stack_pop_val(ctx
, &val
);
688 return add_dynamic_var(ctx
, arg
, TRUE
, val
.v
, val
.owned
);
691 static HRESULT
interp_val(exec_ctx_t
*ctx
)
699 hres
= stack_pop_val(ctx
, &val
);
705 hres
= VariantCopy(&v
, val
.v
);
710 return stack_push(ctx
, val
.owned
? val
.v
: &v
);
713 static HRESULT
interp_pop(exec_ctx_t
*ctx
)
715 const unsigned n
= ctx
->instr
->arg1
.uint
;
723 static HRESULT
interp_new(exec_ctx_t
*ctx
)
725 const WCHAR
*arg
= ctx
->instr
->arg1
.bstr
;
726 class_desc_t
*class_desc
;
731 TRACE("%s\n", debugstr_w(arg
));
733 for(class_desc
= ctx
->script
->classes
; class_desc
; class_desc
= class_desc
->next
) {
734 if(!strcmpiW(class_desc
->name
, arg
))
738 FIXME("Class %s not found\n", debugstr_w(arg
));
742 hres
= create_vbdisp(class_desc
, &obj
);
746 V_VT(&v
) = VT_DISPATCH
;
747 V_DISPATCH(&v
) = (IDispatch
*)&obj
->IDispatchEx_iface
;
748 return stack_push(ctx
, &v
);
751 static HRESULT
interp_step(exec_ctx_t
*ctx
)
753 const BSTR ident
= ctx
->instr
->arg2
.bstr
;
759 TRACE("%s\n", debugstr_w(ident
));
763 hres
= VarCmp(stack_top(ctx
, 0), &zero
, ctx
->script
->lcid
, 0);
767 gteq_zero
= hres
== VARCMP_GT
|| hres
== VARCMP_EQ
;
769 hres
= lookup_identifier(ctx
, ident
, VBDISP_ANY
, &ref
);
773 if(ref
.type
!= REF_VAR
) {
774 FIXME("%s is not REF_VAR\n", debugstr_w(ident
));
778 hres
= VarCmp(ref
.u
.v
, stack_top(ctx
, 1), ctx
->script
->lcid
, 0);
782 if(hres
== VARCMP_EQ
|| hres
== (gteq_zero
? VARCMP_LT
: VARCMP_GT
))
785 instr_jmp(ctx
, ctx
->instr
->arg1
.uint
);
789 static HRESULT
interp_jmp(exec_ctx_t
*ctx
)
791 const unsigned arg
= ctx
->instr
->arg1
.uint
;
799 static HRESULT
interp_jmp_false(exec_ctx_t
*ctx
)
801 const unsigned arg
= ctx
->instr
->arg1
.uint
;
807 hres
= stack_pop_val(ctx
, &val
);
811 if(V_VT(val
.v
) != VT_BOOL
) {
812 FIXME("unsupported for %s\n", debugstr_variant(val
.v
));
820 instr_jmp(ctx
, ctx
->instr
->arg1
.uint
);
824 static HRESULT
interp_jmp_true(exec_ctx_t
*ctx
)
826 const unsigned arg
= ctx
->instr
->arg1
.uint
;
832 hres
= stack_pop_val(ctx
, &val
);
836 if(V_VT(val
.v
) != VT_BOOL
) {
837 FIXME("unsupported for %s\n", debugstr_variant(val
.v
));
843 instr_jmp(ctx
, ctx
->instr
->arg1
.uint
);
849 static HRESULT
interp_ret(exec_ctx_t
*ctx
)
857 static HRESULT
interp_stop(exec_ctx_t
*ctx
)
861 /* NOTE: this should have effect in debugging mode (that we don't support yet) */
865 static HRESULT
interp_me(exec_ctx_t
*ctx
)
871 IDispatch_AddRef(ctx
->this_obj
);
872 V_VT(&v
) = VT_DISPATCH
;
873 V_DISPATCH(&v
) = ctx
->this_obj
;
874 return stack_push(ctx
, &v
);
877 static HRESULT
interp_bool(exec_ctx_t
*ctx
)
879 const VARIANT_BOOL arg
= ctx
->instr
->arg1
.lng
;
882 TRACE("%s\n", arg
? "true" : "false");
886 return stack_push(ctx
, &v
);
889 static HRESULT
interp_errmode(exec_ctx_t
*ctx
)
891 const int err_mode
= ctx
->instr
->arg1
.uint
;
892 FIXME("%d\n", err_mode
);
896 static HRESULT
interp_string(exec_ctx_t
*ctx
)
903 V_BSTR(&v
) = SysAllocString(ctx
->instr
->arg1
.str
);
905 return E_OUTOFMEMORY
;
907 return stack_push(ctx
, &v
);
910 static HRESULT
interp_long(exec_ctx_t
*ctx
)
912 const LONG arg
= ctx
->instr
->arg1
.lng
;
919 return stack_push(ctx
, &v
);
922 static HRESULT
interp_short(exec_ctx_t
*ctx
)
924 const LONG arg
= ctx
->instr
->arg1
.lng
;
931 return stack_push(ctx
, &v
);
934 static HRESULT
interp_double(exec_ctx_t
*ctx
)
936 const DOUBLE
*arg
= ctx
->instr
->arg1
.dbl
;
939 TRACE("%lf\n", *arg
);
943 return stack_push(ctx
, &v
);
946 static HRESULT
interp_empty(exec_ctx_t
*ctx
)
953 return stack_push(ctx
, &v
);
956 static HRESULT
interp_null(exec_ctx_t
*ctx
)
963 return stack_push(ctx
, &v
);
966 static HRESULT
interp_nothing(exec_ctx_t
*ctx
)
972 V_VT(&v
) = VT_DISPATCH
;
973 V_DISPATCH(&v
) = NULL
;
974 return stack_push(ctx
, &v
);
977 static HRESULT
interp_not(exec_ctx_t
*ctx
)
985 hres
= stack_pop_val(ctx
, &val
);
989 hres
= VarNot(val
.v
, &v
);
994 return stack_push(ctx
, &v
);
997 static HRESULT
interp_and(exec_ctx_t
*ctx
)
1005 hres
= stack_pop_val(ctx
, &r
);
1009 hres
= stack_pop_val(ctx
, &l
);
1010 if(SUCCEEDED(hres
)) {
1011 hres
= VarAnd(l
.v
, r
.v
, &v
);
1018 return stack_push(ctx
, &v
);
1021 static HRESULT
interp_or(exec_ctx_t
*ctx
)
1029 hres
= stack_pop_val(ctx
, &r
);
1033 hres
= stack_pop_val(ctx
, &l
);
1034 if(SUCCEEDED(hres
)) {
1035 hres
= VarOr(l
.v
, r
.v
, &v
);
1042 return stack_push(ctx
, &v
);
1045 static HRESULT
interp_xor(exec_ctx_t
*ctx
)
1053 hres
= stack_pop_val(ctx
, &r
);
1057 hres
= stack_pop_val(ctx
, &l
);
1058 if(SUCCEEDED(hres
)) {
1059 hres
= VarXor(l
.v
, r
.v
, &v
);
1066 return stack_push(ctx
, &v
);
1069 static HRESULT
interp_eqv(exec_ctx_t
*ctx
)
1077 hres
= stack_pop_val(ctx
, &r
);
1081 hres
= stack_pop_val(ctx
, &l
);
1082 if(SUCCEEDED(hres
)) {
1083 hres
= VarEqv(l
.v
, r
.v
, &v
);
1090 return stack_push(ctx
, &v
);
1093 static HRESULT
interp_imp(exec_ctx_t
*ctx
)
1101 hres
= stack_pop_val(ctx
, &r
);
1105 hres
= stack_pop_val(ctx
, &l
);
1106 if(SUCCEEDED(hres
)) {
1107 hres
= VarImp(l
.v
, r
.v
, &v
);
1114 return stack_push(ctx
, &v
);
1117 static HRESULT
cmp_oper(exec_ctx_t
*ctx
)
1122 hres
= stack_pop_val(ctx
, &r
);
1126 hres
= stack_pop_val(ctx
, &l
);
1127 if(SUCCEEDED(hres
)) {
1128 if(V_VT(l
.v
) == VT_NULL
|| V_VT(r
.v
) == VT_NULL
) {
1129 FIXME("comparing nulls is not implemented\n");
1132 hres
= VarCmp(l
.v
, r
.v
, ctx
->script
->lcid
, 0);
1141 static HRESULT
interp_equal(exec_ctx_t
*ctx
)
1148 hres
= cmp_oper(ctx
);
1153 V_BOOL(&v
) = hres
== VARCMP_EQ
? VARIANT_TRUE
: VARIANT_FALSE
;
1154 return stack_push(ctx
, &v
);
1157 static HRESULT
interp_nequal(exec_ctx_t
*ctx
)
1164 hres
= cmp_oper(ctx
);
1169 V_BOOL(&v
) = hres
!= VARCMP_EQ
? VARIANT_TRUE
: VARIANT_FALSE
;
1170 return stack_push(ctx
, &v
);
1173 static HRESULT
interp_gt(exec_ctx_t
*ctx
)
1180 hres
= cmp_oper(ctx
);
1185 V_BOOL(&v
) = hres
== VARCMP_GT
? VARIANT_TRUE
: VARIANT_FALSE
;
1186 return stack_push(ctx
, &v
);
1189 static HRESULT
interp_gteq(exec_ctx_t
*ctx
)
1196 hres
= cmp_oper(ctx
);
1201 V_BOOL(&v
) = hres
== VARCMP_GT
|| hres
== VARCMP_EQ
? VARIANT_TRUE
: VARIANT_FALSE
;
1202 return stack_push(ctx
, &v
);
1205 static HRESULT
interp_lt(exec_ctx_t
*ctx
)
1212 hres
= cmp_oper(ctx
);
1217 V_BOOL(&v
) = hres
== VARCMP_LT
? VARIANT_TRUE
: VARIANT_FALSE
;
1218 return stack_push(ctx
, &v
);
1221 static HRESULT
interp_lteq(exec_ctx_t
*ctx
)
1228 hres
= cmp_oper(ctx
);
1233 V_BOOL(&v
) = hres
== VARCMP_LT
|| hres
== VARCMP_EQ
? VARIANT_TRUE
: VARIANT_FALSE
;
1234 return stack_push(ctx
, &v
);
1237 static HRESULT
disp_cmp(IDispatch
*disp1
, IDispatch
*disp2
, VARIANT_BOOL
*ret
)
1239 IObjectIdentity
*identity
;
1240 IUnknown
*unk1
, *unk2
;
1243 if(disp1
== disp2
) {
1244 *ret
= VARIANT_TRUE
;
1248 if(!disp1
|| !disp2
) {
1249 *ret
= VARIANT_FALSE
;
1253 hres
= IDispatch_QueryInterface(disp1
, &IID_IUnknown
, (void**)&unk1
);
1257 hres
= IDispatch_QueryInterface(disp2
, &IID_IUnknown
, (void**)&unk2
);
1259 IUnknown_Release(unk1
);
1264 *ret
= VARIANT_TRUE
;
1266 hres
= IUnknown_QueryInterface(unk1
, &IID_IObjectIdentity
, (void**)&identity
);
1267 if(SUCCEEDED(hres
)) {
1268 hres
= IObjectIdentity_IsEqualObject(identity
, unk2
);
1269 IObjectIdentity_Release(identity
);
1270 *ret
= hres
== S_OK
? VARIANT_TRUE
: VARIANT_FALSE
;
1272 *ret
= VARIANT_FALSE
;
1276 IUnknown_Release(unk1
);
1277 IUnknown_Release(unk2
);
1281 static HRESULT
interp_is(exec_ctx_t
*ctx
)
1289 hres
= stack_pop_disp(ctx
, &r
);
1293 hres
= stack_pop_disp(ctx
, &l
);
1294 if(SUCCEEDED(hres
)) {
1296 hres
= disp_cmp(l
, r
, &V_BOOL(&v
));
1298 IDispatch_Release(l
);
1301 IDispatch_Release(r
);
1305 return stack_push(ctx
, &v
);
1308 static HRESULT
interp_concat(exec_ctx_t
*ctx
)
1316 hres
= stack_pop_val(ctx
, &r
);
1320 hres
= stack_pop_val(ctx
, &l
);
1321 if(SUCCEEDED(hres
)) {
1322 hres
= VarCat(l
.v
, r
.v
, &v
);
1329 return stack_push(ctx
, &v
);
1332 static HRESULT
interp_add(exec_ctx_t
*ctx
)
1340 hres
= stack_pop_val(ctx
, &r
);
1344 hres
= stack_pop_val(ctx
, &l
);
1345 if(SUCCEEDED(hres
)) {
1346 hres
= VarAdd(l
.v
, r
.v
, &v
);
1353 return stack_push(ctx
, &v
);
1356 static HRESULT
interp_sub(exec_ctx_t
*ctx
)
1364 hres
= stack_pop_val(ctx
, &r
);
1368 hres
= stack_pop_val(ctx
, &l
);
1369 if(SUCCEEDED(hres
)) {
1370 hres
= VarSub(l
.v
, r
.v
, &v
);
1377 return stack_push(ctx
, &v
);
1380 static HRESULT
interp_mod(exec_ctx_t
*ctx
)
1388 hres
= stack_pop_val(ctx
, &r
);
1392 hres
= stack_pop_val(ctx
, &l
);
1393 if(SUCCEEDED(hres
)) {
1394 hres
= VarMod(l
.v
, r
.v
, &v
);
1401 return stack_push(ctx
, &v
);
1404 static HRESULT
interp_idiv(exec_ctx_t
*ctx
)
1412 hres
= stack_pop_val(ctx
, &r
);
1416 hres
= stack_pop_val(ctx
, &l
);
1417 if(SUCCEEDED(hres
)) {
1418 hres
= VarIdiv(l
.v
, r
.v
, &v
);
1425 return stack_push(ctx
, &v
);
1428 static HRESULT
interp_div(exec_ctx_t
*ctx
)
1436 hres
= stack_pop_val(ctx
, &r
);
1440 hres
= stack_pop_val(ctx
, &l
);
1441 if(SUCCEEDED(hres
)) {
1442 hres
= VarDiv(l
.v
, r
.v
, &v
);
1449 return stack_push(ctx
, &v
);
1452 static HRESULT
interp_mul(exec_ctx_t
*ctx
)
1460 hres
= stack_pop_val(ctx
, &r
);
1464 hres
= stack_pop_val(ctx
, &l
);
1465 if(SUCCEEDED(hres
)) {
1466 hres
= VarMul(l
.v
, r
.v
, &v
);
1473 return stack_push(ctx
, &v
);
1476 static HRESULT
interp_exp(exec_ctx_t
*ctx
)
1484 hres
= stack_pop_val(ctx
, &r
);
1488 hres
= stack_pop_val(ctx
, &l
);
1489 if(SUCCEEDED(hres
)) {
1490 hres
= VarPow(l
.v
, r
.v
, &v
);
1497 return stack_push(ctx
, &v
);
1500 static HRESULT
interp_neg(exec_ctx_t
*ctx
)
1506 hres
= stack_pop_val(ctx
, &val
);
1510 hres
= VarNeg(val
.v
, &v
);
1515 return stack_push(ctx
, &v
);
1518 static HRESULT
interp_incc(exec_ctx_t
*ctx
)
1520 const BSTR ident
= ctx
->instr
->arg1
.bstr
;
1521 FIXME("%s\n", debugstr_w(ident
));
1525 static const instr_func_t op_funcs
[] = {
1526 #define X(x,n,a,b) interp_ ## x,
1531 static const unsigned op_move
[] = {
1532 #define X(x,n,a,b) n,
1537 static void release_exec(exec_ctx_t
*ctx
)
1541 VariantClear(&ctx
->ret_val
);
1544 IDispatch_Release(ctx
->this_obj
);
1547 for(i
=0; i
< ctx
->func
->arg_cnt
; i
++)
1548 VariantClear(ctx
->args
+i
);
1552 for(i
=0; i
< ctx
->func
->var_cnt
; i
++)
1553 VariantClear(ctx
->vars
+i
);
1556 vbsheap_free(&ctx
->heap
);
1557 heap_free(ctx
->args
);
1558 heap_free(ctx
->vars
);
1559 heap_free(ctx
->stack
);
1562 HRESULT
exec_script(script_ctx_t
*ctx
, function_t
*func
, IDispatch
*this_obj
, DISPPARAMS
*dp
, VARIANT
*res
)
1564 exec_ctx_t exec
= {func
->code_ctx
};
1566 HRESULT hres
= S_OK
;
1568 exec
.code
= func
->code_ctx
;
1570 if(dp
? func
->arg_cnt
!= arg_cnt(dp
) : func
->arg_cnt
) {
1571 FIXME("wrong arg_cnt %d, expected %d\n", dp
? arg_cnt(dp
) : 0, func
->arg_cnt
);
1575 vbsheap_init(&exec
.heap
);
1581 exec
.args
= heap_alloc_zero(func
->arg_cnt
* sizeof(VARIANT
));
1583 release_exec(&exec
);
1584 return E_OUTOFMEMORY
;
1587 for(i
=0; i
< func
->arg_cnt
; i
++) {
1589 if(V_VT(v
) == (VT_VARIANT
|VT_BYREF
)) {
1590 if(func
->args
[i
].by_ref
)
1593 hres
= VariantCopy(exec
.args
+i
, V_VARIANTREF(v
));
1595 hres
= VariantCopy(exec
.args
+i
, v
);
1598 release_exec(&exec
);
1607 exec
.vars
= heap_alloc_zero(func
->var_cnt
* sizeof(VARIANT
));
1609 release_exec(&exec
);
1610 return E_OUTOFMEMORY
;
1616 exec
.stack_size
= 16;
1618 exec
.stack
= heap_alloc(exec
.stack_size
* sizeof(VARIANT
));
1620 release_exec(&exec
);
1621 return E_OUTOFMEMORY
;
1625 exec
.this_obj
= this_obj
;
1626 else if (ctx
->host_global
)
1627 exec
.this_obj
= ctx
->host_global
;
1629 exec
.this_obj
= (IDispatch
*)&ctx
->script_obj
->IDispatchEx_iface
;
1630 IDispatch_AddRef(exec
.this_obj
);
1632 exec
.instr
= exec
.code
->instrs
+ func
->code_off
;
1637 op
= exec
.instr
->op
;
1638 hres
= op_funcs
[op
](&exec
);
1640 FIXME("Failed %08x\n", hres
);
1641 stack_popn(&exec
, exec
.top
);
1645 exec
.instr
+= op_move
[op
];
1649 if(func
->type
!= FUNC_FUNCTION
&& func
->type
!= FUNC_PROPGET
&& func
->type
!= FUNC_DEFGET
)
1650 assert(V_VT(&exec
.ret_val
) == VT_EMPTY
);
1652 if(SUCCEEDED(hres
) && res
) {
1653 *res
= exec
.ret_val
;
1654 V_VT(&exec
.ret_val
) = VT_EMPTY
;
1657 release_exec(&exec
);