vbscript: Added interp_mcall implementation.
[wine] / dlls / vbscript / interp.c
1 /*
2  * Copyright 2011 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <assert.h>
20
21 #include "vbscript.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
26
27
28 typedef struct {
29     vbscode_t *code;
30     instr_t *instr;
31     script_ctx_t *script;
32     function_t *func;
33
34     VARIANT *args;
35     VARIANT *vars;
36
37     unsigned stack_size;
38     unsigned top;
39     VARIANT *stack;
40
41     VARIANT ret_val;
42 } exec_ctx_t;
43
44 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
45
46 typedef enum {
47     REF_NONE,
48     REF_DISP,
49     REF_VAR,
50     REF_FUNC
51 } ref_type_t;
52
53 typedef struct {
54     ref_type_t type;
55     union {
56         struct {
57             IDispatch *disp;
58             DISPID id;
59         } d;
60         VARIANT *v;
61         function_t *f;
62     } u;
63 } ref_t;
64
65 typedef struct {
66     VARIANT *v;
67     VARIANT store;
68     BOOL owned;
69 } variant_val_t;
70
71 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
72 {
73     while(var) {
74         if(!strcmpiW(var->name, name)) {
75             ref->type = REF_VAR;
76             ref->u.v = &var->v;
77             return TRUE;
78         }
79
80         var = var->next;
81     }
82
83     return FALSE;
84 }
85
86 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref)
87 {
88     named_item_t *item;
89     function_t *func;
90     unsigned i;
91     DISPID id;
92     HRESULT hres;
93
94     if(invoke_type == VBDISP_LET && ctx->func->type == FUNC_FUNCTION && !strcmpiW(name, ctx->func->name)) {
95         ref->type = REF_VAR;
96         ref->u.v = &ctx->ret_val;
97         return S_OK;
98     }
99
100     for(i=0; i < ctx->func->var_cnt; i++) {
101         if(!strcmpiW(ctx->func->vars[i].name, name)) {
102             ref->type = REF_VAR;
103             ref->u.v = ctx->vars+i;
104             return TRUE;
105         }
106     }
107
108     for(i=0; i < ctx->func->arg_cnt; i++) {
109         if(!strcmpiW(ctx->func->args[i].name, name)) {
110             ref->type = REF_VAR;
111             ref->u.v = ctx->args+i;
112             return S_OK;
113         }
114     }
115
116     if(lookup_dynamic_vars(ctx->script->global_vars, name, ref))
117         return S_OK;
118
119     for(func = ctx->script->global_funcs; func; func = func->next) {
120         if(!strcmpiW(func->name, name)) {
121             ref->type = REF_FUNC;
122             ref->u.f = func;
123             return S_OK;
124         }
125     }
126
127     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
128         if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
129             hres = disp_get_id(item->disp, name, &id);
130             if(SUCCEEDED(hres)) {
131                 ref->type = REF_DISP;
132                 ref->u.d.disp = item->disp;
133                 ref->u.d.id = id;
134                 return S_OK;
135             }
136         }
137     }
138
139     if(!ctx->func->code_ctx->option_explicit)
140         FIXME("create an attempt to set\n");
141
142     ref->type = REF_NONE;
143     return S_OK;
144 }
145
146 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
147 {
148     assert(ctx->top);
149     return ctx->stack + --ctx->top;
150 }
151
152 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
153 {
154     if(ctx->stack_size == ctx->top) {
155         VARIANT *new_stack;
156
157         new_stack = heap_realloc(ctx->stack, ctx->stack_size*2);
158         if(!new_stack) {
159             VariantClear(v);
160             return E_OUTOFMEMORY;
161         }
162
163         ctx->stack = new_stack;
164         ctx->stack_size *= 2;
165     }
166
167     ctx->stack[ctx->top++] = *v;
168     return S_OK;
169 }
170
171 static void stack_popn(exec_ctx_t *ctx, unsigned n)
172 {
173     while(n--)
174         VariantClear(stack_pop(ctx));
175 }
176
177 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *v)
178 {
179     VARIANT *var;
180
181     var = stack_pop(ctx);
182
183     if(V_VT(var) == (VT_BYREF|VT_VARIANT)) {
184         v->owned = FALSE;
185         var = V_VARIANTREF(var);
186     }else {
187         v->owned = TRUE;
188     }
189
190     if(V_VT(var) == VT_DISPATCH) {
191         FIXME("got dispatch - get its default value\n");
192         return E_NOTIMPL;
193     }else {
194         v->v = var;
195     }
196
197     return S_OK;
198 }
199
200 static inline void release_val(variant_val_t *v)
201 {
202     if(v->owned)
203         VariantClear(v->v);
204 }
205
206 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
207 {
208     VARIANT *v = stack_pop(ctx);
209
210     if(V_VT(v) == VT_DISPATCH) {
211         *ret = V_DISPATCH(v);
212         return S_OK;
213     }
214
215     if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
216         FIXME("not supported type: %s\n", debugstr_variant(v));
217         VariantClear(v);
218         return E_FAIL;
219     }
220
221     v = V_BYREF(v);
222     if(V_VT(v) != VT_DISPATCH) {
223         FIXME("not disp %s\n", debugstr_variant(v));
224         return E_FAIL;
225     }
226
227     if(V_DISPATCH(v))
228         IDispatch_AddRef(V_DISPATCH(v));
229     *ret = V_DISPATCH(v);
230     return S_OK;
231 }
232
233 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
234 {
235     ctx->instr = ctx->code->instrs + addr;
236 }
237
238 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, DISPPARAMS *dp)
239 {
240     dp->cArgs = arg_cnt;
241     dp->rgdispidNamedArgs = NULL;
242     dp->cNamedArgs = 0;
243
244     if(arg_cnt) {
245         VARIANT tmp;
246         unsigned i;
247
248         assert(ctx->top >= arg_cnt);
249
250         for(i=1; i*2 <= arg_cnt; i++) {
251             tmp = ctx->stack[ctx->top-i];
252             ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
253             ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
254         }
255
256         dp->rgvarg = ctx->stack + ctx->top-arg_cnt;
257     }else {
258         dp->rgvarg = NULL;
259     }
260 }
261
262 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
263 {
264     BSTR identifier = ctx->instr->arg1.bstr;
265     const unsigned arg_cnt = ctx->instr->arg2.uint;
266     ref_t ref = {0};
267     DISPPARAMS dp;
268     HRESULT hres;
269
270     hres = lookup_identifier(ctx, identifier, VBDISP_CALLGET, &ref);
271     if(FAILED(hres))
272         return hres;
273
274     vbstack_to_dp(ctx, arg_cnt, &dp);
275
276     switch(ref.type) {
277     case REF_VAR:
278         if(!res) {
279             FIXME("REF_VAR no res\n");
280             return E_NOTIMPL;
281         }
282
283         if(arg_cnt) {
284             FIXME("arguments not implemented\n");
285             return E_NOTIMPL;
286         }
287
288         V_VT(res) = VT_BYREF|VT_VARIANT;
289         V_BYREF(res) = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
290         break;
291     case REF_DISP:
292         hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
293         if(FAILED(hres))
294             return hres;
295         break;
296     case REF_FUNC:
297         hres = exec_script(ctx->script, ref.u.f, &dp, res);
298         if(FAILED(hres))
299             return hres;
300         break;
301     case REF_NONE:
302         FIXME("%s not found\n", debugstr_w(identifier));
303         return DISP_E_UNKNOWNNAME;
304     }
305
306     stack_popn(ctx, arg_cnt);
307     return S_OK;
308 }
309
310 static HRESULT interp_icall(exec_ctx_t *ctx)
311 {
312     VARIANT v;
313     HRESULT hres;
314
315     TRACE("\n");
316
317     hres = do_icall(ctx, &v);
318     if(FAILED(hres))
319         return hres;
320
321     return stack_push(ctx, &v);
322 }
323
324 static HRESULT interp_icallv(exec_ctx_t *ctx)
325 {
326     TRACE("\n");
327     return do_icall(ctx, NULL);
328 }
329
330 static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res)
331 {
332     const BSTR identifier = ctx->instr->arg1.bstr;
333     const unsigned arg_cnt = ctx->instr->arg2.uint;
334     IDispatch *obj;
335     DISPPARAMS dp;
336     DISPID id;
337     HRESULT hres;
338
339     hres = stack_pop_disp(ctx, &obj);
340     if(FAILED(hres))
341         return hres;
342
343     if(!obj) {
344         FIXME("NULL obj\n");
345         return E_FAIL;
346     }
347
348     vbstack_to_dp(ctx, arg_cnt, &dp);
349
350     hres = disp_get_id(obj, identifier, &id);
351     if(SUCCEEDED(hres))
352         hres = disp_call(ctx->script, obj, id, &dp, res);
353     IDispatch_Release(obj);
354     if(FAILED(hres))
355         return hres;
356
357     stack_popn(ctx, arg_cnt);
358     return S_OK;
359 }
360
361 static HRESULT interp_mcall(exec_ctx_t *ctx)
362 {
363     VARIANT res;
364     HRESULT hres;
365
366     TRACE("\n");
367
368     hres = do_mcall(ctx, &res);
369     if(FAILED(hres))
370         return hres;
371
372     return stack_push(ctx, &res);
373 }
374
375 static HRESULT interp_mcallv(exec_ctx_t *ctx)
376 {
377     TRACE("\n");
378
379     return do_mcall(ctx, NULL);
380 }
381
382 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
383 {
384     ref_t ref;
385     HRESULT hres;
386
387     hres = lookup_identifier(ctx, name, VBDISP_LET, &ref);
388     if(FAILED(hres))
389         return hres;
390
391     switch(ref.type) {
392     case REF_VAR: {
393         VARIANT *v = ref.u.v;
394
395         if(V_VT(v) == (VT_VARIANT|VT_BYREF))
396             v = V_VARIANTREF(v);
397
398         if(own_val) {
399             VariantClear(v);
400             *v = *val;
401             hres = S_OK;
402         }else {
403             hres = VariantCopy(v, val);
404         }
405         break;
406     }
407     case REF_DISP:
408         hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, val);
409         if(own_val)
410             VariantClear(val);
411         break;
412     case REF_FUNC:
413         FIXME("functions not implemented\n");
414         return E_NOTIMPL;
415     case REF_NONE:
416         FIXME("%s not found\n", debugstr_w(name));
417         if(own_val)
418             VariantClear(val);
419         return DISP_E_UNKNOWNNAME;
420     }
421
422     return hres;
423 }
424
425 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
426 {
427     const BSTR arg = ctx->instr->arg1.bstr;
428     variant_val_t v;
429     HRESULT hres;
430
431     TRACE("%s\n", debugstr_w(arg));
432
433     hres = stack_pop_val(ctx, &v);
434     if(FAILED(hres))
435         return hres;
436
437     return assign_ident(ctx, arg, v.v, v.owned);
438 }
439
440 static HRESULT interp_set_ident(exec_ctx_t *ctx)
441 {
442     const BSTR arg = ctx->instr->arg1.bstr;
443     IDispatch *disp;
444     VARIANT v;
445     HRESULT hres;
446
447     TRACE("%s\n", debugstr_w(arg));
448
449     hres = stack_pop_disp(ctx, &disp);
450     if(FAILED(hres))
451         return hres;
452
453     V_VT(&v) = VT_DISPATCH;
454     V_DISPATCH(&v) = disp;
455     return assign_ident(ctx, ctx->instr->arg1.bstr, &v, TRUE);
456 }
457
458 static HRESULT interp_assign_member(exec_ctx_t *ctx)
459 {
460     BSTR identifier = ctx->instr->arg1.bstr;
461     variant_val_t val;
462     IDispatch *obj;
463     DISPID id;
464     HRESULT hres;
465
466     TRACE("%s\n", debugstr_w(identifier));
467
468     hres = stack_pop_disp(ctx, &obj);
469     if(FAILED(hres))
470         return hres;
471
472     if(!obj) {
473         FIXME("NULL obj\n");
474         return E_FAIL;
475     }
476
477     hres = stack_pop_val(ctx, &val);
478     if(FAILED(hres)) {
479         IDispatch_Release(obj);
480         return hres;
481     }
482
483     hres = disp_get_id(obj, identifier, &id);
484     if(SUCCEEDED(hres))
485         hres = disp_propput(ctx->script, obj, id, val.v);
486
487     release_val(&val);
488     IDispatch_Release(obj);
489     return hres;
490 }
491
492 static HRESULT interp_set_member(exec_ctx_t *ctx)
493 {
494     BSTR identifier = ctx->instr->arg1.bstr;
495     FIXME("%s\n", debugstr_w(identifier));
496     return E_NOTIMPL;
497 }
498
499 static HRESULT interp_new(exec_ctx_t *ctx)
500 {
501     const WCHAR *arg = ctx->instr->arg1.bstr;
502     class_desc_t *class_desc;
503     vbdisp_t *obj;
504     VARIANT v;
505     HRESULT hres;
506
507     TRACE("%s\n", debugstr_w(arg));
508
509     for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
510         if(!strcmpiW(class_desc->name, arg))
511             break;
512     }
513     if(!class_desc) {
514         FIXME("Class %s not found\n", debugstr_w(arg));
515         return E_FAIL;
516     }
517
518     hres = create_vbdisp(class_desc, &obj);
519     if(FAILED(hres))
520         return hres;
521
522     V_VT(&v) = VT_DISPATCH;
523     V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
524     return stack_push(ctx, &v);
525 }
526
527 static HRESULT interp_jmp(exec_ctx_t *ctx)
528 {
529     const unsigned arg = ctx->instr->arg1.uint;
530
531     TRACE("%u\n", arg);
532
533     instr_jmp(ctx, arg);
534     return S_OK;
535 }
536
537 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
538 {
539     const unsigned arg = ctx->instr->arg1.uint;
540     variant_val_t val;
541     HRESULT hres;
542
543     TRACE("%u\n", arg);
544
545     hres = stack_pop_val(ctx, &val);
546     if(FAILED(hres))
547         return hres;
548
549     if(V_VT(val.v) != VT_BOOL) {
550         FIXME("unsupported for %s\n", debugstr_variant(val.v));
551         release_val(&val);
552         return E_NOTIMPL;
553     }
554
555     if(V_BOOL(val.v))
556         ctx->instr++;
557     else
558         instr_jmp(ctx, ctx->instr->arg1.uint);
559     return S_OK;
560 }
561
562 static HRESULT interp_ret(exec_ctx_t *ctx)
563 {
564     TRACE("\n");
565
566     ctx->instr = NULL;
567     return S_OK;
568 }
569
570 static HRESULT interp_bool(exec_ctx_t *ctx)
571 {
572     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
573     VARIANT v;
574
575     TRACE("%s\n", arg ? "true" : "false");
576
577     V_VT(&v) = VT_BOOL;
578     V_BOOL(&v) = arg;
579     return stack_push(ctx, &v);
580 }
581
582 static HRESULT interp_string(exec_ctx_t *ctx)
583 {
584     VARIANT v;
585
586     TRACE("\n");
587
588     V_VT(&v) = VT_BSTR;
589     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
590     if(!V_BSTR(&v))
591         return E_OUTOFMEMORY;
592
593     return stack_push(ctx, &v);
594 }
595
596 static HRESULT interp_long(exec_ctx_t *ctx)
597 {
598     const LONG arg = ctx->instr->arg1.lng;
599     VARIANT v;
600
601     TRACE("%d\n", arg);
602
603     V_VT(&v) = VT_I4;
604     V_I4(&v) = arg;
605     return stack_push(ctx, &v);
606 }
607
608 static HRESULT interp_short(exec_ctx_t *ctx)
609 {
610     const LONG arg = ctx->instr->arg1.lng;
611     VARIANT v;
612
613     TRACE("%d\n", arg);
614
615     V_VT(&v) = VT_I2;
616     V_I2(&v) = arg;
617     return stack_push(ctx, &v);
618 }
619
620 static HRESULT interp_double(exec_ctx_t *ctx)
621 {
622     const DOUBLE *arg = ctx->instr->arg1.dbl;
623     VARIANT v;
624
625     TRACE("%lf\n", *arg);
626
627     V_VT(&v) = VT_R8;
628     V_R8(&v) = *arg;
629     return stack_push(ctx, &v);
630 }
631
632 static HRESULT interp_empty(exec_ctx_t *ctx)
633 {
634     VARIANT v;
635
636     TRACE("\n");
637
638     V_VT(&v) = VT_EMPTY;
639     return stack_push(ctx, &v);
640 }
641
642 static HRESULT interp_null(exec_ctx_t *ctx)
643 {
644     VARIANT v;
645
646     TRACE("\n");
647
648     V_VT(&v) = VT_NULL;
649     return stack_push(ctx, &v);
650 }
651
652 static HRESULT interp_nothing(exec_ctx_t *ctx)
653 {
654     VARIANT v;
655
656     TRACE("\n");
657
658     V_VT(&v) = VT_DISPATCH;
659     V_DISPATCH(&v) = NULL;
660     return stack_push(ctx, &v);
661 }
662
663 static HRESULT interp_not(exec_ctx_t *ctx)
664 {
665     variant_val_t val;
666     VARIANT v;
667     HRESULT hres;
668
669     TRACE("\n");
670
671     hres = stack_pop_val(ctx, &val);
672     if(FAILED(hres))
673         return hres;
674
675     hres = VarNot(val.v, &v);
676     release_val(&val);
677     if(FAILED(hres))
678         return hres;
679
680     return stack_push(ctx, &v);
681 }
682
683 static HRESULT interp_and(exec_ctx_t *ctx)
684 {
685     variant_val_t r, l;
686     VARIANT v;
687     HRESULT hres;
688
689     TRACE("\n");
690
691     hres = stack_pop_val(ctx, &r);
692     if(FAILED(hres))
693         return hres;
694
695     hres = stack_pop_val(ctx, &l);
696     if(SUCCEEDED(hres)) {
697         hres = VarAnd(l.v, r.v, &v);
698         release_val(&l);
699     }
700     release_val(&r);
701     if(FAILED(hres))
702         return hres;
703
704     return stack_push(ctx, &v);
705 }
706
707 static HRESULT interp_or(exec_ctx_t *ctx)
708 {
709     variant_val_t r, l;
710     VARIANT v;
711     HRESULT hres;
712
713     TRACE("\n");
714
715     hres = stack_pop_val(ctx, &r);
716     if(FAILED(hres))
717         return hres;
718
719     hres = stack_pop_val(ctx, &l);
720     if(SUCCEEDED(hres)) {
721         hres = VarOr(l.v, r.v, &v);
722         release_val(&l);
723     }
724     release_val(&r);
725     if(FAILED(hres))
726         return hres;
727
728     return stack_push(ctx, &v);
729 }
730
731 static HRESULT interp_xor(exec_ctx_t *ctx)
732 {
733     variant_val_t r, l;
734     VARIANT v;
735     HRESULT hres;
736
737     TRACE("\n");
738
739     hres = stack_pop_val(ctx, &r);
740     if(FAILED(hres))
741         return hres;
742
743     hres = stack_pop_val(ctx, &l);
744     if(SUCCEEDED(hres)) {
745         hres = VarXor(l.v, r.v, &v);
746         release_val(&l);
747     }
748     release_val(&r);
749     if(FAILED(hres))
750         return hres;
751
752     return stack_push(ctx, &v);
753 }
754
755 static HRESULT interp_eqv(exec_ctx_t *ctx)
756 {
757     variant_val_t r, l;
758     VARIANT v;
759     HRESULT hres;
760
761     TRACE("\n");
762
763     hres = stack_pop_val(ctx, &r);
764     if(FAILED(hres))
765         return hres;
766
767     hres = stack_pop_val(ctx, &l);
768     if(SUCCEEDED(hres)) {
769         hres = VarEqv(l.v, r.v, &v);
770         release_val(&l);
771     }
772     release_val(&r);
773     if(FAILED(hres))
774         return hres;
775
776     return stack_push(ctx, &v);
777 }
778
779 static HRESULT interp_imp(exec_ctx_t *ctx)
780 {
781     variant_val_t r, l;
782     VARIANT v;
783     HRESULT hres;
784
785     TRACE("\n");
786
787     hres = stack_pop_val(ctx, &r);
788     if(FAILED(hres))
789         return hres;
790
791     hres = stack_pop_val(ctx, &l);
792     if(SUCCEEDED(hres)) {
793         hres = VarImp(l.v, r.v, &v);
794         release_val(&l);
795     }
796     release_val(&r);
797     if(FAILED(hres))
798         return hres;
799
800     return stack_push(ctx, &v);
801 }
802
803 static HRESULT cmp_oper(exec_ctx_t *ctx)
804 {
805     variant_val_t l, r;
806     HRESULT hres;
807
808     hres = stack_pop_val(ctx, &r);
809     if(FAILED(hres))
810         return hres;
811
812     hres = stack_pop_val(ctx, &l);
813     if(SUCCEEDED(hres)) {
814         if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
815             FIXME("comparing nulls is not implemented\n");
816             hres = E_NOTIMPL;
817         }else {
818             hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
819         }
820     }
821
822     release_val(&r);
823     release_val(&l);
824     return hres;
825 }
826
827 static HRESULT interp_equal(exec_ctx_t *ctx)
828 {
829     VARIANT v;
830     HRESULT hres;
831
832     TRACE("\n");
833
834     hres = cmp_oper(ctx);
835     if(FAILED(hres))
836         return hres;
837
838     V_VT(&v) = VT_BOOL;
839     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
840     return stack_push(ctx, &v);
841 }
842
843 static HRESULT interp_nequal(exec_ctx_t *ctx)
844 {
845     VARIANT v;
846     HRESULT hres;
847
848     TRACE("\n");
849
850     hres = cmp_oper(ctx);
851     if(FAILED(hres))
852         return hres;
853
854     V_VT(&v) = VT_BOOL;
855     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
856     return stack_push(ctx, &v);
857 }
858
859 static HRESULT interp_concat(exec_ctx_t *ctx)
860 {
861     variant_val_t r, l;
862     VARIANT v;
863     HRESULT hres;
864
865     TRACE("\n");
866
867     hres = stack_pop_val(ctx, &r);
868     if(FAILED(hres))
869         return hres;
870
871     hres = stack_pop_val(ctx, &l);
872     if(SUCCEEDED(hres)) {
873         hres = VarCat(l.v, r.v, &v);
874         release_val(&l);
875     }
876     release_val(&r);
877     if(FAILED(hres))
878         return hres;
879
880     return stack_push(ctx, &v);
881 }
882
883 static HRESULT interp_add(exec_ctx_t *ctx)
884 {
885     variant_val_t r, l;
886     VARIANT v;
887     HRESULT hres;
888
889     TRACE("\n");
890
891     hres = stack_pop_val(ctx, &r);
892     if(FAILED(hres))
893         return hres;
894
895     hres = stack_pop_val(ctx, &l);
896     if(SUCCEEDED(hres)) {
897         hres = VarAdd(l.v, r.v, &v);
898         release_val(&l);
899     }
900     release_val(&r);
901     if(FAILED(hres))
902         return hres;
903
904     return stack_push(ctx, &v);
905 }
906
907 static HRESULT interp_sub(exec_ctx_t *ctx)
908 {
909     variant_val_t r, l;
910     VARIANT v;
911     HRESULT hres;
912
913     TRACE("\n");
914
915     hres = stack_pop_val(ctx, &r);
916     if(FAILED(hres))
917         return hres;
918
919     hres = stack_pop_val(ctx, &l);
920     if(SUCCEEDED(hres)) {
921         hres = VarSub(l.v, r.v, &v);
922         release_val(&l);
923     }
924     release_val(&r);
925     if(FAILED(hres))
926         return hres;
927
928     return stack_push(ctx, &v);
929 }
930
931 static HRESULT interp_mod(exec_ctx_t *ctx)
932 {
933     variant_val_t r, l;
934     VARIANT v;
935     HRESULT hres;
936
937     TRACE("\n");
938
939     hres = stack_pop_val(ctx, &r);
940     if(FAILED(hres))
941         return hres;
942
943     hres = stack_pop_val(ctx, &l);
944     if(SUCCEEDED(hres)) {
945         hres = VarMod(l.v, r.v, &v);
946         release_val(&l);
947     }
948     release_val(&r);
949     if(FAILED(hres))
950         return hres;
951
952     return stack_push(ctx, &v);
953 }
954
955 static HRESULT interp_idiv(exec_ctx_t *ctx)
956 {
957     variant_val_t r, l;
958     VARIANT v;
959     HRESULT hres;
960
961     TRACE("\n");
962
963     hres = stack_pop_val(ctx, &r);
964     if(FAILED(hres))
965         return hres;
966
967     hres = stack_pop_val(ctx, &l);
968     if(SUCCEEDED(hres)) {
969         hres = VarIdiv(l.v, r.v, &v);
970         release_val(&l);
971     }
972     release_val(&r);
973     if(FAILED(hres))
974         return hres;
975
976     return stack_push(ctx, &v);
977 }
978
979 static HRESULT interp_div(exec_ctx_t *ctx)
980 {
981     variant_val_t r, l;
982     VARIANT v;
983     HRESULT hres;
984
985     TRACE("\n");
986
987     hres = stack_pop_val(ctx, &r);
988     if(FAILED(hres))
989         return hres;
990
991     hres = stack_pop_val(ctx, &l);
992     if(SUCCEEDED(hres)) {
993         hres = VarDiv(l.v, r.v, &v);
994         release_val(&l);
995     }
996     release_val(&r);
997     if(FAILED(hres))
998         return hres;
999
1000     return stack_push(ctx, &v);
1001 }
1002
1003 static HRESULT interp_mul(exec_ctx_t *ctx)
1004 {
1005     variant_val_t r, l;
1006     VARIANT v;
1007     HRESULT hres;
1008
1009     TRACE("\n");
1010
1011     hres = stack_pop_val(ctx, &r);
1012     if(FAILED(hres))
1013         return hres;
1014
1015     hres = stack_pop_val(ctx, &l);
1016     if(SUCCEEDED(hres)) {
1017         hres = VarMul(l.v, r.v, &v);
1018         release_val(&l);
1019     }
1020     release_val(&r);
1021     if(FAILED(hres))
1022         return hres;
1023
1024     return stack_push(ctx, &v);
1025 }
1026
1027 static HRESULT interp_exp(exec_ctx_t *ctx)
1028 {
1029     variant_val_t r, l;
1030     VARIANT v;
1031     HRESULT hres;
1032
1033     TRACE("\n");
1034
1035     hres = stack_pop_val(ctx, &r);
1036     if(FAILED(hres))
1037         return hres;
1038
1039     hres = stack_pop_val(ctx, &l);
1040     if(SUCCEEDED(hres)) {
1041         hres = VarPow(l.v, r.v, &v);
1042         release_val(&l);
1043     }
1044     release_val(&r);
1045     if(FAILED(hres))
1046         return hres;
1047
1048     return stack_push(ctx, &v);
1049 }
1050
1051 static HRESULT interp_neg(exec_ctx_t *ctx)
1052 {
1053     variant_val_t val;
1054     VARIANT v;
1055     HRESULT hres;
1056
1057     hres = stack_pop_val(ctx, &val);
1058     if(FAILED(hres))
1059         return hres;
1060
1061     hres = VarNeg(val.v, &v);
1062     release_val(&val);
1063     if(FAILED(hres))
1064         return hres;
1065
1066     return stack_push(ctx, &v);
1067 }
1068
1069 static const instr_func_t op_funcs[] = {
1070 #define X(x,n,a,b) interp_ ## x,
1071 OP_LIST
1072 #undef X
1073 };
1074
1075 static const unsigned op_move[] = {
1076 #define X(x,n,a,b) n,
1077 OP_LIST
1078 #undef X
1079 };
1080
1081 static void release_exec(exec_ctx_t *ctx)
1082 {
1083     unsigned i;
1084
1085     VariantClear(&ctx->ret_val);
1086
1087     if(ctx->args) {
1088         for(i=0; i < ctx->func->arg_cnt; i++)
1089             VariantClear(ctx->args+i);
1090     }
1091
1092     if(ctx->vars) {
1093         for(i=0; i < ctx->func->var_cnt; i++)
1094             VariantClear(ctx->vars+i);
1095     }
1096
1097     heap_free(ctx->args);
1098     heap_free(ctx->vars);
1099     heap_free(ctx->stack);
1100 }
1101
1102 HRESULT exec_script(script_ctx_t *ctx, function_t *func, DISPPARAMS *dp, VARIANT *res)
1103 {
1104     exec_ctx_t exec = {func->code_ctx};
1105     vbsop_t op;
1106     HRESULT hres = S_OK;
1107
1108     exec.code = func->code_ctx;
1109
1110     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
1111         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
1112         return E_FAIL;
1113     }
1114
1115     if(func->arg_cnt) {
1116         VARIANT *v;
1117         unsigned i;
1118
1119         exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
1120         if(!exec.args) {
1121             release_exec(&exec);
1122             return E_OUTOFMEMORY;
1123         }
1124
1125         for(i=0; i < func->arg_cnt; i++) {
1126             v = get_arg(dp, i);
1127             if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
1128                 if(func->args[i].by_ref)
1129                     exec.args[i] = *v;
1130                 else
1131                     hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
1132             }else {
1133                 hres = VariantCopy(exec.args+i, v);
1134             }
1135             if(FAILED(hres)) {
1136                 release_exec(&exec);
1137                 return hres;
1138             }
1139         }
1140     }else {
1141         exec.args = NULL;
1142     }
1143
1144     if(func->var_cnt) {
1145         exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
1146         if(!exec.vars) {
1147             release_exec(&exec);
1148             return E_OUTOFMEMORY;
1149         }
1150     }else {
1151         exec.vars = NULL;
1152     }
1153
1154     exec.stack_size = 16;
1155     exec.top = 0;
1156     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
1157     if(!exec.stack) {
1158         release_exec(&exec);
1159         return E_OUTOFMEMORY;
1160     }
1161
1162     exec.instr = exec.code->instrs + func->code_off;
1163     exec.script = ctx;
1164     exec.func = func;
1165
1166     while(exec.instr) {
1167         op = exec.instr->op;
1168         hres = op_funcs[op](&exec);
1169         if(FAILED(hres)) {
1170             FIXME("Failed %08x\n", hres);
1171             stack_popn(&exec, exec.top);
1172             break;
1173         }
1174
1175         exec.instr += op_move[op];
1176     }
1177
1178     assert(!exec.top);
1179     if(func->type != FUNC_FUNCTION)
1180         assert(V_VT(&exec.ret_val) == VT_EMPTY);
1181
1182     if(SUCCEEDED(hres) && res) {
1183         *res = exec.ret_val;
1184         V_VT(&exec.ret_val) = VT_EMPTY;
1185     }
1186
1187     release_exec(&exec);
1188
1189     return hres;
1190 }