vbscript: Moved creating new dynamic variable to separated function.
[wine.git] / dlls / vbscript / interp.c
blob46d15fff4a923d5ab1ff04022fcb986adb00214d
1 /*
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
19 #include <assert.h>
21 #include "vbscript.h"
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
28 typedef struct {
29 vbscode_t *code;
30 instr_t *instr;
31 script_ctx_t *script;
32 function_t *func;
33 IDispatch *this_obj;
35 VARIANT *args;
36 VARIANT *vars;
38 dynamic_var_t *dynamic_vars;
39 vbsheap_t heap;
41 unsigned stack_size;
42 unsigned top;
43 VARIANT *stack;
45 VARIANT ret_val;
46 } exec_ctx_t;
48 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
50 typedef enum {
51 REF_NONE,
52 REF_DISP,
53 REF_VAR,
54 REF_OBJ,
55 REF_FUNC
56 } ref_type_t;
58 typedef struct {
59 ref_type_t type;
60 union {
61 struct {
62 IDispatch *disp;
63 DISPID id;
64 } d;
65 VARIANT *v;
66 function_t *f;
67 IDispatch *obj;
68 } u;
69 } ref_t;
71 typedef struct {
72 VARIANT *v;
73 VARIANT store;
74 BOOL owned;
75 } variant_val_t;
77 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
79 while(var) {
80 if(!strcmpiW(var->name, name)) {
81 ref->type = REF_VAR;
82 ref->u.v = &var->v;
83 return TRUE;
86 var = var->next;
89 return FALSE;
92 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref)
94 named_item_t *item;
95 function_t *func;
96 unsigned i;
97 DISPID id;
98 HRESULT hres;
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)) {
105 ref->type = REF_VAR;
106 ref->u.v = &ctx->ret_val;
107 return S_OK;
110 for(i=0; i < ctx->func->var_cnt; i++) {
111 if(!strcmpiW(ctx->func->vars[i].name, name)) {
112 ref->type = REF_VAR;
113 ref->u.v = ctx->vars+i;
114 return TRUE;
118 for(i=0; i < ctx->func->arg_cnt; i++) {
119 if(!strcmpiW(ctx->func->args[i].name, name)) {
120 ref->type = REF_VAR;
121 ref->u.v = ctx->args+i;
122 return S_OK;
126 if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? ctx->script->global_vars : ctx->dynamic_vars, name, ref))
127 return S_OK;
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;
133 ref->u.d.id = id;
134 return S_OK;
137 if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(ctx->script->global_vars, name, ref))
138 return S_OK;
140 for(func = ctx->script->global_funcs; func; func = func->next) {
141 if(!strcmpiW(func->name, name)) {
142 ref->type = REF_FUNC;
143 ref->u.f = func;
144 return S_OK;
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;
154 ref->u.d.id = id;
155 return S_OK;
159 if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpiW(item->name, name)) {
160 if(!item->disp) {
161 IUnknown *unk;
163 hres = IActiveScriptSite_GetItemInfo(ctx->script->site, name, SCRIPTINFO_IUNKNOWN, &unk, NULL);
164 if(FAILED(hres)) {
165 WARN("GetItemInfo failed: %08x\n", hres);
166 continue;
169 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp);
170 IUnknown_Release(unk);
171 if(FAILED(hres)) {
172 WARN("object does not implement IDispatch\n");
173 continue;
177 ref->type = REF_OBJ;
178 ref->u.obj = item->disp;
179 return S_OK;
183 if(!strcmpiW(name, errW)) {
184 ref->type = REF_OBJ;
185 ref->u.obj = (IDispatch*)&ctx->script->err_obj->IDispatchEx_iface;
186 return S_OK;
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;
193 ref->u.d.id = id;
194 return S_OK;
197 ref->type = REF_NONE;
198 return S_OK;
201 static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name, VARIANT *val, BOOL own_val)
203 dynamic_var_t *new_var;
204 vbsheap_t *heap;
205 WCHAR *str;
206 unsigned size;
207 HRESULT hres;
209 heap = ctx->func->type == FUNC_GLOBAL ? &ctx->script->heap : &ctx->heap;
211 new_var = vbsheap_alloc(heap, sizeof(*new_var));
212 if(!new_var)
213 return E_OUTOFMEMORY;
215 size = (strlenW(name)+1)*sizeof(WCHAR);
216 str = vbsheap_alloc(heap, size);
217 if(!str)
218 return E_OUTOFMEMORY;
219 memcpy(str, name, size);
220 new_var->name = str;
222 if(own_val) {
223 new_var->v = *val;
224 }else {
225 hres = VariantCopy(&new_var->v, val);
226 if(FAILED(hres))
227 return hres;
230 if(ctx->func->type == FUNC_GLOBAL) {
231 new_var->next = ctx->script->global_vars;
232 ctx->script->global_vars = new_var;
233 }else {
234 new_var->next = ctx->dynamic_vars;
235 ctx->dynamic_vars = new_var;
238 return S_OK;
241 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
243 assert(ctx->top);
244 return ctx->stack + --ctx->top;
247 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
249 if(ctx->stack_size == ctx->top) {
250 VARIANT *new_stack;
252 new_stack = heap_realloc(ctx->stack, ctx->stack_size*2);
253 if(!new_stack) {
254 VariantClear(v);
255 return E_OUTOFMEMORY;
258 ctx->stack = new_stack;
259 ctx->stack_size *= 2;
262 ctx->stack[ctx->top++] = *v;
263 return S_OK;
266 static void stack_popn(exec_ctx_t *ctx, unsigned n)
268 while(n--)
269 VariantClear(stack_pop(ctx));
272 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *v)
274 VARIANT *var;
276 var = stack_pop(ctx);
278 if(V_VT(var) == (VT_BYREF|VT_VARIANT)) {
279 v->owned = FALSE;
280 var = V_VARIANTREF(var);
281 }else {
282 v->owned = TRUE;
285 if(V_VT(var) == VT_DISPATCH) {
286 DISPPARAMS dp = {0};
287 HRESULT hres;
289 hres = disp_call(ctx->script, V_DISPATCH(var), DISPID_VALUE, &dp, &v->store);
290 if(v->owned)
291 IDispatch_Release(V_DISPATCH(var));
292 if(FAILED(hres))
293 return hres;
295 v->owned = TRUE;
296 v->v = &v->store;
297 }else {
298 v->v = var;
301 return S_OK;
304 static inline void release_val(variant_val_t *v)
306 if(v->owned)
307 VariantClear(v->v);
310 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
312 VARIANT *v = stack_pop(ctx);
314 if(V_VT(v) == VT_DISPATCH) {
315 *ret = V_DISPATCH(v);
316 return S_OK;
319 if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
320 FIXME("not supported type: %s\n", debugstr_variant(v));
321 VariantClear(v);
322 return E_FAIL;
325 v = V_BYREF(v);
326 if(V_VT(v) != VT_DISPATCH) {
327 FIXME("not disp %s\n", debugstr_variant(v));
328 return E_FAIL;
331 if(V_DISPATCH(v))
332 IDispatch_AddRef(V_DISPATCH(v));
333 *ret = V_DISPATCH(v);
334 return S_OK;
337 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
339 ctx->instr = ctx->code->instrs + addr;
342 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, DISPPARAMS *dp)
344 dp->cArgs = arg_cnt;
345 dp->rgdispidNamedArgs = NULL;
346 dp->cNamedArgs = 0;
348 if(arg_cnt) {
349 VARIANT tmp;
350 unsigned i;
352 assert(ctx->top >= arg_cnt);
354 for(i=1; i*2 <= arg_cnt; i++) {
355 tmp = ctx->stack[ctx->top-i];
356 ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
357 ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
360 dp->rgvarg = ctx->stack + ctx->top-arg_cnt;
361 }else {
362 dp->rgvarg = NULL;
366 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
368 BSTR identifier = ctx->instr->arg1.bstr;
369 const unsigned arg_cnt = ctx->instr->arg2.uint;
370 DISPPARAMS dp;
371 ref_t ref;
372 HRESULT hres;
374 hres = lookup_identifier(ctx, identifier, VBDISP_CALLGET, &ref);
375 if(FAILED(hres))
376 return hres;
378 vbstack_to_dp(ctx, arg_cnt, &dp);
380 switch(ref.type) {
381 case REF_VAR:
382 if(!res) {
383 FIXME("REF_VAR no res\n");
384 return E_NOTIMPL;
387 if(arg_cnt) {
388 FIXME("arguments not implemented\n");
389 return E_NOTIMPL;
392 V_VT(res) = VT_BYREF|VT_VARIANT;
393 V_BYREF(res) = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
394 break;
395 case REF_DISP:
396 hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
397 if(FAILED(hres))
398 return hres;
399 break;
400 case REF_FUNC:
401 hres = exec_script(ctx->script, ref.u.f, NULL, &dp, res);
402 if(FAILED(hres))
403 return hres;
404 break;
405 case REF_OBJ:
406 if(arg_cnt) {
407 FIXME("arguments on object\n");
408 return E_NOTIMPL;
411 if(res) {
412 IDispatch_AddRef(ref.u.obj);
413 V_VT(res) = VT_DISPATCH;
414 V_DISPATCH(res) = ref.u.obj;
416 break;
417 case REF_NONE:
418 FIXME("%s not found\n", debugstr_w(identifier));
419 return DISP_E_UNKNOWNNAME;
422 stack_popn(ctx, arg_cnt);
423 return S_OK;
426 static HRESULT interp_icall(exec_ctx_t *ctx)
428 VARIANT v;
429 HRESULT hres;
431 TRACE("\n");
433 hres = do_icall(ctx, &v);
434 if(FAILED(hres))
435 return hres;
437 return stack_push(ctx, &v);
440 static HRESULT interp_icallv(exec_ctx_t *ctx)
442 TRACE("\n");
443 return do_icall(ctx, NULL);
446 static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res)
448 const BSTR identifier = ctx->instr->arg1.bstr;
449 const unsigned arg_cnt = ctx->instr->arg2.uint;
450 IDispatch *obj;
451 DISPPARAMS dp;
452 DISPID id;
453 HRESULT hres;
455 hres = stack_pop_disp(ctx, &obj);
456 if(FAILED(hres))
457 return hres;
459 if(!obj) {
460 FIXME("NULL obj\n");
461 return E_FAIL;
464 vbstack_to_dp(ctx, arg_cnt, &dp);
466 hres = disp_get_id(obj, identifier, VBDISP_CALLGET, FALSE, &id);
467 if(SUCCEEDED(hres))
468 hres = disp_call(ctx->script, obj, id, &dp, res);
469 IDispatch_Release(obj);
470 if(FAILED(hres))
471 return hres;
473 stack_popn(ctx, arg_cnt);
474 return S_OK;
477 static HRESULT interp_mcall(exec_ctx_t *ctx)
479 VARIANT res;
480 HRESULT hres;
482 TRACE("\n");
484 hres = do_mcall(ctx, &res);
485 if(FAILED(hres))
486 return hres;
488 return stack_push(ctx, &res);
491 static HRESULT interp_mcallv(exec_ctx_t *ctx)
493 TRACE("\n");
495 return do_mcall(ctx, NULL);
498 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
500 ref_t ref;
501 HRESULT hres;
503 hres = lookup_identifier(ctx, name, VBDISP_LET, &ref);
504 if(FAILED(hres))
505 return hres;
507 switch(ref.type) {
508 case REF_VAR: {
509 VARIANT *v = ref.u.v;
511 if(V_VT(v) == (VT_VARIANT|VT_BYREF))
512 v = V_VARIANTREF(v);
514 if(own_val) {
515 VariantClear(v);
516 *v = *val;
517 hres = S_OK;
518 }else {
519 hres = VariantCopy(v, val);
521 break;
523 case REF_DISP:
524 hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, val);
525 if(own_val)
526 VariantClear(val);
527 break;
528 case REF_FUNC:
529 FIXME("functions not implemented\n");
530 return E_NOTIMPL;
531 case REF_OBJ:
532 FIXME("REF_OBJ\n");
533 return E_NOTIMPL;
534 case REF_NONE:
535 if(ctx->func->code_ctx->option_explicit) {
536 FIXME("throw exception\n");
537 hres = E_FAIL;
538 }else {
539 TRACE("creating variable %s\n", debugstr_w(name));
540 hres = add_dynamic_var(ctx, name, val, own_val);
544 return hres;
547 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
549 const BSTR arg = ctx->instr->arg1.bstr;
550 variant_val_t v;
551 HRESULT hres;
553 TRACE("%s\n", debugstr_w(arg));
555 hres = stack_pop_val(ctx, &v);
556 if(FAILED(hres))
557 return hres;
559 return assign_ident(ctx, arg, v.v, v.owned);
562 static HRESULT interp_set_ident(exec_ctx_t *ctx)
564 const BSTR arg = ctx->instr->arg1.bstr;
565 IDispatch *disp;
566 VARIANT v;
567 HRESULT hres;
569 TRACE("%s\n", debugstr_w(arg));
571 hres = stack_pop_disp(ctx, &disp);
572 if(FAILED(hres))
573 return hres;
575 V_VT(&v) = VT_DISPATCH;
576 V_DISPATCH(&v) = disp;
577 return assign_ident(ctx, ctx->instr->arg1.bstr, &v, TRUE);
580 static HRESULT interp_assign_member(exec_ctx_t *ctx)
582 BSTR identifier = ctx->instr->arg1.bstr;
583 variant_val_t val;
584 IDispatch *obj;
585 DISPID id;
586 HRESULT hres;
588 TRACE("%s\n", debugstr_w(identifier));
590 hres = stack_pop_disp(ctx, &obj);
591 if(FAILED(hres))
592 return hres;
594 if(!obj) {
595 FIXME("NULL obj\n");
596 return E_FAIL;
599 hres = stack_pop_val(ctx, &val);
600 if(FAILED(hres)) {
601 IDispatch_Release(obj);
602 return hres;
605 hres = disp_get_id(obj, identifier, VBDISP_LET, FALSE, &id);
606 if(SUCCEEDED(hres))
607 hres = disp_propput(ctx->script, obj, id, val.v);
609 release_val(&val);
610 IDispatch_Release(obj);
611 return hres;
614 static HRESULT interp_set_member(exec_ctx_t *ctx)
616 BSTR identifier = ctx->instr->arg1.bstr;
617 IDispatch *obj, *val;
618 DISPID id;
619 HRESULT hres;
621 TRACE("%s\n", debugstr_w(identifier));
623 hres = stack_pop_disp(ctx, &obj);
624 if(FAILED(hres))
625 return hres;
627 if(!obj) {
628 FIXME("NULL obj\n");
629 return E_FAIL;
632 hres = stack_pop_disp(ctx, &val);
633 if(FAILED(hres)) {
634 IDispatch_Release(obj);
635 return hres;
638 hres = disp_get_id(obj, identifier, VBDISP_SET, FALSE, &id);
639 if(SUCCEEDED(hres)) {
640 VARIANT v;
642 V_VT(&v) = VT_DISPATCH;
643 V_DISPATCH(&v) = val;
644 hres = disp_propput(ctx->script, obj, id, &v);
647 if(val)
648 IDispatch_Release(val);
649 IDispatch_Release(obj);
650 return hres;
653 static HRESULT interp_const(exec_ctx_t *ctx)
655 BSTR arg = ctx->instr->arg1.bstr;
656 FIXME("%s\n", debugstr_w(arg));
657 return E_NOTIMPL;
660 static HRESULT interp_new(exec_ctx_t *ctx)
662 const WCHAR *arg = ctx->instr->arg1.bstr;
663 class_desc_t *class_desc;
664 vbdisp_t *obj;
665 VARIANT v;
666 HRESULT hres;
668 TRACE("%s\n", debugstr_w(arg));
670 for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
671 if(!strcmpiW(class_desc->name, arg))
672 break;
674 if(!class_desc) {
675 FIXME("Class %s not found\n", debugstr_w(arg));
676 return E_FAIL;
679 hres = create_vbdisp(class_desc, &obj);
680 if(FAILED(hres))
681 return hres;
683 V_VT(&v) = VT_DISPATCH;
684 V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
685 return stack_push(ctx, &v);
688 static HRESULT interp_jmp(exec_ctx_t *ctx)
690 const unsigned arg = ctx->instr->arg1.uint;
692 TRACE("%u\n", arg);
694 instr_jmp(ctx, arg);
695 return S_OK;
698 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
700 const unsigned arg = ctx->instr->arg1.uint;
701 variant_val_t val;
702 HRESULT hres;
704 TRACE("%u\n", arg);
706 hres = stack_pop_val(ctx, &val);
707 if(FAILED(hres))
708 return hres;
710 if(V_VT(val.v) != VT_BOOL) {
711 FIXME("unsupported for %s\n", debugstr_variant(val.v));
712 release_val(&val);
713 return E_NOTIMPL;
716 if(V_BOOL(val.v))
717 ctx->instr++;
718 else
719 instr_jmp(ctx, ctx->instr->arg1.uint);
720 return S_OK;
723 static HRESULT interp_jmp_true(exec_ctx_t *ctx)
725 const unsigned arg = ctx->instr->arg1.uint;
726 variant_val_t val;
727 HRESULT hres;
729 TRACE("%u\n", arg);
731 hres = stack_pop_val(ctx, &val);
732 if(FAILED(hres))
733 return hres;
735 if(V_VT(val.v) != VT_BOOL) {
736 FIXME("unsupported for %s\n", debugstr_variant(val.v));
737 release_val(&val);
738 return E_NOTIMPL;
741 if(V_BOOL(val.v))
742 instr_jmp(ctx, ctx->instr->arg1.uint);
743 else
744 ctx->instr++;
745 return S_OK;
748 static HRESULT interp_ret(exec_ctx_t *ctx)
750 TRACE("\n");
752 ctx->instr = NULL;
753 return S_OK;
756 static HRESULT interp_stop(exec_ctx_t *ctx)
758 WARN("\n");
760 /* NOTE: this should have effect in debugging mode (that we don't support yet) */
761 return S_OK;
764 static HRESULT interp_me(exec_ctx_t *ctx)
766 VARIANT v;
768 TRACE("\n");
770 IDispatch_AddRef(ctx->this_obj);
771 V_VT(&v) = VT_DISPATCH;
772 V_DISPATCH(&v) = ctx->this_obj;
773 return stack_push(ctx, &v);
776 static HRESULT interp_bool(exec_ctx_t *ctx)
778 const VARIANT_BOOL arg = ctx->instr->arg1.lng;
779 VARIANT v;
781 TRACE("%s\n", arg ? "true" : "false");
783 V_VT(&v) = VT_BOOL;
784 V_BOOL(&v) = arg;
785 return stack_push(ctx, &v);
788 static HRESULT interp_errmode(exec_ctx_t *ctx)
790 const int err_mode = ctx->instr->arg1.uint;
791 FIXME("%d\n", err_mode);
792 return E_NOTIMPL;
795 static HRESULT interp_string(exec_ctx_t *ctx)
797 VARIANT v;
799 TRACE("\n");
801 V_VT(&v) = VT_BSTR;
802 V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
803 if(!V_BSTR(&v))
804 return E_OUTOFMEMORY;
806 return stack_push(ctx, &v);
809 static HRESULT interp_long(exec_ctx_t *ctx)
811 const LONG arg = ctx->instr->arg1.lng;
812 VARIANT v;
814 TRACE("%d\n", arg);
816 V_VT(&v) = VT_I4;
817 V_I4(&v) = arg;
818 return stack_push(ctx, &v);
821 static HRESULT interp_short(exec_ctx_t *ctx)
823 const LONG arg = ctx->instr->arg1.lng;
824 VARIANT v;
826 TRACE("%d\n", arg);
828 V_VT(&v) = VT_I2;
829 V_I2(&v) = arg;
830 return stack_push(ctx, &v);
833 static HRESULT interp_double(exec_ctx_t *ctx)
835 const DOUBLE *arg = ctx->instr->arg1.dbl;
836 VARIANT v;
838 TRACE("%lf\n", *arg);
840 V_VT(&v) = VT_R8;
841 V_R8(&v) = *arg;
842 return stack_push(ctx, &v);
845 static HRESULT interp_empty(exec_ctx_t *ctx)
847 VARIANT v;
849 TRACE("\n");
851 V_VT(&v) = VT_EMPTY;
852 return stack_push(ctx, &v);
855 static HRESULT interp_null(exec_ctx_t *ctx)
857 VARIANT v;
859 TRACE("\n");
861 V_VT(&v) = VT_NULL;
862 return stack_push(ctx, &v);
865 static HRESULT interp_nothing(exec_ctx_t *ctx)
867 VARIANT v;
869 TRACE("\n");
871 V_VT(&v) = VT_DISPATCH;
872 V_DISPATCH(&v) = NULL;
873 return stack_push(ctx, &v);
876 static HRESULT interp_not(exec_ctx_t *ctx)
878 variant_val_t val;
879 VARIANT v;
880 HRESULT hres;
882 TRACE("\n");
884 hres = stack_pop_val(ctx, &val);
885 if(FAILED(hres))
886 return hres;
888 hres = VarNot(val.v, &v);
889 release_val(&val);
890 if(FAILED(hres))
891 return hres;
893 return stack_push(ctx, &v);
896 static HRESULT interp_and(exec_ctx_t *ctx)
898 variant_val_t r, l;
899 VARIANT v;
900 HRESULT hres;
902 TRACE("\n");
904 hres = stack_pop_val(ctx, &r);
905 if(FAILED(hres))
906 return hres;
908 hres = stack_pop_val(ctx, &l);
909 if(SUCCEEDED(hres)) {
910 hres = VarAnd(l.v, r.v, &v);
911 release_val(&l);
913 release_val(&r);
914 if(FAILED(hres))
915 return hres;
917 return stack_push(ctx, &v);
920 static HRESULT interp_or(exec_ctx_t *ctx)
922 variant_val_t r, l;
923 VARIANT v;
924 HRESULT hres;
926 TRACE("\n");
928 hres = stack_pop_val(ctx, &r);
929 if(FAILED(hres))
930 return hres;
932 hres = stack_pop_val(ctx, &l);
933 if(SUCCEEDED(hres)) {
934 hres = VarOr(l.v, r.v, &v);
935 release_val(&l);
937 release_val(&r);
938 if(FAILED(hres))
939 return hres;
941 return stack_push(ctx, &v);
944 static HRESULT interp_xor(exec_ctx_t *ctx)
946 variant_val_t r, l;
947 VARIANT v;
948 HRESULT hres;
950 TRACE("\n");
952 hres = stack_pop_val(ctx, &r);
953 if(FAILED(hres))
954 return hres;
956 hres = stack_pop_val(ctx, &l);
957 if(SUCCEEDED(hres)) {
958 hres = VarXor(l.v, r.v, &v);
959 release_val(&l);
961 release_val(&r);
962 if(FAILED(hres))
963 return hres;
965 return stack_push(ctx, &v);
968 static HRESULT interp_eqv(exec_ctx_t *ctx)
970 variant_val_t r, l;
971 VARIANT v;
972 HRESULT hres;
974 TRACE("\n");
976 hres = stack_pop_val(ctx, &r);
977 if(FAILED(hres))
978 return hres;
980 hres = stack_pop_val(ctx, &l);
981 if(SUCCEEDED(hres)) {
982 hres = VarEqv(l.v, r.v, &v);
983 release_val(&l);
985 release_val(&r);
986 if(FAILED(hres))
987 return hres;
989 return stack_push(ctx, &v);
992 static HRESULT interp_imp(exec_ctx_t *ctx)
994 variant_val_t r, l;
995 VARIANT v;
996 HRESULT hres;
998 TRACE("\n");
1000 hres = stack_pop_val(ctx, &r);
1001 if(FAILED(hres))
1002 return hres;
1004 hres = stack_pop_val(ctx, &l);
1005 if(SUCCEEDED(hres)) {
1006 hres = VarImp(l.v, r.v, &v);
1007 release_val(&l);
1009 release_val(&r);
1010 if(FAILED(hres))
1011 return hres;
1013 return stack_push(ctx, &v);
1016 static HRESULT cmp_oper(exec_ctx_t *ctx)
1018 variant_val_t l, r;
1019 HRESULT hres;
1021 hres = stack_pop_val(ctx, &r);
1022 if(FAILED(hres))
1023 return hres;
1025 hres = stack_pop_val(ctx, &l);
1026 if(SUCCEEDED(hres)) {
1027 if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
1028 FIXME("comparing nulls is not implemented\n");
1029 hres = E_NOTIMPL;
1030 }else {
1031 hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
1035 release_val(&r);
1036 release_val(&l);
1037 return hres;
1040 static HRESULT interp_equal(exec_ctx_t *ctx)
1042 VARIANT v;
1043 HRESULT hres;
1045 TRACE("\n");
1047 hres = cmp_oper(ctx);
1048 if(FAILED(hres))
1049 return hres;
1051 V_VT(&v) = VT_BOOL;
1052 V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1053 return stack_push(ctx, &v);
1056 static HRESULT interp_nequal(exec_ctx_t *ctx)
1058 VARIANT v;
1059 HRESULT hres;
1061 TRACE("\n");
1063 hres = cmp_oper(ctx);
1064 if(FAILED(hres))
1065 return hres;
1067 V_VT(&v) = VT_BOOL;
1068 V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1069 return stack_push(ctx, &v);
1072 static HRESULT interp_gt(exec_ctx_t *ctx)
1074 VARIANT v;
1075 HRESULT hres;
1077 TRACE("\n");
1079 hres = cmp_oper(ctx);
1080 if(FAILED(hres))
1081 return hres;
1083 V_VT(&v) = VT_BOOL;
1084 V_BOOL(&v) = hres == VARCMP_GT ? VARIANT_TRUE : VARIANT_FALSE;
1085 return stack_push(ctx, &v);
1088 static HRESULT interp_gteq(exec_ctx_t *ctx)
1090 VARIANT v;
1091 HRESULT hres;
1093 TRACE("\n");
1095 hres = cmp_oper(ctx);
1096 if(FAILED(hres))
1097 return hres;
1099 V_VT(&v) = VT_BOOL;
1100 V_BOOL(&v) = hres == VARCMP_GT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1101 return stack_push(ctx, &v);
1104 static HRESULT interp_lt(exec_ctx_t *ctx)
1106 VARIANT v;
1107 HRESULT hres;
1109 TRACE("\n");
1111 hres = cmp_oper(ctx);
1112 if(FAILED(hres))
1113 return hres;
1115 V_VT(&v) = VT_BOOL;
1116 V_BOOL(&v) = hres == VARCMP_LT ? VARIANT_TRUE : VARIANT_FALSE;
1117 return stack_push(ctx, &v);
1120 static HRESULT interp_lteq(exec_ctx_t *ctx)
1122 VARIANT v;
1123 HRESULT hres;
1125 TRACE("\n");
1127 hres = cmp_oper(ctx);
1128 if(FAILED(hres))
1129 return hres;
1131 V_VT(&v) = VT_BOOL;
1132 V_BOOL(&v) = hres == VARCMP_LT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1133 return stack_push(ctx, &v);
1136 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, VARIANT_BOOL *ret)
1138 IObjectIdentity *identity;
1139 IUnknown *unk1, *unk2;
1140 HRESULT hres;
1142 if(disp1 == disp2) {
1143 *ret = VARIANT_TRUE;
1144 return S_OK;
1147 if(!disp1 || !disp2) {
1148 *ret = VARIANT_FALSE;
1149 return S_OK;
1152 hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
1153 if(FAILED(hres))
1154 return hres;
1156 hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
1157 if(FAILED(hres)) {
1158 IUnknown_Release(unk1);
1159 return hres;
1162 if(unk1 == unk2) {
1163 *ret = VARIANT_TRUE;
1164 }else {
1165 hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
1166 if(SUCCEEDED(hres)) {
1167 hres = IObjectIdentity_IsEqualObject(identity, unk2);
1168 IObjectIdentity_Release(identity);
1169 *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
1170 }else {
1171 *ret = VARIANT_FALSE;
1175 IUnknown_Release(unk1);
1176 IUnknown_Release(unk2);
1177 return S_OK;
1180 static HRESULT interp_is(exec_ctx_t *ctx)
1182 IDispatch *l, *r;
1183 VARIANT v;
1184 HRESULT hres;
1186 TRACE("\n");
1188 hres = stack_pop_disp(ctx, &r);
1189 if(FAILED(hres))
1190 return hres;
1192 hres = stack_pop_disp(ctx, &l);
1193 if(SUCCEEDED(hres)) {
1194 V_VT(&v) = VT_BOOL;
1195 hres = disp_cmp(l, r, &V_BOOL(&v));
1196 if(l)
1197 IDispatch_Release(l);
1199 if(r)
1200 IDispatch_Release(r);
1201 if(FAILED(hres))
1202 return hres;
1204 return stack_push(ctx, &v);
1207 static HRESULT interp_concat(exec_ctx_t *ctx)
1209 variant_val_t r, l;
1210 VARIANT v;
1211 HRESULT hres;
1213 TRACE("\n");
1215 hres = stack_pop_val(ctx, &r);
1216 if(FAILED(hres))
1217 return hres;
1219 hres = stack_pop_val(ctx, &l);
1220 if(SUCCEEDED(hres)) {
1221 hres = VarCat(l.v, r.v, &v);
1222 release_val(&l);
1224 release_val(&r);
1225 if(FAILED(hres))
1226 return hres;
1228 return stack_push(ctx, &v);
1231 static HRESULT interp_add(exec_ctx_t *ctx)
1233 variant_val_t r, l;
1234 VARIANT v;
1235 HRESULT hres;
1237 TRACE("\n");
1239 hres = stack_pop_val(ctx, &r);
1240 if(FAILED(hres))
1241 return hres;
1243 hres = stack_pop_val(ctx, &l);
1244 if(SUCCEEDED(hres)) {
1245 hres = VarAdd(l.v, r.v, &v);
1246 release_val(&l);
1248 release_val(&r);
1249 if(FAILED(hres))
1250 return hres;
1252 return stack_push(ctx, &v);
1255 static HRESULT interp_sub(exec_ctx_t *ctx)
1257 variant_val_t r, l;
1258 VARIANT v;
1259 HRESULT hres;
1261 TRACE("\n");
1263 hres = stack_pop_val(ctx, &r);
1264 if(FAILED(hres))
1265 return hres;
1267 hres = stack_pop_val(ctx, &l);
1268 if(SUCCEEDED(hres)) {
1269 hres = VarSub(l.v, r.v, &v);
1270 release_val(&l);
1272 release_val(&r);
1273 if(FAILED(hres))
1274 return hres;
1276 return stack_push(ctx, &v);
1279 static HRESULT interp_mod(exec_ctx_t *ctx)
1281 variant_val_t r, l;
1282 VARIANT v;
1283 HRESULT hres;
1285 TRACE("\n");
1287 hres = stack_pop_val(ctx, &r);
1288 if(FAILED(hres))
1289 return hres;
1291 hres = stack_pop_val(ctx, &l);
1292 if(SUCCEEDED(hres)) {
1293 hres = VarMod(l.v, r.v, &v);
1294 release_val(&l);
1296 release_val(&r);
1297 if(FAILED(hres))
1298 return hres;
1300 return stack_push(ctx, &v);
1303 static HRESULT interp_idiv(exec_ctx_t *ctx)
1305 variant_val_t r, l;
1306 VARIANT v;
1307 HRESULT hres;
1309 TRACE("\n");
1311 hres = stack_pop_val(ctx, &r);
1312 if(FAILED(hres))
1313 return hres;
1315 hres = stack_pop_val(ctx, &l);
1316 if(SUCCEEDED(hres)) {
1317 hres = VarIdiv(l.v, r.v, &v);
1318 release_val(&l);
1320 release_val(&r);
1321 if(FAILED(hres))
1322 return hres;
1324 return stack_push(ctx, &v);
1327 static HRESULT interp_div(exec_ctx_t *ctx)
1329 variant_val_t r, l;
1330 VARIANT v;
1331 HRESULT hres;
1333 TRACE("\n");
1335 hres = stack_pop_val(ctx, &r);
1336 if(FAILED(hres))
1337 return hres;
1339 hres = stack_pop_val(ctx, &l);
1340 if(SUCCEEDED(hres)) {
1341 hres = VarDiv(l.v, r.v, &v);
1342 release_val(&l);
1344 release_val(&r);
1345 if(FAILED(hres))
1346 return hres;
1348 return stack_push(ctx, &v);
1351 static HRESULT interp_mul(exec_ctx_t *ctx)
1353 variant_val_t r, l;
1354 VARIANT v;
1355 HRESULT hres;
1357 TRACE("\n");
1359 hres = stack_pop_val(ctx, &r);
1360 if(FAILED(hres))
1361 return hres;
1363 hres = stack_pop_val(ctx, &l);
1364 if(SUCCEEDED(hres)) {
1365 hres = VarMul(l.v, r.v, &v);
1366 release_val(&l);
1368 release_val(&r);
1369 if(FAILED(hres))
1370 return hres;
1372 return stack_push(ctx, &v);
1375 static HRESULT interp_exp(exec_ctx_t *ctx)
1377 variant_val_t r, l;
1378 VARIANT v;
1379 HRESULT hres;
1381 TRACE("\n");
1383 hres = stack_pop_val(ctx, &r);
1384 if(FAILED(hres))
1385 return hres;
1387 hres = stack_pop_val(ctx, &l);
1388 if(SUCCEEDED(hres)) {
1389 hres = VarPow(l.v, r.v, &v);
1390 release_val(&l);
1392 release_val(&r);
1393 if(FAILED(hres))
1394 return hres;
1396 return stack_push(ctx, &v);
1399 static HRESULT interp_neg(exec_ctx_t *ctx)
1401 variant_val_t val;
1402 VARIANT v;
1403 HRESULT hres;
1405 hres = stack_pop_val(ctx, &val);
1406 if(FAILED(hres))
1407 return hres;
1409 hres = VarNeg(val.v, &v);
1410 release_val(&val);
1411 if(FAILED(hres))
1412 return hres;
1414 return stack_push(ctx, &v);
1417 static const instr_func_t op_funcs[] = {
1418 #define X(x,n,a,b) interp_ ## x,
1419 OP_LIST
1420 #undef X
1423 static const unsigned op_move[] = {
1424 #define X(x,n,a,b) n,
1425 OP_LIST
1426 #undef X
1429 static void release_exec(exec_ctx_t *ctx)
1431 unsigned i;
1433 VariantClear(&ctx->ret_val);
1435 if(ctx->this_obj)
1436 IDispatch_Release(ctx->this_obj);
1438 if(ctx->args) {
1439 for(i=0; i < ctx->func->arg_cnt; i++)
1440 VariantClear(ctx->args+i);
1443 if(ctx->vars) {
1444 for(i=0; i < ctx->func->var_cnt; i++)
1445 VariantClear(ctx->vars+i);
1448 vbsheap_free(&ctx->heap);
1449 heap_free(ctx->args);
1450 heap_free(ctx->vars);
1451 heap_free(ctx->stack);
1454 HRESULT exec_script(script_ctx_t *ctx, function_t *func, IDispatch *this_obj, DISPPARAMS *dp, VARIANT *res)
1456 exec_ctx_t exec = {func->code_ctx};
1457 vbsop_t op;
1458 HRESULT hres = S_OK;
1460 exec.code = func->code_ctx;
1462 if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
1463 FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
1464 return E_FAIL;
1467 vbsheap_init(&exec.heap);
1469 if(func->arg_cnt) {
1470 VARIANT *v;
1471 unsigned i;
1473 exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
1474 if(!exec.args) {
1475 release_exec(&exec);
1476 return E_OUTOFMEMORY;
1479 for(i=0; i < func->arg_cnt; i++) {
1480 v = get_arg(dp, i);
1481 if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
1482 if(func->args[i].by_ref)
1483 exec.args[i] = *v;
1484 else
1485 hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
1486 }else {
1487 hres = VariantCopy(exec.args+i, v);
1489 if(FAILED(hres)) {
1490 release_exec(&exec);
1491 return hres;
1494 }else {
1495 exec.args = NULL;
1498 if(func->var_cnt) {
1499 exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
1500 if(!exec.vars) {
1501 release_exec(&exec);
1502 return E_OUTOFMEMORY;
1504 }else {
1505 exec.vars = NULL;
1508 exec.stack_size = 16;
1509 exec.top = 0;
1510 exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
1511 if(!exec.stack) {
1512 release_exec(&exec);
1513 return E_OUTOFMEMORY;
1516 if(this_obj)
1517 exec.this_obj = this_obj;
1518 else if (ctx->host_global)
1519 exec.this_obj = ctx->host_global;
1520 else
1521 exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface;
1522 IDispatch_AddRef(exec.this_obj);
1524 exec.instr = exec.code->instrs + func->code_off;
1525 exec.script = ctx;
1526 exec.func = func;
1528 while(exec.instr) {
1529 op = exec.instr->op;
1530 hres = op_funcs[op](&exec);
1531 if(FAILED(hres)) {
1532 FIXME("Failed %08x\n", hres);
1533 stack_popn(&exec, exec.top);
1534 break;
1537 exec.instr += op_move[op];
1540 assert(!exec.top);
1541 if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)
1542 assert(V_VT(&exec.ret_val) == VT_EMPTY);
1544 if(SUCCEEDED(hres) && res) {
1545 *res = exec.ret_val;
1546 V_VT(&exec.ret_val) = VT_EMPTY;
1549 release_exec(&exec);
1551 return hres;