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