vbscript: Added interp_step implementation.
[wine.git] / dlls / vbscript / interp.c
blobc95183d93adf18eb7166320589548b003d0fc83b
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);
27 typedef struct {
28 vbscode_t *code;
29 instr_t *instr;
30 script_ctx_t *script;
31 function_t *func;
32 IDispatch *this_obj;
34 VARIANT *args;
35 VARIANT *vars;
37 dynamic_var_t *dynamic_vars;
38 vbsheap_t heap;
40 unsigned stack_size;
41 unsigned top;
42 VARIANT *stack;
44 VARIANT ret_val;
45 } exec_ctx_t;
47 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
49 typedef enum {
50 REF_NONE,
51 REF_DISP,
52 REF_VAR,
53 REF_OBJ,
54 REF_CONST,
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 = var->is_const ? REF_CONST : 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, BOOL is_const, 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;
221 new_var->is_const = is_const;
223 if(own_val) {
224 new_var->v = *val;
225 }else {
226 hres = VariantCopy(&new_var->v, val);
227 if(FAILED(hres))
228 return hres;
231 if(ctx->func->type == FUNC_GLOBAL) {
232 new_var->next = ctx->script->global_vars;
233 ctx->script->global_vars = new_var;
234 }else {
235 new_var->next = ctx->dynamic_vars;
236 ctx->dynamic_vars = new_var;
239 return S_OK;
242 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
244 assert(ctx->top);
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) {
257 VARIANT *new_stack;
259 new_stack = heap_realloc(ctx->stack, ctx->stack_size*2);
260 if(!new_stack) {
261 VariantClear(v);
262 return E_OUTOFMEMORY;
265 ctx->stack = new_stack;
266 ctx->stack_size *= 2;
269 ctx->stack[ctx->top++] = *v;
270 return S_OK;
273 static void stack_popn(exec_ctx_t *ctx, unsigned n)
275 while(n--)
276 VariantClear(stack_pop(ctx));
279 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *v)
281 VARIANT *var;
283 var = stack_pop(ctx);
285 if(V_VT(var) == (VT_BYREF|VT_VARIANT)) {
286 v->owned = FALSE;
287 var = V_VARIANTREF(var);
288 }else {
289 v->owned = TRUE;
292 if(V_VT(var) == VT_DISPATCH) {
293 DISPPARAMS dp = {0};
294 HRESULT hres;
296 hres = disp_call(ctx->script, V_DISPATCH(var), DISPID_VALUE, &dp, &v->store);
297 if(v->owned)
298 IDispatch_Release(V_DISPATCH(var));
299 if(FAILED(hres))
300 return hres;
302 v->owned = TRUE;
303 v->v = &v->store;
304 }else {
305 v->v = var;
308 return S_OK;
311 static inline void release_val(variant_val_t *v)
313 if(v->owned)
314 VariantClear(v->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);
323 return S_OK;
326 if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
327 FIXME("not supported type: %s\n", debugstr_variant(v));
328 VariantClear(v);
329 return E_FAIL;
332 v = V_BYREF(v);
333 if(V_VT(v) != VT_DISPATCH) {
334 FIXME("not disp %s\n", debugstr_variant(v));
335 return E_FAIL;
338 if(V_DISPATCH(v))
339 IDispatch_AddRef(V_DISPATCH(v));
340 *ret = V_DISPATCH(v);
341 return S_OK;
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)
351 dp->cArgs = arg_cnt;
352 dp->rgdispidNamedArgs = NULL;
353 dp->cNamedArgs = 0;
355 if(arg_cnt) {
356 VARIANT tmp;
357 unsigned i;
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;
368 }else {
369 dp->rgvarg = NULL;
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;
377 DISPPARAMS dp;
378 ref_t ref;
379 HRESULT hres;
381 hres = lookup_identifier(ctx, identifier, VBDISP_CALLGET, &ref);
382 if(FAILED(hres))
383 return hres;
385 vbstack_to_dp(ctx, arg_cnt, &dp);
387 switch(ref.type) {
388 case REF_VAR:
389 case REF_CONST:
390 if(!res) {
391 FIXME("REF_VAR no res\n");
392 return E_NOTIMPL;
395 if(arg_cnt) {
396 FIXME("arguments not implemented\n");
397 return E_NOTIMPL;
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;
402 break;
403 case REF_DISP:
404 hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
405 if(FAILED(hres))
406 return hres;
407 break;
408 case REF_FUNC:
409 hres = exec_script(ctx->script, ref.u.f, NULL, &dp, res);
410 if(FAILED(hres))
411 return hres;
412 break;
413 case REF_OBJ:
414 if(arg_cnt) {
415 FIXME("arguments on object\n");
416 return E_NOTIMPL;
419 if(res) {
420 IDispatch_AddRef(ref.u.obj);
421 V_VT(res) = VT_DISPATCH;
422 V_DISPATCH(res) = ref.u.obj;
424 break;
425 case REF_NONE:
426 FIXME("%s not found\n", debugstr_w(identifier));
427 return DISP_E_UNKNOWNNAME;
430 stack_popn(ctx, arg_cnt);
431 return S_OK;
434 static HRESULT interp_icall(exec_ctx_t *ctx)
436 VARIANT v;
437 HRESULT hres;
439 TRACE("\n");
441 hres = do_icall(ctx, &v);
442 if(FAILED(hres))
443 return hres;
445 return stack_push(ctx, &v);
448 static HRESULT interp_icallv(exec_ctx_t *ctx)
450 TRACE("\n");
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;
458 IDispatch *obj;
459 DISPPARAMS dp;
460 DISPID id;
461 HRESULT hres;
463 hres = stack_pop_disp(ctx, &obj);
464 if(FAILED(hres))
465 return hres;
467 if(!obj) {
468 FIXME("NULL obj\n");
469 return E_FAIL;
472 vbstack_to_dp(ctx, arg_cnt, &dp);
474 hres = disp_get_id(obj, identifier, VBDISP_CALLGET, FALSE, &id);
475 if(SUCCEEDED(hres))
476 hres = disp_call(ctx->script, obj, id, &dp, res);
477 IDispatch_Release(obj);
478 if(FAILED(hres))
479 return hres;
481 stack_popn(ctx, arg_cnt);
482 return S_OK;
485 static HRESULT interp_mcall(exec_ctx_t *ctx)
487 VARIANT res;
488 HRESULT hres;
490 TRACE("\n");
492 hres = do_mcall(ctx, &res);
493 if(FAILED(hres))
494 return hres;
496 return stack_push(ctx, &res);
499 static HRESULT interp_mcallv(exec_ctx_t *ctx)
501 TRACE("\n");
503 return do_mcall(ctx, NULL);
506 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
508 ref_t ref;
509 HRESULT hres;
511 hres = lookup_identifier(ctx, name, VBDISP_LET, &ref);
512 if(FAILED(hres))
513 return hres;
515 switch(ref.type) {
516 case REF_VAR: {
517 VARIANT *v = ref.u.v;
519 if(V_VT(v) == (VT_VARIANT|VT_BYREF))
520 v = V_VARIANTREF(v);
522 if(own_val) {
523 VariantClear(v);
524 *v = *val;
525 hres = S_OK;
526 }else {
527 hres = VariantCopy(v, val);
529 break;
531 case REF_DISP:
532 hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, val);
533 if(own_val)
534 VariantClear(val);
535 break;
536 case REF_FUNC:
537 FIXME("functions not implemented\n");
538 return E_NOTIMPL;
539 case REF_OBJ:
540 FIXME("REF_OBJ\n");
541 return E_NOTIMPL;
542 case REF_CONST:
543 FIXME("REF_CONST\n");
544 return E_NOTIMPL;
545 case REF_NONE:
546 if(ctx->func->code_ctx->option_explicit) {
547 FIXME("throw exception\n");
548 hres = E_FAIL;
549 }else {
550 TRACE("creating variable %s\n", debugstr_w(name));
551 hres = add_dynamic_var(ctx, name, FALSE, val, own_val);
555 return hres;
558 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
560 const BSTR arg = ctx->instr->arg1.bstr;
561 variant_val_t v;
562 HRESULT hres;
564 TRACE("%s\n", debugstr_w(arg));
566 hres = stack_pop_val(ctx, &v);
567 if(FAILED(hres))
568 return hres;
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;
576 IDispatch *disp;
577 VARIANT v;
578 HRESULT hres;
580 TRACE("%s\n", debugstr_w(arg));
582 hres = stack_pop_disp(ctx, &disp);
583 if(FAILED(hres))
584 return hres;
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;
594 variant_val_t val;
595 IDispatch *obj;
596 DISPID id;
597 HRESULT hres;
599 TRACE("%s\n", debugstr_w(identifier));
601 hres = stack_pop_disp(ctx, &obj);
602 if(FAILED(hres))
603 return hres;
605 if(!obj) {
606 FIXME("NULL obj\n");
607 return E_FAIL;
610 hres = stack_pop_val(ctx, &val);
611 if(FAILED(hres)) {
612 IDispatch_Release(obj);
613 return hres;
616 hres = disp_get_id(obj, identifier, VBDISP_LET, FALSE, &id);
617 if(SUCCEEDED(hres))
618 hres = disp_propput(ctx->script, obj, id, val.v);
620 release_val(&val);
621 IDispatch_Release(obj);
622 return hres;
625 static HRESULT interp_set_member(exec_ctx_t *ctx)
627 BSTR identifier = ctx->instr->arg1.bstr;
628 IDispatch *obj, *val;
629 DISPID id;
630 HRESULT hres;
632 TRACE("%s\n", debugstr_w(identifier));
634 hres = stack_pop_disp(ctx, &obj);
635 if(FAILED(hres))
636 return hres;
638 if(!obj) {
639 FIXME("NULL obj\n");
640 return E_FAIL;
643 hres = stack_pop_disp(ctx, &val);
644 if(FAILED(hres)) {
645 IDispatch_Release(obj);
646 return hres;
649 hres = disp_get_id(obj, identifier, VBDISP_SET, FALSE, &id);
650 if(SUCCEEDED(hres)) {
651 VARIANT v;
653 V_VT(&v) = VT_DISPATCH;
654 V_DISPATCH(&v) = val;
655 hres = disp_propput(ctx->script, obj, id, &v);
658 if(val)
659 IDispatch_Release(val);
660 IDispatch_Release(obj);
661 return hres;
664 static HRESULT interp_const(exec_ctx_t *ctx)
666 BSTR arg = ctx->instr->arg1.bstr;
667 variant_val_t val;
668 ref_t ref;
669 HRESULT hres;
671 TRACE("%s\n", debugstr_w(arg));
673 assert(ctx->func->type == FUNC_GLOBAL);
675 hres = lookup_identifier(ctx, arg, VBDISP_CALLGET, &ref);
676 if(FAILED(hres))
677 return hres;
679 if(ref.type != REF_NONE) {
680 FIXME("%s already defined\n", debugstr_w(arg));
681 return E_FAIL;
684 hres = stack_pop_val(ctx, &val);
685 if(FAILED(hres))
686 return hres;
688 return add_dynamic_var(ctx, arg, TRUE, val.v, val.owned);
691 static HRESULT interp_val(exec_ctx_t *ctx)
693 variant_val_t val;
694 VARIANT v;
695 HRESULT hres;
697 TRACE("\n");
699 hres = stack_pop_val(ctx, &val);
700 if(FAILED(hres))
701 return hres;
703 if(!val.owned) {
704 V_VT(&v) = VT_EMPTY;
705 hres = VariantCopy(&v, val.v);
706 if(FAILED(hres))
707 return hres;
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;
717 TRACE("%u\n", n);
719 stack_popn(ctx, n);
720 return S_OK;
723 static HRESULT interp_new(exec_ctx_t *ctx)
725 const WCHAR *arg = ctx->instr->arg1.bstr;
726 class_desc_t *class_desc;
727 vbdisp_t *obj;
728 VARIANT v;
729 HRESULT hres;
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))
735 break;
737 if(!class_desc) {
738 FIXME("Class %s not found\n", debugstr_w(arg));
739 return E_FAIL;
742 hres = create_vbdisp(class_desc, &obj);
743 if(FAILED(hres))
744 return hres;
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;
754 BOOL gteq_zero;
755 VARIANT zero;
756 ref_t ref;
757 HRESULT hres;
759 TRACE("%s\n", debugstr_w(ident));
761 V_VT(&zero) = VT_I2;
762 V_I2(&zero) = 0;
763 hres = VarCmp(stack_top(ctx, 0), &zero, ctx->script->lcid, 0);
764 if(FAILED(hres))
765 return hres;
767 gteq_zero = hres == VARCMP_GT || hres == VARCMP_EQ;
769 hres = lookup_identifier(ctx, ident, VBDISP_ANY, &ref);
770 if(FAILED(hres))
771 return hres;
773 if(ref.type != REF_VAR) {
774 FIXME("%s is not REF_VAR\n", debugstr_w(ident));
775 return E_FAIL;
778 hres = VarCmp(ref.u.v, stack_top(ctx, 1), ctx->script->lcid, 0);
779 if(FAILED(hres))
780 return hres;
782 if(hres == VARCMP_EQ || hres == (gteq_zero ? VARCMP_LT : VARCMP_GT))
783 ctx->instr++;
784 else
785 instr_jmp(ctx, ctx->instr->arg1.uint);
786 return S_OK;
789 static HRESULT interp_jmp(exec_ctx_t *ctx)
791 const unsigned arg = ctx->instr->arg1.uint;
793 TRACE("%u\n", arg);
795 instr_jmp(ctx, arg);
796 return S_OK;
799 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
801 const unsigned arg = ctx->instr->arg1.uint;
802 variant_val_t val;
803 HRESULT hres;
805 TRACE("%u\n", arg);
807 hres = stack_pop_val(ctx, &val);
808 if(FAILED(hres))
809 return hres;
811 if(V_VT(val.v) != VT_BOOL) {
812 FIXME("unsupported for %s\n", debugstr_variant(val.v));
813 release_val(&val);
814 return E_NOTIMPL;
817 if(V_BOOL(val.v))
818 ctx->instr++;
819 else
820 instr_jmp(ctx, ctx->instr->arg1.uint);
821 return S_OK;
824 static HRESULT interp_jmp_true(exec_ctx_t *ctx)
826 const unsigned arg = ctx->instr->arg1.uint;
827 variant_val_t val;
828 HRESULT hres;
830 TRACE("%u\n", arg);
832 hres = stack_pop_val(ctx, &val);
833 if(FAILED(hres))
834 return hres;
836 if(V_VT(val.v) != VT_BOOL) {
837 FIXME("unsupported for %s\n", debugstr_variant(val.v));
838 release_val(&val);
839 return E_NOTIMPL;
842 if(V_BOOL(val.v))
843 instr_jmp(ctx, ctx->instr->arg1.uint);
844 else
845 ctx->instr++;
846 return S_OK;
849 static HRESULT interp_ret(exec_ctx_t *ctx)
851 TRACE("\n");
853 ctx->instr = NULL;
854 return S_OK;
857 static HRESULT interp_stop(exec_ctx_t *ctx)
859 WARN("\n");
861 /* NOTE: this should have effect in debugging mode (that we don't support yet) */
862 return S_OK;
865 static HRESULT interp_me(exec_ctx_t *ctx)
867 VARIANT v;
869 TRACE("\n");
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;
880 VARIANT v;
882 TRACE("%s\n", arg ? "true" : "false");
884 V_VT(&v) = VT_BOOL;
885 V_BOOL(&v) = arg;
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);
893 return E_NOTIMPL;
896 static HRESULT interp_string(exec_ctx_t *ctx)
898 VARIANT v;
900 TRACE("\n");
902 V_VT(&v) = VT_BSTR;
903 V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
904 if(!V_BSTR(&v))
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;
913 VARIANT v;
915 TRACE("%d\n", arg);
917 V_VT(&v) = VT_I4;
918 V_I4(&v) = arg;
919 return stack_push(ctx, &v);
922 static HRESULT interp_short(exec_ctx_t *ctx)
924 const LONG arg = ctx->instr->arg1.lng;
925 VARIANT v;
927 TRACE("%d\n", arg);
929 V_VT(&v) = VT_I2;
930 V_I2(&v) = arg;
931 return stack_push(ctx, &v);
934 static HRESULT interp_double(exec_ctx_t *ctx)
936 const DOUBLE *arg = ctx->instr->arg1.dbl;
937 VARIANT v;
939 TRACE("%lf\n", *arg);
941 V_VT(&v) = VT_R8;
942 V_R8(&v) = *arg;
943 return stack_push(ctx, &v);
946 static HRESULT interp_empty(exec_ctx_t *ctx)
948 VARIANT v;
950 TRACE("\n");
952 V_VT(&v) = VT_EMPTY;
953 return stack_push(ctx, &v);
956 static HRESULT interp_null(exec_ctx_t *ctx)
958 VARIANT v;
960 TRACE("\n");
962 V_VT(&v) = VT_NULL;
963 return stack_push(ctx, &v);
966 static HRESULT interp_nothing(exec_ctx_t *ctx)
968 VARIANT v;
970 TRACE("\n");
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)
979 variant_val_t val;
980 VARIANT v;
981 HRESULT hres;
983 TRACE("\n");
985 hres = stack_pop_val(ctx, &val);
986 if(FAILED(hres))
987 return hres;
989 hres = VarNot(val.v, &v);
990 release_val(&val);
991 if(FAILED(hres))
992 return hres;
994 return stack_push(ctx, &v);
997 static HRESULT interp_and(exec_ctx_t *ctx)
999 variant_val_t r, l;
1000 VARIANT v;
1001 HRESULT hres;
1003 TRACE("\n");
1005 hres = stack_pop_val(ctx, &r);
1006 if(FAILED(hres))
1007 return hres;
1009 hres = stack_pop_val(ctx, &l);
1010 if(SUCCEEDED(hres)) {
1011 hres = VarAnd(l.v, r.v, &v);
1012 release_val(&l);
1014 release_val(&r);
1015 if(FAILED(hres))
1016 return hres;
1018 return stack_push(ctx, &v);
1021 static HRESULT interp_or(exec_ctx_t *ctx)
1023 variant_val_t r, l;
1024 VARIANT v;
1025 HRESULT hres;
1027 TRACE("\n");
1029 hres = stack_pop_val(ctx, &r);
1030 if(FAILED(hres))
1031 return hres;
1033 hres = stack_pop_val(ctx, &l);
1034 if(SUCCEEDED(hres)) {
1035 hres = VarOr(l.v, r.v, &v);
1036 release_val(&l);
1038 release_val(&r);
1039 if(FAILED(hres))
1040 return hres;
1042 return stack_push(ctx, &v);
1045 static HRESULT interp_xor(exec_ctx_t *ctx)
1047 variant_val_t r, l;
1048 VARIANT v;
1049 HRESULT hres;
1051 TRACE("\n");
1053 hres = stack_pop_val(ctx, &r);
1054 if(FAILED(hres))
1055 return hres;
1057 hres = stack_pop_val(ctx, &l);
1058 if(SUCCEEDED(hres)) {
1059 hres = VarXor(l.v, r.v, &v);
1060 release_val(&l);
1062 release_val(&r);
1063 if(FAILED(hres))
1064 return hres;
1066 return stack_push(ctx, &v);
1069 static HRESULT interp_eqv(exec_ctx_t *ctx)
1071 variant_val_t r, l;
1072 VARIANT v;
1073 HRESULT hres;
1075 TRACE("\n");
1077 hres = stack_pop_val(ctx, &r);
1078 if(FAILED(hres))
1079 return hres;
1081 hres = stack_pop_val(ctx, &l);
1082 if(SUCCEEDED(hres)) {
1083 hres = VarEqv(l.v, r.v, &v);
1084 release_val(&l);
1086 release_val(&r);
1087 if(FAILED(hres))
1088 return hres;
1090 return stack_push(ctx, &v);
1093 static HRESULT interp_imp(exec_ctx_t *ctx)
1095 variant_val_t r, l;
1096 VARIANT v;
1097 HRESULT hres;
1099 TRACE("\n");
1101 hres = stack_pop_val(ctx, &r);
1102 if(FAILED(hres))
1103 return hres;
1105 hres = stack_pop_val(ctx, &l);
1106 if(SUCCEEDED(hres)) {
1107 hres = VarImp(l.v, r.v, &v);
1108 release_val(&l);
1110 release_val(&r);
1111 if(FAILED(hres))
1112 return hres;
1114 return stack_push(ctx, &v);
1117 static HRESULT cmp_oper(exec_ctx_t *ctx)
1119 variant_val_t l, r;
1120 HRESULT hres;
1122 hres = stack_pop_val(ctx, &r);
1123 if(FAILED(hres))
1124 return hres;
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");
1130 hres = E_NOTIMPL;
1131 }else {
1132 hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
1136 release_val(&r);
1137 release_val(&l);
1138 return hres;
1141 static HRESULT interp_equal(exec_ctx_t *ctx)
1143 VARIANT v;
1144 HRESULT hres;
1146 TRACE("\n");
1148 hres = cmp_oper(ctx);
1149 if(FAILED(hres))
1150 return hres;
1152 V_VT(&v) = VT_BOOL;
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)
1159 VARIANT v;
1160 HRESULT hres;
1162 TRACE("\n");
1164 hres = cmp_oper(ctx);
1165 if(FAILED(hres))
1166 return hres;
1168 V_VT(&v) = VT_BOOL;
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)
1175 VARIANT v;
1176 HRESULT hres;
1178 TRACE("\n");
1180 hres = cmp_oper(ctx);
1181 if(FAILED(hres))
1182 return hres;
1184 V_VT(&v) = VT_BOOL;
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)
1191 VARIANT v;
1192 HRESULT hres;
1194 TRACE("\n");
1196 hres = cmp_oper(ctx);
1197 if(FAILED(hres))
1198 return hres;
1200 V_VT(&v) = VT_BOOL;
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)
1207 VARIANT v;
1208 HRESULT hres;
1210 TRACE("\n");
1212 hres = cmp_oper(ctx);
1213 if(FAILED(hres))
1214 return hres;
1216 V_VT(&v) = VT_BOOL;
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)
1223 VARIANT v;
1224 HRESULT hres;
1226 TRACE("\n");
1228 hres = cmp_oper(ctx);
1229 if(FAILED(hres))
1230 return hres;
1232 V_VT(&v) = VT_BOOL;
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;
1241 HRESULT hres;
1243 if(disp1 == disp2) {
1244 *ret = VARIANT_TRUE;
1245 return S_OK;
1248 if(!disp1 || !disp2) {
1249 *ret = VARIANT_FALSE;
1250 return S_OK;
1253 hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
1254 if(FAILED(hres))
1255 return hres;
1257 hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
1258 if(FAILED(hres)) {
1259 IUnknown_Release(unk1);
1260 return hres;
1263 if(unk1 == unk2) {
1264 *ret = VARIANT_TRUE;
1265 }else {
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;
1271 }else {
1272 *ret = VARIANT_FALSE;
1276 IUnknown_Release(unk1);
1277 IUnknown_Release(unk2);
1278 return S_OK;
1281 static HRESULT interp_is(exec_ctx_t *ctx)
1283 IDispatch *l, *r;
1284 VARIANT v;
1285 HRESULT hres;
1287 TRACE("\n");
1289 hres = stack_pop_disp(ctx, &r);
1290 if(FAILED(hres))
1291 return hres;
1293 hres = stack_pop_disp(ctx, &l);
1294 if(SUCCEEDED(hres)) {
1295 V_VT(&v) = VT_BOOL;
1296 hres = disp_cmp(l, r, &V_BOOL(&v));
1297 if(l)
1298 IDispatch_Release(l);
1300 if(r)
1301 IDispatch_Release(r);
1302 if(FAILED(hres))
1303 return hres;
1305 return stack_push(ctx, &v);
1308 static HRESULT interp_concat(exec_ctx_t *ctx)
1310 variant_val_t r, l;
1311 VARIANT v;
1312 HRESULT hres;
1314 TRACE("\n");
1316 hres = stack_pop_val(ctx, &r);
1317 if(FAILED(hres))
1318 return hres;
1320 hres = stack_pop_val(ctx, &l);
1321 if(SUCCEEDED(hres)) {
1322 hres = VarCat(l.v, r.v, &v);
1323 release_val(&l);
1325 release_val(&r);
1326 if(FAILED(hres))
1327 return hres;
1329 return stack_push(ctx, &v);
1332 static HRESULT interp_add(exec_ctx_t *ctx)
1334 variant_val_t r, l;
1335 VARIANT v;
1336 HRESULT hres;
1338 TRACE("\n");
1340 hres = stack_pop_val(ctx, &r);
1341 if(FAILED(hres))
1342 return hres;
1344 hres = stack_pop_val(ctx, &l);
1345 if(SUCCEEDED(hres)) {
1346 hres = VarAdd(l.v, r.v, &v);
1347 release_val(&l);
1349 release_val(&r);
1350 if(FAILED(hres))
1351 return hres;
1353 return stack_push(ctx, &v);
1356 static HRESULT interp_sub(exec_ctx_t *ctx)
1358 variant_val_t r, l;
1359 VARIANT v;
1360 HRESULT hres;
1362 TRACE("\n");
1364 hres = stack_pop_val(ctx, &r);
1365 if(FAILED(hres))
1366 return hres;
1368 hres = stack_pop_val(ctx, &l);
1369 if(SUCCEEDED(hres)) {
1370 hres = VarSub(l.v, r.v, &v);
1371 release_val(&l);
1373 release_val(&r);
1374 if(FAILED(hres))
1375 return hres;
1377 return stack_push(ctx, &v);
1380 static HRESULT interp_mod(exec_ctx_t *ctx)
1382 variant_val_t r, l;
1383 VARIANT v;
1384 HRESULT hres;
1386 TRACE("\n");
1388 hres = stack_pop_val(ctx, &r);
1389 if(FAILED(hres))
1390 return hres;
1392 hres = stack_pop_val(ctx, &l);
1393 if(SUCCEEDED(hres)) {
1394 hres = VarMod(l.v, r.v, &v);
1395 release_val(&l);
1397 release_val(&r);
1398 if(FAILED(hres))
1399 return hres;
1401 return stack_push(ctx, &v);
1404 static HRESULT interp_idiv(exec_ctx_t *ctx)
1406 variant_val_t r, l;
1407 VARIANT v;
1408 HRESULT hres;
1410 TRACE("\n");
1412 hres = stack_pop_val(ctx, &r);
1413 if(FAILED(hres))
1414 return hres;
1416 hres = stack_pop_val(ctx, &l);
1417 if(SUCCEEDED(hres)) {
1418 hres = VarIdiv(l.v, r.v, &v);
1419 release_val(&l);
1421 release_val(&r);
1422 if(FAILED(hres))
1423 return hres;
1425 return stack_push(ctx, &v);
1428 static HRESULT interp_div(exec_ctx_t *ctx)
1430 variant_val_t r, l;
1431 VARIANT v;
1432 HRESULT hres;
1434 TRACE("\n");
1436 hres = stack_pop_val(ctx, &r);
1437 if(FAILED(hres))
1438 return hres;
1440 hres = stack_pop_val(ctx, &l);
1441 if(SUCCEEDED(hres)) {
1442 hres = VarDiv(l.v, r.v, &v);
1443 release_val(&l);
1445 release_val(&r);
1446 if(FAILED(hres))
1447 return hres;
1449 return stack_push(ctx, &v);
1452 static HRESULT interp_mul(exec_ctx_t *ctx)
1454 variant_val_t r, l;
1455 VARIANT v;
1456 HRESULT hres;
1458 TRACE("\n");
1460 hres = stack_pop_val(ctx, &r);
1461 if(FAILED(hres))
1462 return hres;
1464 hres = stack_pop_val(ctx, &l);
1465 if(SUCCEEDED(hres)) {
1466 hres = VarMul(l.v, r.v, &v);
1467 release_val(&l);
1469 release_val(&r);
1470 if(FAILED(hres))
1471 return hres;
1473 return stack_push(ctx, &v);
1476 static HRESULT interp_exp(exec_ctx_t *ctx)
1478 variant_val_t r, l;
1479 VARIANT v;
1480 HRESULT hres;
1482 TRACE("\n");
1484 hres = stack_pop_val(ctx, &r);
1485 if(FAILED(hres))
1486 return hres;
1488 hres = stack_pop_val(ctx, &l);
1489 if(SUCCEEDED(hres)) {
1490 hres = VarPow(l.v, r.v, &v);
1491 release_val(&l);
1493 release_val(&r);
1494 if(FAILED(hres))
1495 return hres;
1497 return stack_push(ctx, &v);
1500 static HRESULT interp_neg(exec_ctx_t *ctx)
1502 variant_val_t val;
1503 VARIANT v;
1504 HRESULT hres;
1506 hres = stack_pop_val(ctx, &val);
1507 if(FAILED(hres))
1508 return hres;
1510 hres = VarNeg(val.v, &v);
1511 release_val(&val);
1512 if(FAILED(hres))
1513 return hres;
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));
1522 return E_NOTIMPL;
1525 static const instr_func_t op_funcs[] = {
1526 #define X(x,n,a,b) interp_ ## x,
1527 OP_LIST
1528 #undef X
1531 static const unsigned op_move[] = {
1532 #define X(x,n,a,b) n,
1533 OP_LIST
1534 #undef X
1537 static void release_exec(exec_ctx_t *ctx)
1539 unsigned i;
1541 VariantClear(&ctx->ret_val);
1543 if(ctx->this_obj)
1544 IDispatch_Release(ctx->this_obj);
1546 if(ctx->args) {
1547 for(i=0; i < ctx->func->arg_cnt; i++)
1548 VariantClear(ctx->args+i);
1551 if(ctx->vars) {
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};
1565 vbsop_t op;
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);
1572 return E_FAIL;
1575 vbsheap_init(&exec.heap);
1577 if(func->arg_cnt) {
1578 VARIANT *v;
1579 unsigned i;
1581 exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
1582 if(!exec.args) {
1583 release_exec(&exec);
1584 return E_OUTOFMEMORY;
1587 for(i=0; i < func->arg_cnt; i++) {
1588 v = get_arg(dp, i);
1589 if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
1590 if(func->args[i].by_ref)
1591 exec.args[i] = *v;
1592 else
1593 hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
1594 }else {
1595 hres = VariantCopy(exec.args+i, v);
1597 if(FAILED(hres)) {
1598 release_exec(&exec);
1599 return hres;
1602 }else {
1603 exec.args = NULL;
1606 if(func->var_cnt) {
1607 exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
1608 if(!exec.vars) {
1609 release_exec(&exec);
1610 return E_OUTOFMEMORY;
1612 }else {
1613 exec.vars = NULL;
1616 exec.stack_size = 16;
1617 exec.top = 0;
1618 exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
1619 if(!exec.stack) {
1620 release_exec(&exec);
1621 return E_OUTOFMEMORY;
1624 if(this_obj)
1625 exec.this_obj = this_obj;
1626 else if (ctx->host_global)
1627 exec.this_obj = ctx->host_global;
1628 else
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;
1633 exec.script = ctx;
1634 exec.func = func;
1636 while(exec.instr) {
1637 op = exec.instr->op;
1638 hres = op_funcs[op](&exec);
1639 if(FAILED(hres)) {
1640 FIXME("Failed %08x\n", hres);
1641 stack_popn(&exec, exec.top);
1642 break;
1645 exec.instr += op_move[op];
1648 assert(!exec.top);
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);
1658 return hres;