vbscript: Added support for undeclared variables in non-explicit mode.
[wine] / dlls / vbscript / interp.c
1 /*
2  * Copyright 2011 Jacek Caban for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include <assert.h>
20
21 #include "vbscript.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
26
27
28 typedef struct {
29     vbscode_t *code;
30     instr_t *instr;
31     script_ctx_t *script;
32     function_t *func;
33     IDispatch *this_obj;
34
35     VARIANT *args;
36     VARIANT *vars;
37
38     dynamic_var_t *dynamic_vars;
39     vbsheap_t heap;
40
41     unsigned stack_size;
42     unsigned top;
43     VARIANT *stack;
44
45     VARIANT ret_val;
46 } exec_ctx_t;
47
48 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
49
50 typedef enum {
51     REF_NONE,
52     REF_DISP,
53     REF_VAR,
54     REF_OBJ,
55     REF_FUNC
56 } ref_type_t;
57
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;
70
71 typedef struct {
72     VARIANT *v;
73     VARIANT store;
74     BOOL owned;
75 } variant_val_t;
76
77 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
78 {
79     while(var) {
80         if(!strcmpiW(var->name, name)) {
81             ref->type = REF_VAR;
82             ref->u.v = &var->v;
83             return TRUE;
84         }
85
86         var = var->next;
87     }
88
89     return FALSE;
90 }
91
92 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref)
93 {
94     named_item_t *item;
95     function_t *func;
96     unsigned i;
97     DISPID id;
98     HRESULT hres;
99
100     static const WCHAR errW[] = {'e','r','r',0};
101
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;
108     }
109
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;
115         }
116     }
117
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;
123         }
124     }
125
126     if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? ctx->script->global_vars : ctx->dynamic_vars, name, ref))
127         return S_OK;
128
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;
135     }
136
137     if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(ctx->script->global_vars, name, ref))
138         return S_OK;
139
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;
145         }
146     }
147
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;
156             }
157         }
158
159         if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpiW(item->name, name)) {
160             if(!item->disp) {
161                 IUnknown *unk;
162
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;
167                 }
168
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;
174                 }
175             }
176
177             ref->type = REF_OBJ;
178             ref->u.obj = item->disp;
179             return S_OK;
180         }
181     }
182
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;
187     }
188
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;
195     }
196
197     ref->type = REF_NONE;
198     return S_OK;
199 }
200
201 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
202 {
203     assert(ctx->top);
204     return ctx->stack + --ctx->top;
205 }
206
207 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
208 {
209     if(ctx->stack_size == ctx->top) {
210         VARIANT *new_stack;
211
212         new_stack = heap_realloc(ctx->stack, ctx->stack_size*2);
213         if(!new_stack) {
214             VariantClear(v);
215             return E_OUTOFMEMORY;
216         }
217
218         ctx->stack = new_stack;
219         ctx->stack_size *= 2;
220     }
221
222     ctx->stack[ctx->top++] = *v;
223     return S_OK;
224 }
225
226 static void stack_popn(exec_ctx_t *ctx, unsigned n)
227 {
228     while(n--)
229         VariantClear(stack_pop(ctx));
230 }
231
232 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *v)
233 {
234     VARIANT *var;
235
236     var = stack_pop(ctx);
237
238     if(V_VT(var) == (VT_BYREF|VT_VARIANT)) {
239         v->owned = FALSE;
240         var = V_VARIANTREF(var);
241     }else {
242         v->owned = TRUE;
243     }
244
245     if(V_VT(var) == VT_DISPATCH) {
246         DISPPARAMS dp = {0};
247         HRESULT hres;
248
249         hres = disp_call(ctx->script, V_DISPATCH(var), DISPID_VALUE, &dp, &v->store);
250         if(v->owned)
251             IDispatch_Release(V_DISPATCH(var));
252         if(FAILED(hres))
253             return hres;
254
255         v->owned = TRUE;
256         v->v = &v->store;
257     }else {
258         v->v = var;
259     }
260
261     return S_OK;
262 }
263
264 static inline void release_val(variant_val_t *v)
265 {
266     if(v->owned)
267         VariantClear(v->v);
268 }
269
270 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
271 {
272     VARIANT *v = stack_pop(ctx);
273
274     if(V_VT(v) == VT_DISPATCH) {
275         *ret = V_DISPATCH(v);
276         return S_OK;
277     }
278
279     if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
280         FIXME("not supported type: %s\n", debugstr_variant(v));
281         VariantClear(v);
282         return E_FAIL;
283     }
284
285     v = V_BYREF(v);
286     if(V_VT(v) != VT_DISPATCH) {
287         FIXME("not disp %s\n", debugstr_variant(v));
288         return E_FAIL;
289     }
290
291     if(V_DISPATCH(v))
292         IDispatch_AddRef(V_DISPATCH(v));
293     *ret = V_DISPATCH(v);
294     return S_OK;
295 }
296
297 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
298 {
299     ctx->instr = ctx->code->instrs + addr;
300 }
301
302 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, DISPPARAMS *dp)
303 {
304     dp->cArgs = arg_cnt;
305     dp->rgdispidNamedArgs = NULL;
306     dp->cNamedArgs = 0;
307
308     if(arg_cnt) {
309         VARIANT tmp;
310         unsigned i;
311
312         assert(ctx->top >= arg_cnt);
313
314         for(i=1; i*2 <= arg_cnt; i++) {
315             tmp = ctx->stack[ctx->top-i];
316             ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
317             ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
318         }
319
320         dp->rgvarg = ctx->stack + ctx->top-arg_cnt;
321     }else {
322         dp->rgvarg = NULL;
323     }
324 }
325
326 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
327 {
328     BSTR identifier = ctx->instr->arg1.bstr;
329     const unsigned arg_cnt = ctx->instr->arg2.uint;
330     DISPPARAMS dp;
331     ref_t ref;
332     HRESULT hres;
333
334     hres = lookup_identifier(ctx, identifier, VBDISP_CALLGET, &ref);
335     if(FAILED(hres))
336         return hres;
337
338     vbstack_to_dp(ctx, arg_cnt, &dp);
339
340     switch(ref.type) {
341     case REF_VAR:
342         if(!res) {
343             FIXME("REF_VAR no res\n");
344             return E_NOTIMPL;
345         }
346
347         if(arg_cnt) {
348             FIXME("arguments not implemented\n");
349             return E_NOTIMPL;
350         }
351
352         V_VT(res) = VT_BYREF|VT_VARIANT;
353         V_BYREF(res) = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
354         break;
355     case REF_DISP:
356         hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
357         if(FAILED(hres))
358             return hres;
359         break;
360     case REF_FUNC:
361         hres = exec_script(ctx->script, ref.u.f, NULL, &dp, res);
362         if(FAILED(hres))
363             return hres;
364         break;
365     case REF_OBJ:
366         if(arg_cnt) {
367             FIXME("arguments on object\n");
368             return E_NOTIMPL;
369         }
370
371         if(res) {
372             IDispatch_AddRef(ref.u.obj);
373             V_VT(res) = VT_DISPATCH;
374             V_DISPATCH(res) = ref.u.obj;
375         }
376         break;
377     case REF_NONE:
378         FIXME("%s not found\n", debugstr_w(identifier));
379         return DISP_E_UNKNOWNNAME;
380     }
381
382     stack_popn(ctx, arg_cnt);
383     return S_OK;
384 }
385
386 static HRESULT interp_icall(exec_ctx_t *ctx)
387 {
388     VARIANT v;
389     HRESULT hres;
390
391     TRACE("\n");
392
393     hres = do_icall(ctx, &v);
394     if(FAILED(hres))
395         return hres;
396
397     return stack_push(ctx, &v);
398 }
399
400 static HRESULT interp_icallv(exec_ctx_t *ctx)
401 {
402     TRACE("\n");
403     return do_icall(ctx, NULL);
404 }
405
406 static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res)
407 {
408     const BSTR identifier = ctx->instr->arg1.bstr;
409     const unsigned arg_cnt = ctx->instr->arg2.uint;
410     IDispatch *obj;
411     DISPPARAMS dp;
412     DISPID id;
413     HRESULT hres;
414
415     hres = stack_pop_disp(ctx, &obj);
416     if(FAILED(hres))
417         return hres;
418
419     if(!obj) {
420         FIXME("NULL obj\n");
421         return E_FAIL;
422     }
423
424     vbstack_to_dp(ctx, arg_cnt, &dp);
425
426     hres = disp_get_id(obj, identifier, VBDISP_CALLGET, FALSE, &id);
427     if(SUCCEEDED(hres))
428         hres = disp_call(ctx->script, obj, id, &dp, res);
429     IDispatch_Release(obj);
430     if(FAILED(hres))
431         return hres;
432
433     stack_popn(ctx, arg_cnt);
434     return S_OK;
435 }
436
437 static HRESULT interp_mcall(exec_ctx_t *ctx)
438 {
439     VARIANT res;
440     HRESULT hres;
441
442     TRACE("\n");
443
444     hres = do_mcall(ctx, &res);
445     if(FAILED(hres))
446         return hres;
447
448     return stack_push(ctx, &res);
449 }
450
451 static HRESULT interp_mcallv(exec_ctx_t *ctx)
452 {
453     TRACE("\n");
454
455     return do_mcall(ctx, NULL);
456 }
457
458 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
459 {
460     ref_t ref;
461     HRESULT hres;
462
463     hres = lookup_identifier(ctx, name, VBDISP_LET, &ref);
464     if(FAILED(hres))
465         return hres;
466
467     switch(ref.type) {
468     case REF_VAR: {
469         VARIANT *v = ref.u.v;
470
471         if(V_VT(v) == (VT_VARIANT|VT_BYREF))
472             v = V_VARIANTREF(v);
473
474         if(own_val) {
475             VariantClear(v);
476             *v = *val;
477             hres = S_OK;
478         }else {
479             hres = VariantCopy(v, val);
480         }
481         break;
482     }
483     case REF_DISP:
484         hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, val);
485         if(own_val)
486             VariantClear(val);
487         break;
488     case REF_FUNC:
489         FIXME("functions not implemented\n");
490         return E_NOTIMPL;
491     case REF_OBJ:
492         FIXME("REF_OBJ\n");
493         return E_NOTIMPL;
494     case REF_NONE: {
495         dynamic_var_t *new_var;
496         vbsheap_t *heap;
497         WCHAR *str;
498         unsigned size;
499
500         if(ctx->func->code_ctx->option_explicit) {
501             FIXME("throw exception\n");
502             return E_FAIL;
503         }
504
505         TRACE("creating variable %s\n", debugstr_w(name));
506
507         heap = ctx->func->type == FUNC_GLOBAL ? &ctx->script->heap : &ctx->heap;
508
509         new_var = vbsheap_alloc(heap, sizeof(*new_var));
510         if(!new_var)
511             return E_OUTOFMEMORY;
512
513         size = (strlenW(name)+1)*sizeof(WCHAR);
514         str = vbsheap_alloc(heap, size);
515         if(!str)
516             return E_OUTOFMEMORY;
517         memcpy(str, name, size);
518         new_var->name = str;
519
520         if(own_val) {
521             new_var->v = *val;
522         }else {
523             hres = VariantCopy(&new_var->v, val);
524             if(FAILED(hres))
525                 return hres;
526         }
527
528         if(ctx->func->type == FUNC_GLOBAL) {
529             new_var->next = ctx->script->global_vars;
530             ctx->script->global_vars = new_var;
531         }else {
532             new_var->next = ctx->dynamic_vars;
533             ctx->dynamic_vars = new_var;
534         }
535     }
536     }
537
538     return hres;
539 }
540
541 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
542 {
543     const BSTR arg = ctx->instr->arg1.bstr;
544     variant_val_t v;
545     HRESULT hres;
546
547     TRACE("%s\n", debugstr_w(arg));
548
549     hres = stack_pop_val(ctx, &v);
550     if(FAILED(hres))
551         return hres;
552
553     return assign_ident(ctx, arg, v.v, v.owned);
554 }
555
556 static HRESULT interp_set_ident(exec_ctx_t *ctx)
557 {
558     const BSTR arg = ctx->instr->arg1.bstr;
559     IDispatch *disp;
560     VARIANT v;
561     HRESULT hres;
562
563     TRACE("%s\n", debugstr_w(arg));
564
565     hres = stack_pop_disp(ctx, &disp);
566     if(FAILED(hres))
567         return hres;
568
569     V_VT(&v) = VT_DISPATCH;
570     V_DISPATCH(&v) = disp;
571     return assign_ident(ctx, ctx->instr->arg1.bstr, &v, TRUE);
572 }
573
574 static HRESULT interp_assign_member(exec_ctx_t *ctx)
575 {
576     BSTR identifier = ctx->instr->arg1.bstr;
577     variant_val_t val;
578     IDispatch *obj;
579     DISPID id;
580     HRESULT hres;
581
582     TRACE("%s\n", debugstr_w(identifier));
583
584     hres = stack_pop_disp(ctx, &obj);
585     if(FAILED(hres))
586         return hres;
587
588     if(!obj) {
589         FIXME("NULL obj\n");
590         return E_FAIL;
591     }
592
593     hres = stack_pop_val(ctx, &val);
594     if(FAILED(hres)) {
595         IDispatch_Release(obj);
596         return hres;
597     }
598
599     hres = disp_get_id(obj, identifier, VBDISP_LET, FALSE, &id);
600     if(SUCCEEDED(hres))
601         hres = disp_propput(ctx->script, obj, id, val.v);
602
603     release_val(&val);
604     IDispatch_Release(obj);
605     return hres;
606 }
607
608 static HRESULT interp_set_member(exec_ctx_t *ctx)
609 {
610     BSTR identifier = ctx->instr->arg1.bstr;
611     IDispatch *obj, *val;
612     DISPID id;
613     HRESULT hres;
614
615     TRACE("%s\n", debugstr_w(identifier));
616
617     hres = stack_pop_disp(ctx, &obj);
618     if(FAILED(hres))
619         return hres;
620
621     if(!obj) {
622         FIXME("NULL obj\n");
623         return E_FAIL;
624     }
625
626     hres = stack_pop_disp(ctx, &val);
627     if(FAILED(hres)) {
628         IDispatch_Release(obj);
629         return hres;
630     }
631
632     hres = disp_get_id(obj, identifier, VBDISP_SET, FALSE, &id);
633     if(SUCCEEDED(hres)) {
634         VARIANT v;
635
636         V_VT(&v) = VT_DISPATCH;
637         V_DISPATCH(&v) = val;
638         hres = disp_propput(ctx->script, obj, id, &v);
639     }
640
641     if(val)
642         IDispatch_Release(val);
643     IDispatch_Release(obj);
644     return hres;
645 }
646
647 static HRESULT interp_new(exec_ctx_t *ctx)
648 {
649     const WCHAR *arg = ctx->instr->arg1.bstr;
650     class_desc_t *class_desc;
651     vbdisp_t *obj;
652     VARIANT v;
653     HRESULT hres;
654
655     TRACE("%s\n", debugstr_w(arg));
656
657     for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
658         if(!strcmpiW(class_desc->name, arg))
659             break;
660     }
661     if(!class_desc) {
662         FIXME("Class %s not found\n", debugstr_w(arg));
663         return E_FAIL;
664     }
665
666     hres = create_vbdisp(class_desc, &obj);
667     if(FAILED(hres))
668         return hres;
669
670     V_VT(&v) = VT_DISPATCH;
671     V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
672     return stack_push(ctx, &v);
673 }
674
675 static HRESULT interp_jmp(exec_ctx_t *ctx)
676 {
677     const unsigned arg = ctx->instr->arg1.uint;
678
679     TRACE("%u\n", arg);
680
681     instr_jmp(ctx, arg);
682     return S_OK;
683 }
684
685 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
686 {
687     const unsigned arg = ctx->instr->arg1.uint;
688     variant_val_t val;
689     HRESULT hres;
690
691     TRACE("%u\n", arg);
692
693     hres = stack_pop_val(ctx, &val);
694     if(FAILED(hres))
695         return hres;
696
697     if(V_VT(val.v) != VT_BOOL) {
698         FIXME("unsupported for %s\n", debugstr_variant(val.v));
699         release_val(&val);
700         return E_NOTIMPL;
701     }
702
703     if(V_BOOL(val.v))
704         ctx->instr++;
705     else
706         instr_jmp(ctx, ctx->instr->arg1.uint);
707     return S_OK;
708 }
709
710 static HRESULT interp_jmp_true(exec_ctx_t *ctx)
711 {
712     const unsigned arg = ctx->instr->arg1.uint;
713     variant_val_t val;
714     HRESULT hres;
715
716     TRACE("%u\n", arg);
717
718     hres = stack_pop_val(ctx, &val);
719     if(FAILED(hres))
720         return hres;
721
722     if(V_VT(val.v) != VT_BOOL) {
723         FIXME("unsupported for %s\n", debugstr_variant(val.v));
724         release_val(&val);
725         return E_NOTIMPL;
726     }
727
728     if(V_BOOL(val.v))
729         instr_jmp(ctx, ctx->instr->arg1.uint);
730     else
731         ctx->instr++;
732     return S_OK;
733 }
734
735 static HRESULT interp_ret(exec_ctx_t *ctx)
736 {
737     TRACE("\n");
738
739     ctx->instr = NULL;
740     return S_OK;
741 }
742
743 static HRESULT interp_stop(exec_ctx_t *ctx)
744 {
745     WARN("\n");
746
747     /* NOTE: this should have effect in debugging mode (that we don't support yet) */
748     return S_OK;
749 }
750
751 static HRESULT interp_me(exec_ctx_t *ctx)
752 {
753     VARIANT v;
754
755     TRACE("\n");
756
757     IDispatch_AddRef(ctx->this_obj);
758     V_VT(&v) = VT_DISPATCH;
759     V_DISPATCH(&v) = ctx->this_obj;
760     return stack_push(ctx, &v);
761 }
762
763 static HRESULT interp_bool(exec_ctx_t *ctx)
764 {
765     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
766     VARIANT v;
767
768     TRACE("%s\n", arg ? "true" : "false");
769
770     V_VT(&v) = VT_BOOL;
771     V_BOOL(&v) = arg;
772     return stack_push(ctx, &v);
773 }
774
775 static HRESULT interp_errmode(exec_ctx_t *ctx)
776 {
777     const int err_mode = ctx->instr->arg1.uint;
778     FIXME("%d\n", err_mode);
779     return E_NOTIMPL;
780 }
781
782 static HRESULT interp_string(exec_ctx_t *ctx)
783 {
784     VARIANT v;
785
786     TRACE("\n");
787
788     V_VT(&v) = VT_BSTR;
789     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
790     if(!V_BSTR(&v))
791         return E_OUTOFMEMORY;
792
793     return stack_push(ctx, &v);
794 }
795
796 static HRESULT interp_long(exec_ctx_t *ctx)
797 {
798     const LONG arg = ctx->instr->arg1.lng;
799     VARIANT v;
800
801     TRACE("%d\n", arg);
802
803     V_VT(&v) = VT_I4;
804     V_I4(&v) = arg;
805     return stack_push(ctx, &v);
806 }
807
808 static HRESULT interp_short(exec_ctx_t *ctx)
809 {
810     const LONG arg = ctx->instr->arg1.lng;
811     VARIANT v;
812
813     TRACE("%d\n", arg);
814
815     V_VT(&v) = VT_I2;
816     V_I2(&v) = arg;
817     return stack_push(ctx, &v);
818 }
819
820 static HRESULT interp_double(exec_ctx_t *ctx)
821 {
822     const DOUBLE *arg = ctx->instr->arg1.dbl;
823     VARIANT v;
824
825     TRACE("%lf\n", *arg);
826
827     V_VT(&v) = VT_R8;
828     V_R8(&v) = *arg;
829     return stack_push(ctx, &v);
830 }
831
832 static HRESULT interp_empty(exec_ctx_t *ctx)
833 {
834     VARIANT v;
835
836     TRACE("\n");
837
838     V_VT(&v) = VT_EMPTY;
839     return stack_push(ctx, &v);
840 }
841
842 static HRESULT interp_null(exec_ctx_t *ctx)
843 {
844     VARIANT v;
845
846     TRACE("\n");
847
848     V_VT(&v) = VT_NULL;
849     return stack_push(ctx, &v);
850 }
851
852 static HRESULT interp_nothing(exec_ctx_t *ctx)
853 {
854     VARIANT v;
855
856     TRACE("\n");
857
858     V_VT(&v) = VT_DISPATCH;
859     V_DISPATCH(&v) = NULL;
860     return stack_push(ctx, &v);
861 }
862
863 static HRESULT interp_not(exec_ctx_t *ctx)
864 {
865     variant_val_t val;
866     VARIANT v;
867     HRESULT hres;
868
869     TRACE("\n");
870
871     hres = stack_pop_val(ctx, &val);
872     if(FAILED(hres))
873         return hres;
874
875     hres = VarNot(val.v, &v);
876     release_val(&val);
877     if(FAILED(hres))
878         return hres;
879
880     return stack_push(ctx, &v);
881 }
882
883 static HRESULT interp_and(exec_ctx_t *ctx)
884 {
885     variant_val_t r, l;
886     VARIANT v;
887     HRESULT hres;
888
889     TRACE("\n");
890
891     hres = stack_pop_val(ctx, &r);
892     if(FAILED(hres))
893         return hres;
894
895     hres = stack_pop_val(ctx, &l);
896     if(SUCCEEDED(hres)) {
897         hres = VarAnd(l.v, r.v, &v);
898         release_val(&l);
899     }
900     release_val(&r);
901     if(FAILED(hres))
902         return hres;
903
904     return stack_push(ctx, &v);
905 }
906
907 static HRESULT interp_or(exec_ctx_t *ctx)
908 {
909     variant_val_t r, l;
910     VARIANT v;
911     HRESULT hres;
912
913     TRACE("\n");
914
915     hres = stack_pop_val(ctx, &r);
916     if(FAILED(hres))
917         return hres;
918
919     hres = stack_pop_val(ctx, &l);
920     if(SUCCEEDED(hres)) {
921         hres = VarOr(l.v, r.v, &v);
922         release_val(&l);
923     }
924     release_val(&r);
925     if(FAILED(hres))
926         return hres;
927
928     return stack_push(ctx, &v);
929 }
930
931 static HRESULT interp_xor(exec_ctx_t *ctx)
932 {
933     variant_val_t r, l;
934     VARIANT v;
935     HRESULT hres;
936
937     TRACE("\n");
938
939     hres = stack_pop_val(ctx, &r);
940     if(FAILED(hres))
941         return hres;
942
943     hres = stack_pop_val(ctx, &l);
944     if(SUCCEEDED(hres)) {
945         hres = VarXor(l.v, r.v, &v);
946         release_val(&l);
947     }
948     release_val(&r);
949     if(FAILED(hres))
950         return hres;
951
952     return stack_push(ctx, &v);
953 }
954
955 static HRESULT interp_eqv(exec_ctx_t *ctx)
956 {
957     variant_val_t r, l;
958     VARIANT v;
959     HRESULT hres;
960
961     TRACE("\n");
962
963     hres = stack_pop_val(ctx, &r);
964     if(FAILED(hres))
965         return hres;
966
967     hres = stack_pop_val(ctx, &l);
968     if(SUCCEEDED(hres)) {
969         hres = VarEqv(l.v, r.v, &v);
970         release_val(&l);
971     }
972     release_val(&r);
973     if(FAILED(hres))
974         return hres;
975
976     return stack_push(ctx, &v);
977 }
978
979 static HRESULT interp_imp(exec_ctx_t *ctx)
980 {
981     variant_val_t r, l;
982     VARIANT v;
983     HRESULT hres;
984
985     TRACE("\n");
986
987     hres = stack_pop_val(ctx, &r);
988     if(FAILED(hres))
989         return hres;
990
991     hres = stack_pop_val(ctx, &l);
992     if(SUCCEEDED(hres)) {
993         hres = VarImp(l.v, r.v, &v);
994         release_val(&l);
995     }
996     release_val(&r);
997     if(FAILED(hres))
998         return hres;
999
1000     return stack_push(ctx, &v);
1001 }
1002
1003 static HRESULT cmp_oper(exec_ctx_t *ctx)
1004 {
1005     variant_val_t l, r;
1006     HRESULT hres;
1007
1008     hres = stack_pop_val(ctx, &r);
1009     if(FAILED(hres))
1010         return hres;
1011
1012     hres = stack_pop_val(ctx, &l);
1013     if(SUCCEEDED(hres)) {
1014         if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
1015             FIXME("comparing nulls is not implemented\n");
1016             hres = E_NOTIMPL;
1017         }else {
1018             hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
1019         }
1020     }
1021
1022     release_val(&r);
1023     release_val(&l);
1024     return hres;
1025 }
1026
1027 static HRESULT interp_equal(exec_ctx_t *ctx)
1028 {
1029     VARIANT v;
1030     HRESULT hres;
1031
1032     TRACE("\n");
1033
1034     hres = cmp_oper(ctx);
1035     if(FAILED(hres))
1036         return hres;
1037
1038     V_VT(&v) = VT_BOOL;
1039     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1040     return stack_push(ctx, &v);
1041 }
1042
1043 static HRESULT interp_nequal(exec_ctx_t *ctx)
1044 {
1045     VARIANT v;
1046     HRESULT hres;
1047
1048     TRACE("\n");
1049
1050     hres = cmp_oper(ctx);
1051     if(FAILED(hres))
1052         return hres;
1053
1054     V_VT(&v) = VT_BOOL;
1055     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1056     return stack_push(ctx, &v);
1057 }
1058
1059 static HRESULT interp_gt(exec_ctx_t *ctx)
1060 {
1061     VARIANT v;
1062     HRESULT hres;
1063
1064     TRACE("\n");
1065
1066     hres = cmp_oper(ctx);
1067     if(FAILED(hres))
1068         return hres;
1069
1070     V_VT(&v) = VT_BOOL;
1071     V_BOOL(&v) = hres == VARCMP_GT ? VARIANT_TRUE : VARIANT_FALSE;
1072     return stack_push(ctx, &v);
1073 }
1074
1075 static HRESULT interp_gteq(exec_ctx_t *ctx)
1076 {
1077     VARIANT v;
1078     HRESULT hres;
1079
1080     TRACE("\n");
1081
1082     hres = cmp_oper(ctx);
1083     if(FAILED(hres))
1084         return hres;
1085
1086     V_VT(&v) = VT_BOOL;
1087     V_BOOL(&v) = hres == VARCMP_GT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1088     return stack_push(ctx, &v);
1089 }
1090
1091 static HRESULT interp_lt(exec_ctx_t *ctx)
1092 {
1093     VARIANT v;
1094     HRESULT hres;
1095
1096     TRACE("\n");
1097
1098     hres = cmp_oper(ctx);
1099     if(FAILED(hres))
1100         return hres;
1101
1102     V_VT(&v) = VT_BOOL;
1103     V_BOOL(&v) = hres == VARCMP_LT ? VARIANT_TRUE : VARIANT_FALSE;
1104     return stack_push(ctx, &v);
1105 }
1106
1107 static HRESULT interp_lteq(exec_ctx_t *ctx)
1108 {
1109     VARIANT v;
1110     HRESULT hres;
1111
1112     TRACE("\n");
1113
1114     hres = cmp_oper(ctx);
1115     if(FAILED(hres))
1116         return hres;
1117
1118     V_VT(&v) = VT_BOOL;
1119     V_BOOL(&v) = hres == VARCMP_LT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1120     return stack_push(ctx, &v);
1121 }
1122
1123 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, VARIANT_BOOL *ret)
1124 {
1125     IObjectIdentity *identity;
1126     IUnknown *unk1, *unk2;
1127     HRESULT hres;
1128
1129     if(disp1 == disp2) {
1130         *ret = VARIANT_TRUE;
1131         return S_OK;
1132     }
1133
1134     if(!disp1 || !disp2) {
1135         *ret = VARIANT_FALSE;
1136         return S_OK;
1137     }
1138
1139     hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
1140     if(FAILED(hres))
1141         return hres;
1142
1143     hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
1144     if(FAILED(hres)) {
1145         IUnknown_Release(unk1);
1146         return hres;
1147     }
1148
1149     if(unk1 == unk2) {
1150         *ret = VARIANT_TRUE;
1151     }else {
1152         hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
1153         if(SUCCEEDED(hres)) {
1154             hres = IObjectIdentity_IsEqualObject(identity, unk2);
1155             IObjectIdentity_Release(identity);
1156             *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
1157         }else {
1158             *ret = VARIANT_FALSE;
1159         }
1160     }
1161
1162     IUnknown_Release(unk1);
1163     IUnknown_Release(unk2);
1164     return S_OK;
1165 }
1166
1167 static HRESULT interp_is(exec_ctx_t *ctx)
1168 {
1169     IDispatch *l, *r;
1170     VARIANT v;
1171     HRESULT hres;
1172
1173     TRACE("\n");
1174
1175     hres = stack_pop_disp(ctx, &r);
1176     if(FAILED(hres))
1177         return hres;
1178
1179     hres = stack_pop_disp(ctx, &l);
1180     if(SUCCEEDED(hres)) {
1181         V_VT(&v) = VT_BOOL;
1182         hres = disp_cmp(l, r, &V_BOOL(&v));
1183         if(l)
1184             IDispatch_Release(l);
1185     }
1186     if(r)
1187         IDispatch_Release(r);
1188     if(FAILED(hres))
1189         return hres;
1190
1191     return stack_push(ctx, &v);
1192 }
1193
1194 static HRESULT interp_concat(exec_ctx_t *ctx)
1195 {
1196     variant_val_t r, l;
1197     VARIANT v;
1198     HRESULT hres;
1199
1200     TRACE("\n");
1201
1202     hres = stack_pop_val(ctx, &r);
1203     if(FAILED(hres))
1204         return hres;
1205
1206     hres = stack_pop_val(ctx, &l);
1207     if(SUCCEEDED(hres)) {
1208         hres = VarCat(l.v, r.v, &v);
1209         release_val(&l);
1210     }
1211     release_val(&r);
1212     if(FAILED(hres))
1213         return hres;
1214
1215     return stack_push(ctx, &v);
1216 }
1217
1218 static HRESULT interp_add(exec_ctx_t *ctx)
1219 {
1220     variant_val_t r, l;
1221     VARIANT v;
1222     HRESULT hres;
1223
1224     TRACE("\n");
1225
1226     hres = stack_pop_val(ctx, &r);
1227     if(FAILED(hres))
1228         return hres;
1229
1230     hres = stack_pop_val(ctx, &l);
1231     if(SUCCEEDED(hres)) {
1232         hres = VarAdd(l.v, r.v, &v);
1233         release_val(&l);
1234     }
1235     release_val(&r);
1236     if(FAILED(hres))
1237         return hres;
1238
1239     return stack_push(ctx, &v);
1240 }
1241
1242 static HRESULT interp_sub(exec_ctx_t *ctx)
1243 {
1244     variant_val_t r, l;
1245     VARIANT v;
1246     HRESULT hres;
1247
1248     TRACE("\n");
1249
1250     hres = stack_pop_val(ctx, &r);
1251     if(FAILED(hres))
1252         return hres;
1253
1254     hres = stack_pop_val(ctx, &l);
1255     if(SUCCEEDED(hres)) {
1256         hres = VarSub(l.v, r.v, &v);
1257         release_val(&l);
1258     }
1259     release_val(&r);
1260     if(FAILED(hres))
1261         return hres;
1262
1263     return stack_push(ctx, &v);
1264 }
1265
1266 static HRESULT interp_mod(exec_ctx_t *ctx)
1267 {
1268     variant_val_t r, l;
1269     VARIANT v;
1270     HRESULT hres;
1271
1272     TRACE("\n");
1273
1274     hres = stack_pop_val(ctx, &r);
1275     if(FAILED(hres))
1276         return hres;
1277
1278     hres = stack_pop_val(ctx, &l);
1279     if(SUCCEEDED(hres)) {
1280         hres = VarMod(l.v, r.v, &v);
1281         release_val(&l);
1282     }
1283     release_val(&r);
1284     if(FAILED(hres))
1285         return hres;
1286
1287     return stack_push(ctx, &v);
1288 }
1289
1290 static HRESULT interp_idiv(exec_ctx_t *ctx)
1291 {
1292     variant_val_t r, l;
1293     VARIANT v;
1294     HRESULT hres;
1295
1296     TRACE("\n");
1297
1298     hres = stack_pop_val(ctx, &r);
1299     if(FAILED(hres))
1300         return hres;
1301
1302     hres = stack_pop_val(ctx, &l);
1303     if(SUCCEEDED(hres)) {
1304         hres = VarIdiv(l.v, r.v, &v);
1305         release_val(&l);
1306     }
1307     release_val(&r);
1308     if(FAILED(hres))
1309         return hres;
1310
1311     return stack_push(ctx, &v);
1312 }
1313
1314 static HRESULT interp_div(exec_ctx_t *ctx)
1315 {
1316     variant_val_t r, l;
1317     VARIANT v;
1318     HRESULT hres;
1319
1320     TRACE("\n");
1321
1322     hres = stack_pop_val(ctx, &r);
1323     if(FAILED(hres))
1324         return hres;
1325
1326     hres = stack_pop_val(ctx, &l);
1327     if(SUCCEEDED(hres)) {
1328         hres = VarDiv(l.v, r.v, &v);
1329         release_val(&l);
1330     }
1331     release_val(&r);
1332     if(FAILED(hres))
1333         return hres;
1334
1335     return stack_push(ctx, &v);
1336 }
1337
1338 static HRESULT interp_mul(exec_ctx_t *ctx)
1339 {
1340     variant_val_t r, l;
1341     VARIANT v;
1342     HRESULT hres;
1343
1344     TRACE("\n");
1345
1346     hres = stack_pop_val(ctx, &r);
1347     if(FAILED(hres))
1348         return hres;
1349
1350     hres = stack_pop_val(ctx, &l);
1351     if(SUCCEEDED(hres)) {
1352         hres = VarMul(l.v, r.v, &v);
1353         release_val(&l);
1354     }
1355     release_val(&r);
1356     if(FAILED(hres))
1357         return hres;
1358
1359     return stack_push(ctx, &v);
1360 }
1361
1362 static HRESULT interp_exp(exec_ctx_t *ctx)
1363 {
1364     variant_val_t r, l;
1365     VARIANT v;
1366     HRESULT hres;
1367
1368     TRACE("\n");
1369
1370     hres = stack_pop_val(ctx, &r);
1371     if(FAILED(hres))
1372         return hres;
1373
1374     hres = stack_pop_val(ctx, &l);
1375     if(SUCCEEDED(hres)) {
1376         hres = VarPow(l.v, r.v, &v);
1377         release_val(&l);
1378     }
1379     release_val(&r);
1380     if(FAILED(hres))
1381         return hres;
1382
1383     return stack_push(ctx, &v);
1384 }
1385
1386 static HRESULT interp_neg(exec_ctx_t *ctx)
1387 {
1388     variant_val_t val;
1389     VARIANT v;
1390     HRESULT hres;
1391
1392     hres = stack_pop_val(ctx, &val);
1393     if(FAILED(hres))
1394         return hres;
1395
1396     hres = VarNeg(val.v, &v);
1397     release_val(&val);
1398     if(FAILED(hres))
1399         return hres;
1400
1401     return stack_push(ctx, &v);
1402 }
1403
1404 static const instr_func_t op_funcs[] = {
1405 #define X(x,n,a,b) interp_ ## x,
1406 OP_LIST
1407 #undef X
1408 };
1409
1410 static const unsigned op_move[] = {
1411 #define X(x,n,a,b) n,
1412 OP_LIST
1413 #undef X
1414 };
1415
1416 static void release_exec(exec_ctx_t *ctx)
1417 {
1418     unsigned i;
1419
1420     VariantClear(&ctx->ret_val);
1421
1422     if(ctx->this_obj)
1423         IDispatch_Release(ctx->this_obj);
1424
1425     if(ctx->args) {
1426         for(i=0; i < ctx->func->arg_cnt; i++)
1427             VariantClear(ctx->args+i);
1428     }
1429
1430     if(ctx->vars) {
1431         for(i=0; i < ctx->func->var_cnt; i++)
1432             VariantClear(ctx->vars+i);
1433     }
1434
1435     vbsheap_free(&ctx->heap);
1436     heap_free(ctx->args);
1437     heap_free(ctx->vars);
1438     heap_free(ctx->stack);
1439 }
1440
1441 HRESULT exec_script(script_ctx_t *ctx, function_t *func, IDispatch *this_obj, DISPPARAMS *dp, VARIANT *res)
1442 {
1443     exec_ctx_t exec = {func->code_ctx};
1444     vbsop_t op;
1445     HRESULT hres = S_OK;
1446
1447     exec.code = func->code_ctx;
1448
1449     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
1450         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
1451         return E_FAIL;
1452     }
1453
1454     vbsheap_init(&exec.heap);
1455
1456     if(func->arg_cnt) {
1457         VARIANT *v;
1458         unsigned i;
1459
1460         exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
1461         if(!exec.args) {
1462             release_exec(&exec);
1463             return E_OUTOFMEMORY;
1464         }
1465
1466         for(i=0; i < func->arg_cnt; i++) {
1467             v = get_arg(dp, i);
1468             if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
1469                 if(func->args[i].by_ref)
1470                     exec.args[i] = *v;
1471                 else
1472                     hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
1473             }else {
1474                 hres = VariantCopy(exec.args+i, v);
1475             }
1476             if(FAILED(hres)) {
1477                 release_exec(&exec);
1478                 return hres;
1479             }
1480         }
1481     }else {
1482         exec.args = NULL;
1483     }
1484
1485     if(func->var_cnt) {
1486         exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
1487         if(!exec.vars) {
1488             release_exec(&exec);
1489             return E_OUTOFMEMORY;
1490         }
1491     }else {
1492         exec.vars = NULL;
1493     }
1494
1495     exec.stack_size = 16;
1496     exec.top = 0;
1497     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
1498     if(!exec.stack) {
1499         release_exec(&exec);
1500         return E_OUTOFMEMORY;
1501     }
1502
1503     if(this_obj)
1504         exec.this_obj = this_obj;
1505     else if (ctx->host_global)
1506         exec.this_obj = ctx->host_global;
1507     else
1508         exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface;
1509     IDispatch_AddRef(exec.this_obj);
1510
1511     exec.instr = exec.code->instrs + func->code_off;
1512     exec.script = ctx;
1513     exec.func = func;
1514
1515     while(exec.instr) {
1516         op = exec.instr->op;
1517         hres = op_funcs[op](&exec);
1518         if(FAILED(hres)) {
1519             FIXME("Failed %08x\n", hres);
1520             stack_popn(&exec, exec.top);
1521             break;
1522         }
1523
1524         exec.instr += op_move[op];
1525     }
1526
1527     assert(!exec.top);
1528     if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)
1529         assert(V_VT(&exec.ret_val) == VT_EMPTY);
1530
1531     if(SUCCEEDED(hres) && res) {
1532         *res = exec.ret_val;
1533         V_VT(&exec.ret_val) = VT_EMPTY;
1534     }
1535
1536     release_exec(&exec);
1537
1538     return hres;
1539 }