comctl32: XOR'ing with a black pen is not useful.
[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 static DISPID propput_dispid = DISPID_PROPERTYPUT;
28
29 typedef struct {
30     vbscode_t *code;
31     instr_t *instr;
32     script_ctx_t *script;
33     function_t *func;
34     IDispatch *this_obj;
35
36     VARIANT *args;
37     VARIANT *vars;
38
39     dynamic_var_t *dynamic_vars;
40     vbsheap_t heap;
41
42     BOOL resume_next;
43
44     unsigned stack_size;
45     unsigned top;
46     VARIANT *stack;
47
48     VARIANT ret_val;
49 } exec_ctx_t;
50
51 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
52
53 typedef enum {
54     REF_NONE,
55     REF_DISP,
56     REF_VAR,
57     REF_OBJ,
58     REF_CONST,
59     REF_FUNC
60 } ref_type_t;
61
62 typedef struct {
63     ref_type_t type;
64     union {
65         struct {
66             IDispatch *disp;
67             DISPID id;
68         } d;
69         VARIANT *v;
70         function_t *f;
71         IDispatch *obj;
72     } u;
73 } ref_t;
74
75 typedef struct {
76     VARIANT *v;
77     VARIANT store;
78     BOOL owned;
79 } variant_val_t;
80
81 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
82 {
83     while(var) {
84         if(!strcmpiW(var->name, name)) {
85             ref->type = var->is_const ? REF_CONST : REF_VAR;
86             ref->u.v = &var->v;
87             return TRUE;
88         }
89
90         var = var->next;
91     }
92
93     return FALSE;
94 }
95
96 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref)
97 {
98     named_item_t *item;
99     function_t *func;
100     unsigned i;
101     DISPID id;
102     HRESULT hres;
103
104     static const WCHAR errW[] = {'e','r','r',0};
105
106     if(invoke_type == VBDISP_LET
107             && (ctx->func->type == FUNC_FUNCTION || ctx->func->type == FUNC_PROPGET || ctx->func->type == FUNC_DEFGET)
108             && !strcmpiW(name, ctx->func->name)) {
109         ref->type = REF_VAR;
110         ref->u.v = &ctx->ret_val;
111         return S_OK;
112     }
113
114     for(i=0; i < ctx->func->var_cnt; i++) {
115         if(!strcmpiW(ctx->func->vars[i].name, name)) {
116             ref->type = REF_VAR;
117             ref->u.v = ctx->vars+i;
118             return TRUE;
119         }
120     }
121
122     for(i=0; i < ctx->func->arg_cnt; i++) {
123         if(!strcmpiW(ctx->func->args[i].name, name)) {
124             ref->type = REF_VAR;
125             ref->u.v = ctx->args+i;
126             return S_OK;
127         }
128     }
129
130     if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? ctx->script->global_vars : ctx->dynamic_vars, name, ref))
131         return S_OK;
132
133     if(ctx->func->type != FUNC_GLOBAL) {
134         hres = disp_get_id(ctx->this_obj, name, invoke_type, TRUE, &id);
135         if(SUCCEEDED(hres)) {
136             ref->type = REF_DISP;
137             ref->u.d.disp = ctx->this_obj;
138             ref->u.d.id = id;
139             return S_OK;
140         }
141     }
142
143     if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(ctx->script->global_vars, name, ref))
144         return S_OK;
145
146     for(func = ctx->script->global_funcs; func; func = func->next) {
147         if(!strcmpiW(func->name, name)) {
148             ref->type = REF_FUNC;
149             ref->u.f = func;
150             return S_OK;
151         }
152     }
153
154     if(!strcmpiW(name, errW)) {
155         ref->type = REF_OBJ;
156         ref->u.obj = (IDispatch*)&ctx->script->err_obj->IDispatchEx_iface;
157         return S_OK;
158     }
159
160     hres = vbdisp_get_id(ctx->script->global_obj, name, invoke_type, TRUE, &id);
161     if(SUCCEEDED(hres)) {
162         ref->type = REF_DISP;
163         ref->u.d.disp = (IDispatch*)&ctx->script->global_obj->IDispatchEx_iface;
164         ref->u.d.id = id;
165         return S_OK;
166     }
167
168     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
169         if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpiW(item->name, name)) {
170             if(!item->disp) {
171                 IUnknown *unk;
172
173                 hres = IActiveScriptSite_GetItemInfo(ctx->script->site, name, SCRIPTINFO_IUNKNOWN, &unk, NULL);
174                 if(FAILED(hres)) {
175                     WARN("GetItemInfo failed: %08x\n", hres);
176                     continue;
177                 }
178
179                 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp);
180                 IUnknown_Release(unk);
181                 if(FAILED(hres)) {
182                     WARN("object does not implement IDispatch\n");
183                     continue;
184                 }
185             }
186
187             ref->type = REF_OBJ;
188             ref->u.obj = item->disp;
189             return S_OK;
190         }
191     }
192
193     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
194         if((item->flags & SCRIPTITEM_GLOBALMEMBERS)) {
195             hres = disp_get_id(item->disp, name, invoke_type, FALSE, &id);
196             if(SUCCEEDED(hres)) {
197                 ref->type = REF_DISP;
198                 ref->u.d.disp = item->disp;
199                 ref->u.d.id = id;
200                 return S_OK;
201             }
202         }
203     }
204
205     ref->type = REF_NONE;
206     return S_OK;
207 }
208
209 static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name, BOOL is_const, VARIANT *val, BOOL own_val)
210 {
211     dynamic_var_t *new_var;
212     vbsheap_t *heap;
213     WCHAR *str;
214     unsigned size;
215     HRESULT hres;
216
217     heap = ctx->func->type == FUNC_GLOBAL ? &ctx->script->heap : &ctx->heap;
218
219     new_var = vbsheap_alloc(heap, sizeof(*new_var));
220     if(!new_var)
221         return E_OUTOFMEMORY;
222
223     size = (strlenW(name)+1)*sizeof(WCHAR);
224     str = vbsheap_alloc(heap, size);
225     if(!str)
226         return E_OUTOFMEMORY;
227     memcpy(str, name, size);
228     new_var->name = str;
229     new_var->is_const = is_const;
230
231     if(own_val) {
232         new_var->v = *val;
233     }else {
234         V_VT(&new_var->v) = VT_EMPTY;
235         hres = VariantCopy(&new_var->v, val);
236         if(FAILED(hres))
237             return hres;
238     }
239
240     if(ctx->func->type == FUNC_GLOBAL) {
241         new_var->next = ctx->script->global_vars;
242         ctx->script->global_vars = new_var;
243     }else {
244         new_var->next = ctx->dynamic_vars;
245         ctx->dynamic_vars = new_var;
246     }
247
248     return S_OK;
249 }
250
251 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
252 {
253     assert(ctx->top);
254     return ctx->stack + --ctx->top;
255 }
256
257 static inline VARIANT *stack_top(exec_ctx_t *ctx, unsigned n)
258 {
259     assert(ctx->top >= n);
260     return ctx->stack + (ctx->top-n-1);
261 }
262
263 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
264 {
265     if(ctx->stack_size == ctx->top) {
266         VARIANT *new_stack;
267
268         new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(*ctx->stack));
269         if(!new_stack) {
270             VariantClear(v);
271             return E_OUTOFMEMORY;
272         }
273
274         ctx->stack = new_stack;
275         ctx->stack_size *= 2;
276     }
277
278     ctx->stack[ctx->top++] = *v;
279     return S_OK;
280 }
281
282 static void stack_popn(exec_ctx_t *ctx, unsigned n)
283 {
284     while(n--)
285         VariantClear(stack_pop(ctx));
286 }
287
288 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *v)
289 {
290     VARIANT *var;
291
292     var = stack_pop(ctx);
293
294     if(V_VT(var) == (VT_BYREF|VT_VARIANT)) {
295         v->owned = FALSE;
296         var = V_VARIANTREF(var);
297     }else {
298         v->owned = TRUE;
299     }
300
301     if(V_VT(var) == VT_DISPATCH) {
302         DISPPARAMS dp = {0};
303         HRESULT hres;
304
305         hres = disp_call(ctx->script, V_DISPATCH(var), DISPID_VALUE, &dp, &v->store);
306         if(v->owned)
307             IDispatch_Release(V_DISPATCH(var));
308         if(FAILED(hres))
309             return hres;
310
311         v->owned = TRUE;
312         v->v = &v->store;
313     }else {
314         v->v = var;
315     }
316
317     return S_OK;
318 }
319
320 static HRESULT stack_assume_val(exec_ctx_t *ctx, unsigned n)
321 {
322     VARIANT *v = stack_top(ctx, n);
323     HRESULT hres;
324
325     if(V_VT(v) == (VT_BYREF|VT_VARIANT)) {
326         VARIANT *ref = V_VARIANTREF(v);
327
328         V_VT(v) = VT_EMPTY;
329         hres = VariantCopy(v, ref);
330         if(FAILED(hres))
331             return hres;
332     }
333
334     if(V_VT(v) == VT_DISPATCH) {
335         DISPPARAMS dp = {0};
336         IDispatch *disp;
337
338         disp = V_DISPATCH(v);
339         V_VT(v) = VT_EMPTY;
340         hres = disp_call(ctx->script, disp, DISPID_VALUE, &dp, v);
341         IDispatch_Release(disp);
342         if(FAILED(hres))
343             return hres;
344     }
345
346     return S_OK;
347 }
348
349 static inline void release_val(variant_val_t *v)
350 {
351     if(v->owned)
352         VariantClear(v->v);
353 }
354
355 static int stack_pop_bool(exec_ctx_t *ctx, BOOL *b)
356 {
357     variant_val_t val;
358     HRESULT hres;
359
360     hres = stack_pop_val(ctx, &val);
361     if(FAILED(hres))
362         return hres;
363
364     switch (V_VT(val.v))
365     {
366     case VT_BOOL:
367         *b = V_BOOL(val.v);
368         break;
369     case VT_I2:
370         *b = V_I2(val.v);
371         break;
372     case VT_I4:
373         *b = V_I4(val.v);
374         break;
375     default:
376         FIXME("unsupported for %s\n", debugstr_variant(val.v));
377         release_val(&val);
378         return E_NOTIMPL;
379     }
380     return S_OK;
381 }
382
383 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
384 {
385     VARIANT *v = stack_pop(ctx);
386
387     if(V_VT(v) == VT_DISPATCH) {
388         *ret = V_DISPATCH(v);
389         return S_OK;
390     }
391
392     if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
393         FIXME("not supported type: %s\n", debugstr_variant(v));
394         VariantClear(v);
395         return E_FAIL;
396     }
397
398     v = V_BYREF(v);
399     if(V_VT(v) != VT_DISPATCH) {
400         FIXME("not disp %s\n", debugstr_variant(v));
401         return E_FAIL;
402     }
403
404     if(V_DISPATCH(v))
405         IDispatch_AddRef(V_DISPATCH(v));
406     *ret = V_DISPATCH(v);
407     return S_OK;
408 }
409
410 static HRESULT stack_assume_disp(exec_ctx_t *ctx, unsigned n, IDispatch **disp)
411 {
412     VARIANT *v = stack_top(ctx, n), *ref;
413
414     if(V_VT(v) != VT_DISPATCH) {
415         if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
416             FIXME("not supported type: %s\n", debugstr_variant(v));
417             return E_FAIL;
418         }
419
420         ref = V_VARIANTREF(v);
421         if(V_VT(ref) != VT_DISPATCH) {
422             FIXME("not disp %s\n", debugstr_variant(ref));
423             return E_FAIL;
424         }
425
426         V_VT(v) = VT_DISPATCH;
427         V_DISPATCH(v) = V_DISPATCH(ref);
428         if(V_DISPATCH(v))
429             IDispatch_AddRef(V_DISPATCH(v));
430     }
431
432     if(disp)
433         *disp = V_DISPATCH(v);
434     return S_OK;
435 }
436
437 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
438 {
439     ctx->instr = ctx->code->instrs + addr;
440 }
441
442 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, BOOL is_propput, DISPPARAMS *dp)
443 {
444     dp->cNamedArgs = is_propput ? 1 : 0;
445     dp->cArgs = arg_cnt + dp->cNamedArgs;
446     dp->rgdispidNamedArgs = is_propput ? &propput_dispid : NULL;
447
448     if(arg_cnt) {
449         VARIANT tmp;
450         unsigned i;
451
452         assert(ctx->top >= arg_cnt);
453
454         for(i=1; i*2 <= arg_cnt; i++) {
455             tmp = ctx->stack[ctx->top-i];
456             ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
457             ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
458         }
459
460         dp->rgvarg = ctx->stack + ctx->top-dp->cArgs;
461     }else {
462         dp->rgvarg = is_propput ? ctx->stack+ctx->top-1 : NULL;
463     }
464 }
465
466 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
467 {
468     BSTR identifier = ctx->instr->arg1.bstr;
469     const unsigned arg_cnt = ctx->instr->arg2.uint;
470     DISPPARAMS dp;
471     ref_t ref;
472     HRESULT hres;
473
474     hres = lookup_identifier(ctx, identifier, VBDISP_CALLGET, &ref);
475     if(FAILED(hres))
476         return hres;
477
478     vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
479
480     switch(ref.type) {
481     case REF_VAR:
482     case REF_CONST:
483         if(!res) {
484             FIXME("REF_VAR no res\n");
485             return E_NOTIMPL;
486         }
487
488         if(arg_cnt) {
489             FIXME("arguments not implemented\n");
490             return E_NOTIMPL;
491         }
492
493         V_VT(res) = VT_BYREF|VT_VARIANT;
494         V_BYREF(res) = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
495         break;
496     case REF_DISP:
497         hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
498         if(FAILED(hres))
499             return hres;
500         break;
501     case REF_FUNC:
502         hres = exec_script(ctx->script, ref.u.f, NULL, &dp, res);
503         if(FAILED(hres))
504             return hres;
505         break;
506     case REF_OBJ:
507         if(arg_cnt) {
508             FIXME("arguments on object\n");
509             return E_NOTIMPL;
510         }
511
512         if(res) {
513             IDispatch_AddRef(ref.u.obj);
514             V_VT(res) = VT_DISPATCH;
515             V_DISPATCH(res) = ref.u.obj;
516         }
517         break;
518     case REF_NONE:
519         FIXME("%s not found\n", debugstr_w(identifier));
520         return DISP_E_UNKNOWNNAME;
521     }
522
523     stack_popn(ctx, arg_cnt);
524     return S_OK;
525 }
526
527 static HRESULT interp_icall(exec_ctx_t *ctx)
528 {
529     VARIANT v;
530     HRESULT hres;
531
532     TRACE("\n");
533
534     hres = do_icall(ctx, &v);
535     if(FAILED(hres))
536         return hres;
537
538     return stack_push(ctx, &v);
539 }
540
541 static HRESULT interp_icallv(exec_ctx_t *ctx)
542 {
543     TRACE("\n");
544     return do_icall(ctx, NULL);
545 }
546
547 static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res)
548 {
549     const BSTR identifier = ctx->instr->arg1.bstr;
550     const unsigned arg_cnt = ctx->instr->arg2.uint;
551     IDispatch *obj;
552     DISPPARAMS dp;
553     DISPID id;
554     HRESULT hres;
555
556     hres = stack_pop_disp(ctx, &obj);
557     if(FAILED(hres))
558         return hres;
559
560     if(!obj) {
561         FIXME("NULL obj\n");
562         return E_FAIL;
563     }
564
565     vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
566
567     hres = disp_get_id(obj, identifier, VBDISP_CALLGET, FALSE, &id);
568     if(SUCCEEDED(hres))
569         hres = disp_call(ctx->script, obj, id, &dp, res);
570     IDispatch_Release(obj);
571     if(FAILED(hres))
572         return hres;
573
574     stack_popn(ctx, arg_cnt);
575     return S_OK;
576 }
577
578 static HRESULT interp_mcall(exec_ctx_t *ctx)
579 {
580     VARIANT res;
581     HRESULT hres;
582
583     TRACE("\n");
584
585     hres = do_mcall(ctx, &res);
586     if(FAILED(hres))
587         return hres;
588
589     return stack_push(ctx, &res);
590 }
591
592 static HRESULT interp_mcallv(exec_ctx_t *ctx)
593 {
594     TRACE("\n");
595
596     return do_mcall(ctx, NULL);
597 }
598
599 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, DISPPARAMS *dp)
600 {
601     ref_t ref;
602     HRESULT hres;
603
604     hres = lookup_identifier(ctx, name, VBDISP_LET, &ref);
605     if(FAILED(hres))
606         return hres;
607
608     switch(ref.type) {
609     case REF_VAR: {
610         VARIANT *v = ref.u.v;
611
612         if(arg_cnt(dp)) {
613             FIXME("arg_cnt %d not supported\n", arg_cnt(dp));
614             return E_NOTIMPL;
615         }
616
617         if(V_VT(v) == (VT_VARIANT|VT_BYREF))
618             v = V_VARIANTREF(v);
619
620         hres = VariantCopy(v, dp->rgvarg);
621         break;
622     }
623     case REF_DISP:
624         hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, dp);
625         break;
626     case REF_FUNC:
627         FIXME("functions not implemented\n");
628         return E_NOTIMPL;
629     case REF_OBJ:
630         FIXME("REF_OBJ\n");
631         return E_NOTIMPL;
632     case REF_CONST:
633         FIXME("REF_CONST\n");
634         return E_NOTIMPL;
635     case REF_NONE:
636         if(ctx->func->code_ctx->option_explicit) {
637             FIXME("throw exception\n");
638             hres = E_FAIL;
639         }else {
640             if(arg_cnt(dp)) {
641                 FIXME("arg_cnt %d not supported\n", arg_cnt(dp));
642                 return E_NOTIMPL;
643             }
644
645             TRACE("creating variable %s\n", debugstr_w(name));
646             hres = add_dynamic_var(ctx, name, FALSE, dp->rgvarg, FALSE);
647         }
648     }
649
650     return hres;
651 }
652
653 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
654 {
655     const BSTR arg = ctx->instr->arg1.bstr;
656     const unsigned arg_cnt = ctx->instr->arg2.uint;
657     DISPPARAMS dp;
658     HRESULT hres;
659
660     TRACE("%s\n", debugstr_w(arg));
661
662     hres = stack_assume_val(ctx, arg_cnt);
663     if(FAILED(hres))
664         return hres;
665
666     vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
667     hres = assign_ident(ctx, arg, &dp);
668     if(FAILED(hres))
669         return hres;
670
671     stack_popn(ctx, arg_cnt+1);
672     return S_OK;
673 }
674
675 static HRESULT interp_set_ident(exec_ctx_t *ctx)
676 {
677     const BSTR arg = ctx->instr->arg1.bstr;
678     const unsigned arg_cnt = ctx->instr->arg2.uint;
679     DISPPARAMS dp;
680     HRESULT hres;
681
682     TRACE("%s\n", debugstr_w(arg));
683
684     if(arg_cnt) {
685         FIXME("arguments not supported\n");
686         return E_NOTIMPL;
687     }
688
689     hres = stack_assume_disp(ctx, 0, NULL);
690     if(FAILED(hres))
691         return hres;
692
693     vbstack_to_dp(ctx, 0, TRUE, &dp);
694     hres = assign_ident(ctx, ctx->instr->arg1.bstr, &dp);
695     if(FAILED(hres))
696         return hres;
697
698     stack_popn(ctx, 1);
699     return S_OK;
700 }
701
702 static HRESULT interp_assign_member(exec_ctx_t *ctx)
703 {
704     BSTR identifier = ctx->instr->arg1.bstr;
705     const unsigned arg_cnt = ctx->instr->arg2.uint;
706     IDispatch *obj;
707     DISPPARAMS dp;
708     DISPID id;
709     HRESULT hres;
710
711     TRACE("%s\n", debugstr_w(identifier));
712
713     hres = stack_assume_disp(ctx, arg_cnt+1, &obj);
714     if(FAILED(hres))
715         return hres;
716
717     if(!obj) {
718         FIXME("NULL obj\n");
719         return E_FAIL;
720     }
721
722     hres = stack_assume_val(ctx, arg_cnt);
723     if(FAILED(hres))
724         return hres;
725
726     hres = disp_get_id(obj, identifier, VBDISP_LET, FALSE, &id);
727     if(SUCCEEDED(hres)) {
728         vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
729         hres = disp_propput(ctx->script, obj, id, &dp);
730     }
731     if(FAILED(hres))
732         return hres;
733
734     stack_popn(ctx, arg_cnt+2);
735     return S_OK;
736 }
737
738 static HRESULT interp_set_member(exec_ctx_t *ctx)
739 {
740     BSTR identifier = ctx->instr->arg1.bstr;
741     const unsigned arg_cnt = ctx->instr->arg2.uint;
742     IDispatch *obj;
743     DISPPARAMS dp;
744     DISPID id;
745     HRESULT hres;
746
747     TRACE("%s\n", debugstr_w(identifier));
748
749     if(arg_cnt) {
750         FIXME("arguments not supported\n");
751         return E_NOTIMPL;
752     }
753
754     hres = stack_assume_disp(ctx, 1, &obj);
755     if(FAILED(hres))
756         return hres;
757
758     if(!obj) {
759         FIXME("NULL obj\n");
760         return E_FAIL;
761     }
762
763     hres = stack_assume_disp(ctx, 0, NULL);
764     if(FAILED(hres))
765         return hres;
766
767     hres = disp_get_id(obj, identifier, VBDISP_SET, FALSE, &id);
768     if(SUCCEEDED(hres)) {
769         vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
770         hres = disp_propput(ctx->script, obj, id, &dp);
771     }
772     if(FAILED(hres))
773         return hres;
774
775     stack_popn(ctx, 2);
776     return S_OK;
777 }
778
779 static HRESULT interp_const(exec_ctx_t *ctx)
780 {
781     BSTR arg = ctx->instr->arg1.bstr;
782     variant_val_t val;
783     ref_t ref;
784     HRESULT hres;
785
786     TRACE("%s\n", debugstr_w(arg));
787
788     assert(ctx->func->type == FUNC_GLOBAL);
789
790     hres = lookup_identifier(ctx, arg, VBDISP_CALLGET, &ref);
791     if(FAILED(hres))
792         return hres;
793
794     if(ref.type != REF_NONE) {
795         FIXME("%s already defined\n", debugstr_w(arg));
796         return E_FAIL;
797     }
798
799     hres = stack_pop_val(ctx, &val);
800     if(FAILED(hres))
801         return hres;
802
803     return add_dynamic_var(ctx, arg, TRUE, val.v, val.owned);
804 }
805
806 static HRESULT interp_val(exec_ctx_t *ctx)
807 {
808     variant_val_t val;
809     VARIANT v;
810     HRESULT hres;
811
812     TRACE("\n");
813
814     hres = stack_pop_val(ctx, &val);
815     if(FAILED(hres))
816         return hres;
817
818     if(!val.owned) {
819         V_VT(&v) = VT_EMPTY;
820         hres = VariantCopy(&v, val.v);
821         if(FAILED(hres))
822             return hres;
823     }
824
825     return stack_push(ctx, val.owned ? val.v : &v);
826 }
827
828 static HRESULT interp_pop(exec_ctx_t *ctx)
829 {
830     const unsigned n = ctx->instr->arg1.uint;
831
832     TRACE("%u\n", n);
833
834     stack_popn(ctx, n);
835     return S_OK;
836 }
837
838 static HRESULT interp_new(exec_ctx_t *ctx)
839 {
840     const WCHAR *arg = ctx->instr->arg1.bstr;
841     class_desc_t *class_desc;
842     vbdisp_t *obj;
843     VARIANT v;
844     HRESULT hres;
845
846     TRACE("%s\n", debugstr_w(arg));
847
848     for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
849         if(!strcmpiW(class_desc->name, arg))
850             break;
851     }
852     if(!class_desc) {
853         FIXME("Class %s not found\n", debugstr_w(arg));
854         return E_FAIL;
855     }
856
857     hres = create_vbdisp(class_desc, &obj);
858     if(FAILED(hres))
859         return hres;
860
861     V_VT(&v) = VT_DISPATCH;
862     V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
863     return stack_push(ctx, &v);
864 }
865
866 static HRESULT interp_step(exec_ctx_t *ctx)
867 {
868     const BSTR ident = ctx->instr->arg2.bstr;
869     BOOL gteq_zero;
870     VARIANT zero;
871     ref_t ref;
872     HRESULT hres;
873
874     TRACE("%s\n", debugstr_w(ident));
875
876     V_VT(&zero) = VT_I2;
877     V_I2(&zero) = 0;
878     hres = VarCmp(stack_top(ctx, 0), &zero, ctx->script->lcid, 0);
879     if(FAILED(hres))
880         return hres;
881
882     gteq_zero = hres == VARCMP_GT || hres == VARCMP_EQ;
883
884     hres = lookup_identifier(ctx, ident, VBDISP_ANY, &ref);
885     if(FAILED(hres))
886         return hres;
887
888     if(ref.type != REF_VAR) {
889         FIXME("%s is not REF_VAR\n", debugstr_w(ident));
890         return E_FAIL;
891     }
892
893     hres = VarCmp(ref.u.v, stack_top(ctx, 1), ctx->script->lcid, 0);
894     if(FAILED(hres))
895         return hres;
896
897     if(hres == VARCMP_EQ || hres == (gteq_zero ? VARCMP_LT : VARCMP_GT)) {
898         ctx->instr++;
899     }else {
900         stack_popn(ctx, 2);
901         instr_jmp(ctx, ctx->instr->arg1.uint);
902     }
903     return S_OK;
904 }
905
906 static HRESULT interp_newenum(exec_ctx_t *ctx)
907 {
908     VARIANT *v, r;
909     HRESULT hres;
910
911     TRACE("\n");
912
913     v = stack_pop(ctx);
914     switch(V_VT(v)) {
915     case VT_DISPATCH: {
916         IEnumVARIANT *iter;
917         DISPPARAMS dp = {0};
918         VARIANT iterv;
919
920         hres = disp_call(ctx->script, V_DISPATCH(v), DISPID_NEWENUM, &dp, &iterv);
921         VariantClear(v);
922         if(FAILED(hres))
923             return hres;
924
925         if(V_VT(&iterv) != VT_UNKNOWN && V_VT(&iterv) != VT_DISPATCH) {
926             FIXME("Unsupported iterv %s\n", debugstr_variant(&iterv));
927             VariantClear(&iterv);
928             return hres;
929         }
930
931         hres = IUnknown_QueryInterface(V_UNKNOWN(&iterv), &IID_IEnumVARIANT, (void**)&iter);
932         IUnknown_Release(V_UNKNOWN(&iterv));
933         if(FAILED(hres)) {
934             FIXME("Could not get IEnumVARIANT iface: %08x\n", hres);
935             return hres;
936         }
937
938         V_VT(&r) = VT_UNKNOWN;
939         V_UNKNOWN(&r) = (IUnknown*)iter;
940         break;
941     }
942     default:
943         FIXME("Unsupported for %s\n", debugstr_variant(v));
944         VariantClear(v);
945         return E_NOTIMPL;
946     }
947
948     return stack_push(ctx, &r);
949 }
950
951 static HRESULT interp_enumnext(exec_ctx_t *ctx)
952 {
953     const unsigned loop_end = ctx->instr->arg1.uint;
954     const BSTR ident = ctx->instr->arg2.bstr;
955     VARIANT v;
956     DISPPARAMS dp = {&v, &propput_dispid, 1, 1};
957     IEnumVARIANT *iter;
958     BOOL do_continue;
959     HRESULT hres;
960
961     TRACE("\n");
962
963     assert(V_VT(stack_top(ctx, 0)) == VT_UNKNOWN);
964     iter = (IEnumVARIANT*)V_UNKNOWN(stack_top(ctx, 0));
965
966     V_VT(&v) = VT_EMPTY;
967     hres = IEnumVARIANT_Next(iter, 1, &v, NULL);
968     if(FAILED(hres))
969         return hres;
970
971     do_continue = hres == S_OK;
972     hres = assign_ident(ctx, ident, &dp);
973     VariantClear(&v);
974     if(FAILED(hres))
975         return hres;
976
977     if(do_continue) {
978         ctx->instr++;
979     }else {
980         stack_pop(ctx);
981         instr_jmp(ctx, loop_end);
982     }
983     return S_OK;
984 }
985
986 static HRESULT interp_jmp(exec_ctx_t *ctx)
987 {
988     const unsigned arg = ctx->instr->arg1.uint;
989
990     TRACE("%u\n", arg);
991
992     instr_jmp(ctx, arg);
993     return S_OK;
994 }
995
996 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
997 {
998     const unsigned arg = ctx->instr->arg1.uint;
999     HRESULT hres;
1000     BOOL b;
1001
1002     TRACE("%u\n", arg);
1003
1004     hres = stack_pop_bool(ctx, &b);
1005     if(FAILED(hres))
1006         return hres;
1007
1008     if(b)
1009         ctx->instr++;
1010     else
1011         instr_jmp(ctx, ctx->instr->arg1.uint);
1012     return S_OK;
1013 }
1014
1015 static HRESULT interp_jmp_true(exec_ctx_t *ctx)
1016 {
1017     const unsigned arg = ctx->instr->arg1.uint;
1018     HRESULT hres;
1019     BOOL b;
1020
1021     TRACE("%u\n", arg);
1022
1023     hres = stack_pop_bool(ctx, &b);
1024     if(FAILED(hres))
1025         return hres;
1026
1027     if(b)
1028         instr_jmp(ctx, ctx->instr->arg1.uint);
1029     else
1030         ctx->instr++;
1031     return S_OK;
1032 }
1033
1034 static HRESULT interp_ret(exec_ctx_t *ctx)
1035 {
1036     TRACE("\n");
1037
1038     ctx->instr = NULL;
1039     return S_OK;
1040 }
1041
1042 static HRESULT interp_stop(exec_ctx_t *ctx)
1043 {
1044     WARN("\n");
1045
1046     /* NOTE: this should have effect in debugging mode (that we don't support yet) */
1047     return S_OK;
1048 }
1049
1050 static HRESULT interp_me(exec_ctx_t *ctx)
1051 {
1052     VARIANT v;
1053
1054     TRACE("\n");
1055
1056     IDispatch_AddRef(ctx->this_obj);
1057     V_VT(&v) = VT_DISPATCH;
1058     V_DISPATCH(&v) = ctx->this_obj;
1059     return stack_push(ctx, &v);
1060 }
1061
1062 static HRESULT interp_bool(exec_ctx_t *ctx)
1063 {
1064     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
1065     VARIANT v;
1066
1067     TRACE("%s\n", arg ? "true" : "false");
1068
1069     V_VT(&v) = VT_BOOL;
1070     V_BOOL(&v) = arg;
1071     return stack_push(ctx, &v);
1072 }
1073
1074 static HRESULT interp_errmode(exec_ctx_t *ctx)
1075 {
1076     const int err_mode = ctx->instr->arg1.uint;
1077
1078     TRACE("%d\n", err_mode);
1079
1080     ctx->resume_next = err_mode;
1081     return S_OK;
1082 }
1083
1084 static HRESULT interp_string(exec_ctx_t *ctx)
1085 {
1086     VARIANT v;
1087
1088     TRACE("\n");
1089
1090     V_VT(&v) = VT_BSTR;
1091     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
1092     if(!V_BSTR(&v))
1093         return E_OUTOFMEMORY;
1094
1095     return stack_push(ctx, &v);
1096 }
1097
1098 static HRESULT interp_long(exec_ctx_t *ctx)
1099 {
1100     const LONG arg = ctx->instr->arg1.lng;
1101     VARIANT v;
1102
1103     TRACE("%d\n", arg);
1104
1105     V_VT(&v) = VT_I4;
1106     V_I4(&v) = arg;
1107     return stack_push(ctx, &v);
1108 }
1109
1110 static HRESULT interp_short(exec_ctx_t *ctx)
1111 {
1112     const LONG arg = ctx->instr->arg1.lng;
1113     VARIANT v;
1114
1115     TRACE("%d\n", arg);
1116
1117     V_VT(&v) = VT_I2;
1118     V_I2(&v) = arg;
1119     return stack_push(ctx, &v);
1120 }
1121
1122 static HRESULT interp_double(exec_ctx_t *ctx)
1123 {
1124     const DOUBLE *arg = ctx->instr->arg1.dbl;
1125     VARIANT v;
1126
1127     TRACE("%lf\n", *arg);
1128
1129     V_VT(&v) = VT_R8;
1130     V_R8(&v) = *arg;
1131     return stack_push(ctx, &v);
1132 }
1133
1134 static HRESULT interp_empty(exec_ctx_t *ctx)
1135 {
1136     VARIANT v;
1137
1138     TRACE("\n");
1139
1140     V_VT(&v) = VT_EMPTY;
1141     return stack_push(ctx, &v);
1142 }
1143
1144 static HRESULT interp_null(exec_ctx_t *ctx)
1145 {
1146     VARIANT v;
1147
1148     TRACE("\n");
1149
1150     V_VT(&v) = VT_NULL;
1151     return stack_push(ctx, &v);
1152 }
1153
1154 static HRESULT interp_nothing(exec_ctx_t *ctx)
1155 {
1156     VARIANT v;
1157
1158     TRACE("\n");
1159
1160     V_VT(&v) = VT_DISPATCH;
1161     V_DISPATCH(&v) = NULL;
1162     return stack_push(ctx, &v);
1163 }
1164
1165 static HRESULT interp_not(exec_ctx_t *ctx)
1166 {
1167     variant_val_t val;
1168     VARIANT v;
1169     HRESULT hres;
1170
1171     TRACE("\n");
1172
1173     hres = stack_pop_val(ctx, &val);
1174     if(FAILED(hres))
1175         return hres;
1176
1177     hres = VarNot(val.v, &v);
1178     release_val(&val);
1179     if(FAILED(hres))
1180         return hres;
1181
1182     return stack_push(ctx, &v);
1183 }
1184
1185 static HRESULT interp_and(exec_ctx_t *ctx)
1186 {
1187     variant_val_t r, l;
1188     VARIANT v;
1189     HRESULT hres;
1190
1191     TRACE("\n");
1192
1193     hres = stack_pop_val(ctx, &r);
1194     if(FAILED(hres))
1195         return hres;
1196
1197     hres = stack_pop_val(ctx, &l);
1198     if(SUCCEEDED(hres)) {
1199         hres = VarAnd(l.v, r.v, &v);
1200         release_val(&l);
1201     }
1202     release_val(&r);
1203     if(FAILED(hres))
1204         return hres;
1205
1206     return stack_push(ctx, &v);
1207 }
1208
1209 static HRESULT interp_or(exec_ctx_t *ctx)
1210 {
1211     variant_val_t r, l;
1212     VARIANT v;
1213     HRESULT hres;
1214
1215     TRACE("\n");
1216
1217     hres = stack_pop_val(ctx, &r);
1218     if(FAILED(hres))
1219         return hres;
1220
1221     hres = stack_pop_val(ctx, &l);
1222     if(SUCCEEDED(hres)) {
1223         hres = VarOr(l.v, r.v, &v);
1224         release_val(&l);
1225     }
1226     release_val(&r);
1227     if(FAILED(hres))
1228         return hres;
1229
1230     return stack_push(ctx, &v);
1231 }
1232
1233 static HRESULT interp_xor(exec_ctx_t *ctx)
1234 {
1235     variant_val_t r, l;
1236     VARIANT v;
1237     HRESULT hres;
1238
1239     TRACE("\n");
1240
1241     hres = stack_pop_val(ctx, &r);
1242     if(FAILED(hres))
1243         return hres;
1244
1245     hres = stack_pop_val(ctx, &l);
1246     if(SUCCEEDED(hres)) {
1247         hres = VarXor(l.v, r.v, &v);
1248         release_val(&l);
1249     }
1250     release_val(&r);
1251     if(FAILED(hres))
1252         return hres;
1253
1254     return stack_push(ctx, &v);
1255 }
1256
1257 static HRESULT interp_eqv(exec_ctx_t *ctx)
1258 {
1259     variant_val_t r, l;
1260     VARIANT v;
1261     HRESULT hres;
1262
1263     TRACE("\n");
1264
1265     hres = stack_pop_val(ctx, &r);
1266     if(FAILED(hres))
1267         return hres;
1268
1269     hres = stack_pop_val(ctx, &l);
1270     if(SUCCEEDED(hres)) {
1271         hres = VarEqv(l.v, r.v, &v);
1272         release_val(&l);
1273     }
1274     release_val(&r);
1275     if(FAILED(hres))
1276         return hres;
1277
1278     return stack_push(ctx, &v);
1279 }
1280
1281 static HRESULT interp_imp(exec_ctx_t *ctx)
1282 {
1283     variant_val_t r, l;
1284     VARIANT v;
1285     HRESULT hres;
1286
1287     TRACE("\n");
1288
1289     hres = stack_pop_val(ctx, &r);
1290     if(FAILED(hres))
1291         return hres;
1292
1293     hres = stack_pop_val(ctx, &l);
1294     if(SUCCEEDED(hres)) {
1295         hres = VarImp(l.v, r.v, &v);
1296         release_val(&l);
1297     }
1298     release_val(&r);
1299     if(FAILED(hres))
1300         return hres;
1301
1302     return stack_push(ctx, &v);
1303 }
1304
1305 static HRESULT var_cmp(exec_ctx_t *ctx, VARIANT *l, VARIANT *r)
1306 {
1307     TRACE("%s %s\n", debugstr_variant(l), debugstr_variant(r));
1308
1309     if(V_VT(l) == VT_NULL || V_VT(r) == VT_NULL) {
1310         FIXME("comparing nulls is not implemented\n");
1311         return E_NOTIMPL;
1312     }
1313
1314     /* FIXME: Fix comparing string to number */
1315
1316     return VarCmp(l, r, ctx->script->lcid, 0);
1317  }
1318
1319 static HRESULT cmp_oper(exec_ctx_t *ctx)
1320 {
1321     variant_val_t l, r;
1322     HRESULT hres;
1323
1324     hres = stack_pop_val(ctx, &r);
1325     if(FAILED(hres))
1326         return hres;
1327
1328     hres = stack_pop_val(ctx, &l);
1329     if(SUCCEEDED(hres)) {
1330         hres = var_cmp(ctx, l.v, r.v);
1331         release_val(&l);
1332     }
1333
1334     release_val(&r);
1335     return hres;
1336 }
1337
1338 static HRESULT interp_equal(exec_ctx_t *ctx)
1339 {
1340     VARIANT v;
1341     HRESULT hres;
1342
1343     TRACE("\n");
1344
1345     hres = cmp_oper(ctx);
1346     if(FAILED(hres))
1347         return hres;
1348
1349     V_VT(&v) = VT_BOOL;
1350     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1351     return stack_push(ctx, &v);
1352 }
1353
1354 static HRESULT interp_nequal(exec_ctx_t *ctx)
1355 {
1356     VARIANT v;
1357     HRESULT hres;
1358
1359     TRACE("\n");
1360
1361     hres = cmp_oper(ctx);
1362     if(FAILED(hres))
1363         return hres;
1364
1365     V_VT(&v) = VT_BOOL;
1366     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1367     return stack_push(ctx, &v);
1368 }
1369
1370 static HRESULT interp_gt(exec_ctx_t *ctx)
1371 {
1372     VARIANT v;
1373     HRESULT hres;
1374
1375     TRACE("\n");
1376
1377     hres = cmp_oper(ctx);
1378     if(FAILED(hres))
1379         return hres;
1380
1381     V_VT(&v) = VT_BOOL;
1382     V_BOOL(&v) = hres == VARCMP_GT ? VARIANT_TRUE : VARIANT_FALSE;
1383     return stack_push(ctx, &v);
1384 }
1385
1386 static HRESULT interp_gteq(exec_ctx_t *ctx)
1387 {
1388     VARIANT v;
1389     HRESULT hres;
1390
1391     TRACE("\n");
1392
1393     hres = cmp_oper(ctx);
1394     if(FAILED(hres))
1395         return hres;
1396
1397     V_VT(&v) = VT_BOOL;
1398     V_BOOL(&v) = hres == VARCMP_GT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1399     return stack_push(ctx, &v);
1400 }
1401
1402 static HRESULT interp_lt(exec_ctx_t *ctx)
1403 {
1404     VARIANT v;
1405     HRESULT hres;
1406
1407     TRACE("\n");
1408
1409     hres = cmp_oper(ctx);
1410     if(FAILED(hres))
1411         return hres;
1412
1413     V_VT(&v) = VT_BOOL;
1414     V_BOOL(&v) = hres == VARCMP_LT ? VARIANT_TRUE : VARIANT_FALSE;
1415     return stack_push(ctx, &v);
1416 }
1417
1418 static HRESULT interp_lteq(exec_ctx_t *ctx)
1419 {
1420     VARIANT v;
1421     HRESULT hres;
1422
1423     TRACE("\n");
1424
1425     hres = cmp_oper(ctx);
1426     if(FAILED(hres))
1427         return hres;
1428
1429     V_VT(&v) = VT_BOOL;
1430     V_BOOL(&v) = hres == VARCMP_LT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1431     return stack_push(ctx, &v);
1432 }
1433
1434 static HRESULT interp_case(exec_ctx_t *ctx)
1435 {
1436     const unsigned arg = ctx->instr->arg1.uint;
1437     variant_val_t v;
1438     HRESULT hres;
1439
1440     TRACE("%d\n", arg);
1441
1442     hres = stack_pop_val(ctx, &v);
1443     if(FAILED(hres))
1444         return hres;
1445
1446     hres = var_cmp(ctx, stack_top(ctx, 0), v.v);
1447     release_val(&v);
1448     if(FAILED(hres))
1449         return hres;
1450
1451     if(hres == VARCMP_EQ) {
1452         stack_popn(ctx, 1);
1453         instr_jmp(ctx, arg);
1454     }else {
1455         ctx->instr++;
1456     }
1457
1458     return S_OK;
1459 }
1460
1461 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, VARIANT_BOOL *ret)
1462 {
1463     IObjectIdentity *identity;
1464     IUnknown *unk1, *unk2;
1465     HRESULT hres;
1466
1467     if(disp1 == disp2) {
1468         *ret = VARIANT_TRUE;
1469         return S_OK;
1470     }
1471
1472     if(!disp1 || !disp2) {
1473         *ret = VARIANT_FALSE;
1474         return S_OK;
1475     }
1476
1477     hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
1478     if(FAILED(hres))
1479         return hres;
1480
1481     hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
1482     if(FAILED(hres)) {
1483         IUnknown_Release(unk1);
1484         return hres;
1485     }
1486
1487     if(unk1 == unk2) {
1488         *ret = VARIANT_TRUE;
1489     }else {
1490         hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
1491         if(SUCCEEDED(hres)) {
1492             hres = IObjectIdentity_IsEqualObject(identity, unk2);
1493             IObjectIdentity_Release(identity);
1494             *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
1495         }else {
1496             *ret = VARIANT_FALSE;
1497         }
1498     }
1499
1500     IUnknown_Release(unk1);
1501     IUnknown_Release(unk2);
1502     return S_OK;
1503 }
1504
1505 static HRESULT interp_is(exec_ctx_t *ctx)
1506 {
1507     IDispatch *l, *r;
1508     VARIANT v;
1509     HRESULT hres;
1510
1511     TRACE("\n");
1512
1513     hres = stack_pop_disp(ctx, &r);
1514     if(FAILED(hres))
1515         return hres;
1516
1517     hres = stack_pop_disp(ctx, &l);
1518     if(SUCCEEDED(hres)) {
1519         V_VT(&v) = VT_BOOL;
1520         hres = disp_cmp(l, r, &V_BOOL(&v));
1521         if(l)
1522             IDispatch_Release(l);
1523     }
1524     if(r)
1525         IDispatch_Release(r);
1526     if(FAILED(hres))
1527         return hres;
1528
1529     return stack_push(ctx, &v);
1530 }
1531
1532 static HRESULT interp_concat(exec_ctx_t *ctx)
1533 {
1534     variant_val_t r, l;
1535     VARIANT v;
1536     HRESULT hres;
1537
1538     TRACE("\n");
1539
1540     hres = stack_pop_val(ctx, &r);
1541     if(FAILED(hres))
1542         return hres;
1543
1544     hres = stack_pop_val(ctx, &l);
1545     if(SUCCEEDED(hres)) {
1546         hres = VarCat(l.v, r.v, &v);
1547         release_val(&l);
1548     }
1549     release_val(&r);
1550     if(FAILED(hres))
1551         return hres;
1552
1553     return stack_push(ctx, &v);
1554 }
1555
1556 static HRESULT interp_add(exec_ctx_t *ctx)
1557 {
1558     variant_val_t r, l;
1559     VARIANT v;
1560     HRESULT hres;
1561
1562     TRACE("\n");
1563
1564     hres = stack_pop_val(ctx, &r);
1565     if(FAILED(hres))
1566         return hres;
1567
1568     hres = stack_pop_val(ctx, &l);
1569     if(SUCCEEDED(hres)) {
1570         hres = VarAdd(l.v, r.v, &v);
1571         release_val(&l);
1572     }
1573     release_val(&r);
1574     if(FAILED(hres))
1575         return hres;
1576
1577     return stack_push(ctx, &v);
1578 }
1579
1580 static HRESULT interp_sub(exec_ctx_t *ctx)
1581 {
1582     variant_val_t r, l;
1583     VARIANT v;
1584     HRESULT hres;
1585
1586     TRACE("\n");
1587
1588     hres = stack_pop_val(ctx, &r);
1589     if(FAILED(hres))
1590         return hres;
1591
1592     hres = stack_pop_val(ctx, &l);
1593     if(SUCCEEDED(hres)) {
1594         hres = VarSub(l.v, r.v, &v);
1595         release_val(&l);
1596     }
1597     release_val(&r);
1598     if(FAILED(hres))
1599         return hres;
1600
1601     return stack_push(ctx, &v);
1602 }
1603
1604 static HRESULT interp_mod(exec_ctx_t *ctx)
1605 {
1606     variant_val_t r, l;
1607     VARIANT v;
1608     HRESULT hres;
1609
1610     TRACE("\n");
1611
1612     hres = stack_pop_val(ctx, &r);
1613     if(FAILED(hres))
1614         return hres;
1615
1616     hres = stack_pop_val(ctx, &l);
1617     if(SUCCEEDED(hres)) {
1618         hres = VarMod(l.v, r.v, &v);
1619         release_val(&l);
1620     }
1621     release_val(&r);
1622     if(FAILED(hres))
1623         return hres;
1624
1625     return stack_push(ctx, &v);
1626 }
1627
1628 static HRESULT interp_idiv(exec_ctx_t *ctx)
1629 {
1630     variant_val_t r, l;
1631     VARIANT v;
1632     HRESULT hres;
1633
1634     TRACE("\n");
1635
1636     hres = stack_pop_val(ctx, &r);
1637     if(FAILED(hres))
1638         return hres;
1639
1640     hres = stack_pop_val(ctx, &l);
1641     if(SUCCEEDED(hres)) {
1642         hres = VarIdiv(l.v, r.v, &v);
1643         release_val(&l);
1644     }
1645     release_val(&r);
1646     if(FAILED(hres))
1647         return hres;
1648
1649     return stack_push(ctx, &v);
1650 }
1651
1652 static HRESULT interp_div(exec_ctx_t *ctx)
1653 {
1654     variant_val_t r, l;
1655     VARIANT v;
1656     HRESULT hres;
1657
1658     TRACE("\n");
1659
1660     hres = stack_pop_val(ctx, &r);
1661     if(FAILED(hres))
1662         return hres;
1663
1664     hres = stack_pop_val(ctx, &l);
1665     if(SUCCEEDED(hres)) {
1666         hres = VarDiv(l.v, r.v, &v);
1667         release_val(&l);
1668     }
1669     release_val(&r);
1670     if(FAILED(hres))
1671         return hres;
1672
1673     return stack_push(ctx, &v);
1674 }
1675
1676 static HRESULT interp_mul(exec_ctx_t *ctx)
1677 {
1678     variant_val_t r, l;
1679     VARIANT v;
1680     HRESULT hres;
1681
1682     TRACE("\n");
1683
1684     hres = stack_pop_val(ctx, &r);
1685     if(FAILED(hres))
1686         return hres;
1687
1688     hres = stack_pop_val(ctx, &l);
1689     if(SUCCEEDED(hres)) {
1690         hres = VarMul(l.v, r.v, &v);
1691         release_val(&l);
1692     }
1693     release_val(&r);
1694     if(FAILED(hres))
1695         return hres;
1696
1697     return stack_push(ctx, &v);
1698 }
1699
1700 static HRESULT interp_exp(exec_ctx_t *ctx)
1701 {
1702     variant_val_t r, l;
1703     VARIANT v;
1704     HRESULT hres;
1705
1706     TRACE("\n");
1707
1708     hres = stack_pop_val(ctx, &r);
1709     if(FAILED(hres))
1710         return hres;
1711
1712     hres = stack_pop_val(ctx, &l);
1713     if(SUCCEEDED(hres)) {
1714         hres = VarPow(l.v, r.v, &v);
1715         release_val(&l);
1716     }
1717     release_val(&r);
1718     if(FAILED(hres))
1719         return hres;
1720
1721     return stack_push(ctx, &v);
1722 }
1723
1724 static HRESULT interp_neg(exec_ctx_t *ctx)
1725 {
1726     variant_val_t val;
1727     VARIANT v;
1728     HRESULT hres;
1729
1730     hres = stack_pop_val(ctx, &val);
1731     if(FAILED(hres))
1732         return hres;
1733
1734     hres = VarNeg(val.v, &v);
1735     release_val(&val);
1736     if(FAILED(hres))
1737         return hres;
1738
1739     return stack_push(ctx, &v);
1740 }
1741
1742 static HRESULT interp_incc(exec_ctx_t *ctx)
1743 {
1744     const BSTR ident = ctx->instr->arg1.bstr;
1745     VARIANT v;
1746     ref_t ref;
1747     HRESULT hres;
1748
1749     TRACE("\n");
1750
1751     hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref);
1752     if(FAILED(hres))
1753         return hres;
1754
1755     if(ref.type != REF_VAR) {
1756         FIXME("ref.type is not REF_VAR\n");
1757         return E_FAIL;
1758     }
1759
1760     hres = VarAdd(stack_top(ctx, 0), ref.u.v, &v);
1761     if(FAILED(hres))
1762         return hres;
1763
1764     VariantClear(ref.u.v);
1765     *ref.u.v = v;
1766     return S_OK;
1767 }
1768
1769 static const instr_func_t op_funcs[] = {
1770 #define X(x,n,a,b) interp_ ## x,
1771 OP_LIST
1772 #undef X
1773 };
1774
1775 static const unsigned op_move[] = {
1776 #define X(x,n,a,b) n,
1777 OP_LIST
1778 #undef X
1779 };
1780
1781 void release_dynamic_vars(dynamic_var_t *var)
1782 {
1783     while(var) {
1784         VariantClear(&var->v);
1785         var = var->next;
1786     }
1787 }
1788
1789 static void release_exec(exec_ctx_t *ctx)
1790 {
1791     unsigned i;
1792
1793     VariantClear(&ctx->ret_val);
1794     release_dynamic_vars(ctx->dynamic_vars);
1795
1796     if(ctx->this_obj)
1797         IDispatch_Release(ctx->this_obj);
1798
1799     if(ctx->args) {
1800         for(i=0; i < ctx->func->arg_cnt; i++)
1801             VariantClear(ctx->args+i);
1802     }
1803
1804     if(ctx->vars) {
1805         for(i=0; i < ctx->func->var_cnt; i++)
1806             VariantClear(ctx->vars+i);
1807     }
1808
1809     vbsheap_free(&ctx->heap);
1810     heap_free(ctx->args);
1811     heap_free(ctx->vars);
1812     heap_free(ctx->stack);
1813 }
1814
1815 HRESULT exec_script(script_ctx_t *ctx, function_t *func, IDispatch *this_obj, DISPPARAMS *dp, VARIANT *res)
1816 {
1817     exec_ctx_t exec = {func->code_ctx};
1818     vbsop_t op;
1819     HRESULT hres = S_OK;
1820
1821     exec.code = func->code_ctx;
1822
1823     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
1824         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
1825         return E_FAIL;
1826     }
1827
1828     vbsheap_init(&exec.heap);
1829
1830     if(func->arg_cnt) {
1831         VARIANT *v;
1832         unsigned i;
1833
1834         exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
1835         if(!exec.args) {
1836             release_exec(&exec);
1837             return E_OUTOFMEMORY;
1838         }
1839
1840         for(i=0; i < func->arg_cnt; i++) {
1841             v = get_arg(dp, i);
1842             if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
1843                 if(func->args[i].by_ref)
1844                     exec.args[i] = *v;
1845                 else
1846                     hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
1847             }else {
1848                 hres = VariantCopy(exec.args+i, v);
1849             }
1850             if(FAILED(hres)) {
1851                 release_exec(&exec);
1852                 return hres;
1853             }
1854         }
1855     }else {
1856         exec.args = NULL;
1857     }
1858
1859     if(func->var_cnt) {
1860         exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
1861         if(!exec.vars) {
1862             release_exec(&exec);
1863             return E_OUTOFMEMORY;
1864         }
1865     }else {
1866         exec.vars = NULL;
1867     }
1868
1869     exec.stack_size = 16;
1870     exec.top = 0;
1871     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
1872     if(!exec.stack) {
1873         release_exec(&exec);
1874         return E_OUTOFMEMORY;
1875     }
1876
1877     if(this_obj)
1878         exec.this_obj = this_obj;
1879     else if (ctx->host_global)
1880         exec.this_obj = ctx->host_global;
1881     else
1882         exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface;
1883     IDispatch_AddRef(exec.this_obj);
1884
1885     exec.instr = exec.code->instrs + func->code_off;
1886     exec.script = ctx;
1887     exec.func = func;
1888
1889     while(exec.instr) {
1890         op = exec.instr->op;
1891         hres = op_funcs[op](&exec);
1892         if(FAILED(hres)) {
1893             if(exec.resume_next)
1894                 FIXME("Failed %08x in resume next mode\n", hres);
1895             else
1896                 WARN("Failed %08x\n", hres);
1897             stack_popn(&exec, exec.top);
1898             break;
1899         }
1900
1901         exec.instr += op_move[op];
1902     }
1903
1904     assert(!exec.top);
1905     if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)
1906         assert(V_VT(&exec.ret_val) == VT_EMPTY);
1907
1908     if(SUCCEEDED(hres) && res) {
1909         *res = exec.ret_val;
1910         V_VT(&exec.ret_val) = VT_EMPTY;
1911     }
1912
1913     release_exec(&exec);
1914     return hres;
1915 }