vbscript: Added interp_nothing implementation and tests.
[wine] / dlls / vbscript / interp.c
1 /*
2  * Copyright 2011 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <assert.h>
20
21 #include "vbscript.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
26
27
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 assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
331 {
332     ref_t ref;
333     HRESULT hres;
334
335     hres = lookup_identifier(ctx, name, VBDISP_LET, &ref);
336     if(FAILED(hres))
337         return hres;
338
339     switch(ref.type) {
340     case REF_VAR: {
341         VARIANT *v = ref.u.v;
342
343         if(V_VT(v) == (VT_VARIANT|VT_BYREF))
344             v = V_VARIANTREF(v);
345
346         if(own_val) {
347             VariantClear(v);
348             *v = *val;
349             hres = S_OK;
350         }else {
351             hres = VariantCopy(v, val);
352         }
353         break;
354     }
355     case REF_DISP:
356         hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, val);
357         if(own_val)
358             VariantClear(val);
359         break;
360     case REF_FUNC:
361         FIXME("functions not implemented\n");
362         return E_NOTIMPL;
363     case REF_NONE:
364         FIXME("%s not found\n", debugstr_w(name));
365         if(own_val)
366             VariantClear(val);
367         return DISP_E_UNKNOWNNAME;
368     }
369
370     return hres;
371 }
372
373 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
374 {
375     const BSTR arg = ctx->instr->arg1.bstr;
376     variant_val_t v;
377     HRESULT hres;
378
379     TRACE("%s\n", debugstr_w(arg));
380
381     hres = stack_pop_val(ctx, &v);
382     if(FAILED(hres))
383         return hres;
384
385     return assign_ident(ctx, arg, v.v, v.owned);
386 }
387
388 static HRESULT interp_set_ident(exec_ctx_t *ctx)
389 {
390     const BSTR arg = ctx->instr->arg1.bstr;
391     IDispatch *disp;
392     VARIANT v;
393     HRESULT hres;
394
395     TRACE("%s\n", debugstr_w(arg));
396
397     hres = stack_pop_disp(ctx, &disp);
398     if(FAILED(hres))
399         return hres;
400
401     V_VT(&v) = VT_DISPATCH;
402     V_DISPATCH(&v) = disp;
403     return assign_ident(ctx, ctx->instr->arg1.bstr, &v, TRUE);
404 }
405
406 static HRESULT interp_assign_member(exec_ctx_t *ctx)
407 {
408     BSTR identifier = ctx->instr->arg1.bstr;
409     variant_val_t val;
410     IDispatch *obj;
411     DISPID id;
412     HRESULT hres;
413
414     TRACE("%s\n", debugstr_w(identifier));
415
416     hres = stack_pop_disp(ctx, &obj);
417     if(FAILED(hres))
418         return hres;
419
420     if(!obj) {
421         FIXME("NULL obj\n");
422         return E_FAIL;
423     }
424
425     hres = stack_pop_val(ctx, &val);
426     if(FAILED(hres)) {
427         IDispatch_Release(obj);
428         return hres;
429     }
430
431     hres = disp_get_id(obj, identifier, &id);
432     if(SUCCEEDED(hres))
433         hres = disp_propput(ctx->script, obj, id, val.v);
434
435     release_val(&val);
436     IDispatch_Release(obj);
437     return hres;
438 }
439
440 static HRESULT interp_set_member(exec_ctx_t *ctx)
441 {
442     BSTR identifier = ctx->instr->arg1.bstr;
443     FIXME("%s\n", debugstr_w(identifier));
444     return E_NOTIMPL;
445 }
446
447 static HRESULT interp_new(exec_ctx_t *ctx)
448 {
449     const WCHAR *arg = ctx->instr->arg1.bstr;
450     class_desc_t *class_desc;
451     vbdisp_t *obj;
452     VARIANT v;
453     HRESULT hres;
454
455     TRACE("%s\n", debugstr_w(arg));
456
457     for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
458         if(!strcmpiW(class_desc->name, arg))
459             break;
460     }
461     if(!class_desc) {
462         FIXME("Class %s not found\n", debugstr_w(arg));
463         return E_FAIL;
464     }
465
466     hres = create_vbdisp(class_desc, &obj);
467     if(FAILED(hres))
468         return hres;
469
470     V_VT(&v) = VT_DISPATCH;
471     V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
472     return stack_push(ctx, &v);
473 }
474
475 static HRESULT interp_jmp(exec_ctx_t *ctx)
476 {
477     const unsigned arg = ctx->instr->arg1.uint;
478
479     TRACE("%u\n", arg);
480
481     instr_jmp(ctx, arg);
482     return S_OK;
483 }
484
485 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
486 {
487     const unsigned arg = ctx->instr->arg1.uint;
488     variant_val_t val;
489     HRESULT hres;
490
491     TRACE("%u\n", arg);
492
493     hres = stack_pop_val(ctx, &val);
494     if(FAILED(hres))
495         return hres;
496
497     if(V_VT(val.v) != VT_BOOL) {
498         FIXME("unsupported for %s\n", debugstr_variant(val.v));
499         release_val(&val);
500         return E_NOTIMPL;
501     }
502
503     if(V_BOOL(val.v))
504         ctx->instr++;
505     else
506         instr_jmp(ctx, ctx->instr->arg1.uint);
507     return S_OK;
508 }
509
510 static HRESULT interp_ret(exec_ctx_t *ctx)
511 {
512     TRACE("\n");
513
514     ctx->instr = NULL;
515     return S_OK;
516 }
517
518 static HRESULT interp_bool(exec_ctx_t *ctx)
519 {
520     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
521     VARIANT v;
522
523     TRACE("%s\n", arg ? "true" : "false");
524
525     V_VT(&v) = VT_BOOL;
526     V_BOOL(&v) = arg;
527     return stack_push(ctx, &v);
528 }
529
530 static HRESULT interp_string(exec_ctx_t *ctx)
531 {
532     VARIANT v;
533
534     TRACE("\n");
535
536     V_VT(&v) = VT_BSTR;
537     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
538     if(!V_BSTR(&v))
539         return E_OUTOFMEMORY;
540
541     return stack_push(ctx, &v);
542 }
543
544 static HRESULT interp_long(exec_ctx_t *ctx)
545 {
546     const LONG arg = ctx->instr->arg1.lng;
547     VARIANT v;
548
549     TRACE("%d\n", arg);
550
551     V_VT(&v) = VT_I4;
552     V_I4(&v) = arg;
553     return stack_push(ctx, &v);
554 }
555
556 static HRESULT interp_short(exec_ctx_t *ctx)
557 {
558     const LONG arg = ctx->instr->arg1.lng;
559     VARIANT v;
560
561     TRACE("%d\n", arg);
562
563     V_VT(&v) = VT_I2;
564     V_I2(&v) = arg;
565     return stack_push(ctx, &v);
566 }
567
568 static HRESULT interp_double(exec_ctx_t *ctx)
569 {
570     const DOUBLE *arg = ctx->instr->arg1.dbl;
571     VARIANT v;
572
573     TRACE("%lf\n", *arg);
574
575     V_VT(&v) = VT_R8;
576     V_R8(&v) = *arg;
577     return stack_push(ctx, &v);
578 }
579
580 static HRESULT interp_empty(exec_ctx_t *ctx)
581 {
582     VARIANT v;
583
584     TRACE("\n");
585
586     V_VT(&v) = VT_EMPTY;
587     return stack_push(ctx, &v);
588 }
589
590 static HRESULT interp_null(exec_ctx_t *ctx)
591 {
592     VARIANT v;
593
594     TRACE("\n");
595
596     V_VT(&v) = VT_NULL;
597     return stack_push(ctx, &v);
598 }
599
600 static HRESULT interp_nothing(exec_ctx_t *ctx)
601 {
602     VARIANT v;
603
604     TRACE("\n");
605
606     V_VT(&v) = VT_DISPATCH;
607     V_DISPATCH(&v) = NULL;
608     return stack_push(ctx, &v);
609 }
610
611 static HRESULT interp_not(exec_ctx_t *ctx)
612 {
613     variant_val_t val;
614     VARIANT v;
615     HRESULT hres;
616
617     TRACE("\n");
618
619     hres = stack_pop_val(ctx, &val);
620     if(FAILED(hres))
621         return hres;
622
623     hres = VarNot(val.v, &v);
624     release_val(&val);
625     if(FAILED(hres))
626         return hres;
627
628     return stack_push(ctx, &v);
629 }
630
631 static HRESULT interp_and(exec_ctx_t *ctx)
632 {
633     variant_val_t r, l;
634     VARIANT v;
635     HRESULT hres;
636
637     TRACE("\n");
638
639     hres = stack_pop_val(ctx, &r);
640     if(FAILED(hres))
641         return hres;
642
643     hres = stack_pop_val(ctx, &l);
644     if(SUCCEEDED(hres)) {
645         hres = VarAnd(l.v, r.v, &v);
646         release_val(&l);
647     }
648     release_val(&r);
649     if(FAILED(hres))
650         return hres;
651
652     return stack_push(ctx, &v);
653 }
654
655 static HRESULT interp_or(exec_ctx_t *ctx)
656 {
657     variant_val_t r, l;
658     VARIANT v;
659     HRESULT hres;
660
661     TRACE("\n");
662
663     hres = stack_pop_val(ctx, &r);
664     if(FAILED(hres))
665         return hres;
666
667     hres = stack_pop_val(ctx, &l);
668     if(SUCCEEDED(hres)) {
669         hres = VarOr(l.v, r.v, &v);
670         release_val(&l);
671     }
672     release_val(&r);
673     if(FAILED(hres))
674         return hres;
675
676     return stack_push(ctx, &v);
677 }
678
679 static HRESULT interp_xor(exec_ctx_t *ctx)
680 {
681     variant_val_t r, l;
682     VARIANT v;
683     HRESULT hres;
684
685     TRACE("\n");
686
687     hres = stack_pop_val(ctx, &r);
688     if(FAILED(hres))
689         return hres;
690
691     hres = stack_pop_val(ctx, &l);
692     if(SUCCEEDED(hres)) {
693         hres = VarXor(l.v, r.v, &v);
694         release_val(&l);
695     }
696     release_val(&r);
697     if(FAILED(hres))
698         return hres;
699
700     return stack_push(ctx, &v);
701 }
702
703 static HRESULT interp_eqv(exec_ctx_t *ctx)
704 {
705     variant_val_t r, l;
706     VARIANT v;
707     HRESULT hres;
708
709     TRACE("\n");
710
711     hres = stack_pop_val(ctx, &r);
712     if(FAILED(hres))
713         return hres;
714
715     hres = stack_pop_val(ctx, &l);
716     if(SUCCEEDED(hres)) {
717         hres = VarEqv(l.v, r.v, &v);
718         release_val(&l);
719     }
720     release_val(&r);
721     if(FAILED(hres))
722         return hres;
723
724     return stack_push(ctx, &v);
725 }
726
727 static HRESULT interp_imp(exec_ctx_t *ctx)
728 {
729     variant_val_t r, l;
730     VARIANT v;
731     HRESULT hres;
732
733     TRACE("\n");
734
735     hres = stack_pop_val(ctx, &r);
736     if(FAILED(hres))
737         return hres;
738
739     hres = stack_pop_val(ctx, &l);
740     if(SUCCEEDED(hres)) {
741         hres = VarImp(l.v, r.v, &v);
742         release_val(&l);
743     }
744     release_val(&r);
745     if(FAILED(hres))
746         return hres;
747
748     return stack_push(ctx, &v);
749 }
750
751 static HRESULT cmp_oper(exec_ctx_t *ctx)
752 {
753     variant_val_t l, r;
754     HRESULT hres;
755
756     hres = stack_pop_val(ctx, &r);
757     if(FAILED(hres))
758         return hres;
759
760     hres = stack_pop_val(ctx, &l);
761     if(SUCCEEDED(hres)) {
762         if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
763             FIXME("comparing nulls is not implemented\n");
764             hres = E_NOTIMPL;
765         }else {
766             hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
767         }
768     }
769
770     release_val(&r);
771     release_val(&l);
772     return hres;
773 }
774
775 static HRESULT interp_equal(exec_ctx_t *ctx)
776 {
777     VARIANT v;
778     HRESULT hres;
779
780     TRACE("\n");
781
782     hres = cmp_oper(ctx);
783     if(FAILED(hres))
784         return hres;
785
786     V_VT(&v) = VT_BOOL;
787     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
788     return stack_push(ctx, &v);
789 }
790
791 static HRESULT interp_nequal(exec_ctx_t *ctx)
792 {
793     VARIANT v;
794     HRESULT hres;
795
796     TRACE("\n");
797
798     hres = cmp_oper(ctx);
799     if(FAILED(hres))
800         return hres;
801
802     V_VT(&v) = VT_BOOL;
803     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
804     return stack_push(ctx, &v);
805 }
806
807 static HRESULT interp_concat(exec_ctx_t *ctx)
808 {
809     variant_val_t r, l;
810     VARIANT v;
811     HRESULT hres;
812
813     TRACE("\n");
814
815     hres = stack_pop_val(ctx, &r);
816     if(FAILED(hres))
817         return hres;
818
819     hres = stack_pop_val(ctx, &l);
820     if(SUCCEEDED(hres)) {
821         hres = VarCat(l.v, r.v, &v);
822         release_val(&l);
823     }
824     release_val(&r);
825     if(FAILED(hres))
826         return hres;
827
828     return stack_push(ctx, &v);
829 }
830
831 static HRESULT interp_add(exec_ctx_t *ctx)
832 {
833     variant_val_t r, l;
834     VARIANT v;
835     HRESULT hres;
836
837     TRACE("\n");
838
839     hres = stack_pop_val(ctx, &r);
840     if(FAILED(hres))
841         return hres;
842
843     hres = stack_pop_val(ctx, &l);
844     if(SUCCEEDED(hres)) {
845         hres = VarAdd(l.v, r.v, &v);
846         release_val(&l);
847     }
848     release_val(&r);
849     if(FAILED(hres))
850         return hres;
851
852     return stack_push(ctx, &v);
853 }
854
855 static HRESULT interp_sub(exec_ctx_t *ctx)
856 {
857     variant_val_t r, l;
858     VARIANT v;
859     HRESULT hres;
860
861     TRACE("\n");
862
863     hres = stack_pop_val(ctx, &r);
864     if(FAILED(hres))
865         return hres;
866
867     hres = stack_pop_val(ctx, &l);
868     if(SUCCEEDED(hres)) {
869         hres = VarSub(l.v, r.v, &v);
870         release_val(&l);
871     }
872     release_val(&r);
873     if(FAILED(hres))
874         return hres;
875
876     return stack_push(ctx, &v);
877 }
878
879 static HRESULT interp_mod(exec_ctx_t *ctx)
880 {
881     variant_val_t r, l;
882     VARIANT v;
883     HRESULT hres;
884
885     TRACE("\n");
886
887     hres = stack_pop_val(ctx, &r);
888     if(FAILED(hres))
889         return hres;
890
891     hres = stack_pop_val(ctx, &l);
892     if(SUCCEEDED(hres)) {
893         hres = VarMod(l.v, r.v, &v);
894         release_val(&l);
895     }
896     release_val(&r);
897     if(FAILED(hres))
898         return hres;
899
900     return stack_push(ctx, &v);
901 }
902
903 static HRESULT interp_idiv(exec_ctx_t *ctx)
904 {
905     variant_val_t r, l;
906     VARIANT v;
907     HRESULT hres;
908
909     TRACE("\n");
910
911     hres = stack_pop_val(ctx, &r);
912     if(FAILED(hres))
913         return hres;
914
915     hres = stack_pop_val(ctx, &l);
916     if(SUCCEEDED(hres)) {
917         hres = VarIdiv(l.v, r.v, &v);
918         release_val(&l);
919     }
920     release_val(&r);
921     if(FAILED(hres))
922         return hres;
923
924     return stack_push(ctx, &v);
925 }
926
927 static HRESULT interp_div(exec_ctx_t *ctx)
928 {
929     variant_val_t r, l;
930     VARIANT v;
931     HRESULT hres;
932
933     TRACE("\n");
934
935     hres = stack_pop_val(ctx, &r);
936     if(FAILED(hres))
937         return hres;
938
939     hres = stack_pop_val(ctx, &l);
940     if(SUCCEEDED(hres)) {
941         hres = VarDiv(l.v, r.v, &v);
942         release_val(&l);
943     }
944     release_val(&r);
945     if(FAILED(hres))
946         return hres;
947
948     return stack_push(ctx, &v);
949 }
950
951 static HRESULT interp_mul(exec_ctx_t *ctx)
952 {
953     variant_val_t r, l;
954     VARIANT v;
955     HRESULT hres;
956
957     TRACE("\n");
958
959     hres = stack_pop_val(ctx, &r);
960     if(FAILED(hres))
961         return hres;
962
963     hres = stack_pop_val(ctx, &l);
964     if(SUCCEEDED(hres)) {
965         hres = VarMul(l.v, r.v, &v);
966         release_val(&l);
967     }
968     release_val(&r);
969     if(FAILED(hres))
970         return hres;
971
972     return stack_push(ctx, &v);
973 }
974
975 static HRESULT interp_exp(exec_ctx_t *ctx)
976 {
977     variant_val_t r, l;
978     VARIANT v;
979     HRESULT hres;
980
981     TRACE("\n");
982
983     hres = stack_pop_val(ctx, &r);
984     if(FAILED(hres))
985         return hres;
986
987     hres = stack_pop_val(ctx, &l);
988     if(SUCCEEDED(hres)) {
989         hres = VarPow(l.v, r.v, &v);
990         release_val(&l);
991     }
992     release_val(&r);
993     if(FAILED(hres))
994         return hres;
995
996     return stack_push(ctx, &v);
997 }
998
999 static HRESULT interp_neg(exec_ctx_t *ctx)
1000 {
1001     variant_val_t val;
1002     VARIANT v;
1003     HRESULT hres;
1004
1005     hres = stack_pop_val(ctx, &val);
1006     if(FAILED(hres))
1007         return hres;
1008
1009     hres = VarNeg(val.v, &v);
1010     release_val(&val);
1011     if(FAILED(hres))
1012         return hres;
1013
1014     return stack_push(ctx, &v);
1015 }
1016
1017 static const instr_func_t op_funcs[] = {
1018 #define X(x,n,a,b) interp_ ## x,
1019 OP_LIST
1020 #undef X
1021 };
1022
1023 static const unsigned op_move[] = {
1024 #define X(x,n,a,b) n,
1025 OP_LIST
1026 #undef X
1027 };
1028
1029 static void release_exec(exec_ctx_t *ctx)
1030 {
1031     unsigned i;
1032
1033     VariantClear(&ctx->ret_val);
1034
1035     if(ctx->args) {
1036         for(i=0; i < ctx->func->arg_cnt; i++)
1037             VariantClear(ctx->args+i);
1038     }
1039
1040     if(ctx->vars) {
1041         for(i=0; i < ctx->func->var_cnt; i++)
1042             VariantClear(ctx->vars+i);
1043     }
1044
1045     heap_free(ctx->args);
1046     heap_free(ctx->vars);
1047     heap_free(ctx->stack);
1048 }
1049
1050 HRESULT exec_script(script_ctx_t *ctx, function_t *func, DISPPARAMS *dp, VARIANT *res)
1051 {
1052     exec_ctx_t exec = {func->code_ctx};
1053     vbsop_t op;
1054     HRESULT hres = S_OK;
1055
1056     exec.code = func->code_ctx;
1057
1058     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
1059         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
1060         return E_FAIL;
1061     }
1062
1063     if(func->arg_cnt) {
1064         VARIANT *v;
1065         unsigned i;
1066
1067         exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
1068         if(!exec.args) {
1069             release_exec(&exec);
1070             return E_OUTOFMEMORY;
1071         }
1072
1073         for(i=0; i < func->arg_cnt; i++) {
1074             v = get_arg(dp, i);
1075             if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
1076                 if(func->args[i].by_ref)
1077                     exec.args[i] = *v;
1078                 else
1079                     hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
1080             }else {
1081                 hres = VariantCopy(exec.args+i, v);
1082             }
1083             if(FAILED(hres)) {
1084                 release_exec(&exec);
1085                 return hres;
1086             }
1087         }
1088     }else {
1089         exec.args = NULL;
1090     }
1091
1092     if(func->var_cnt) {
1093         exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
1094         if(!exec.vars) {
1095             release_exec(&exec);
1096             return E_OUTOFMEMORY;
1097         }
1098     }else {
1099         exec.vars = NULL;
1100     }
1101
1102     exec.stack_size = 16;
1103     exec.top = 0;
1104     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
1105     if(!exec.stack) {
1106         release_exec(&exec);
1107         return E_OUTOFMEMORY;
1108     }
1109
1110     exec.instr = exec.code->instrs + func->code_off;
1111     exec.script = ctx;
1112     exec.func = func;
1113
1114     while(exec.instr) {
1115         op = exec.instr->op;
1116         hres = op_funcs[op](&exec);
1117         if(FAILED(hres)) {
1118             FIXME("Failed %08x\n", hres);
1119             stack_popn(&exec, exec.top);
1120             break;
1121         }
1122
1123         exec.instr += op_move[op];
1124     }
1125
1126     assert(!exec.top);
1127     if(func->type != FUNC_FUNCTION)
1128         assert(V_VT(&exec.ret_val) == VT_EMPTY);
1129
1130     if(SUCCEEDED(hres) && res) {
1131         *res = exec.ret_val;
1132         V_VT(&exec.ret_val) = VT_EMPTY;
1133     }
1134
1135     release_exec(&exec);
1136
1137     return hres;
1138 }