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