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