vbscript: Added interp_eqv 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 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_assign_member(exec_ctx_t *ctx)
389 {
390     BSTR identifier = ctx->instr->arg1.bstr;
391     variant_val_t val;
392     IDispatch *obj;
393     DISPID id;
394     HRESULT hres;
395
396     TRACE("%s\n", debugstr_w(identifier));
397
398     hres = stack_pop_disp(ctx, &obj);
399     if(FAILED(hres))
400         return hres;
401
402     if(!obj) {
403         FIXME("NULL obj\n");
404         return E_FAIL;
405     }
406
407     hres = stack_pop_val(ctx, &val);
408     if(FAILED(hres)) {
409         IDispatch_Release(obj);
410         return hres;
411     }
412
413     hres = disp_get_id(obj, identifier, &id);
414     if(SUCCEEDED(hres))
415         hres = disp_propput(ctx->script, obj, id, val.v);
416
417     release_val(&val);
418     IDispatch_Release(obj);
419     return hres;
420 }
421
422 static HRESULT interp_jmp(exec_ctx_t *ctx)
423 {
424     const unsigned arg = ctx->instr->arg1.uint;
425
426     TRACE("%u\n", arg);
427
428     instr_jmp(ctx, arg);
429     return S_OK;
430 }
431
432 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
433 {
434     const unsigned arg = ctx->instr->arg1.uint;
435     variant_val_t val;
436     HRESULT hres;
437
438     TRACE("%u\n", arg);
439
440     hres = stack_pop_val(ctx, &val);
441     if(FAILED(hres))
442         return hres;
443
444     if(V_VT(val.v) != VT_BOOL) {
445         FIXME("unsupported for %s\n", debugstr_variant(val.v));
446         release_val(&val);
447         return E_NOTIMPL;
448     }
449
450     if(V_BOOL(val.v))
451         ctx->instr++;
452     else
453         instr_jmp(ctx, ctx->instr->arg1.uint);
454     return S_OK;
455 }
456
457 static HRESULT interp_ret(exec_ctx_t *ctx)
458 {
459     TRACE("\n");
460
461     ctx->instr = NULL;
462     return S_OK;
463 }
464
465 static HRESULT interp_bool(exec_ctx_t *ctx)
466 {
467     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
468     VARIANT v;
469
470     TRACE("%s\n", arg ? "true" : "false");
471
472     V_VT(&v) = VT_BOOL;
473     V_BOOL(&v) = arg;
474     return stack_push(ctx, &v);
475 }
476
477 static HRESULT interp_string(exec_ctx_t *ctx)
478 {
479     VARIANT v;
480
481     TRACE("\n");
482
483     V_VT(&v) = VT_BSTR;
484     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
485     if(!V_BSTR(&v))
486         return E_OUTOFMEMORY;
487
488     return stack_push(ctx, &v);
489 }
490
491 static HRESULT interp_long(exec_ctx_t *ctx)
492 {
493     const LONG arg = ctx->instr->arg1.lng;
494     VARIANT v;
495
496     TRACE("%d\n", arg);
497
498     V_VT(&v) = VT_I4;
499     V_I4(&v) = arg;
500     return stack_push(ctx, &v);
501 }
502
503 static HRESULT interp_short(exec_ctx_t *ctx)
504 {
505     const LONG arg = ctx->instr->arg1.lng;
506     VARIANT v;
507
508     TRACE("%d\n", arg);
509
510     V_VT(&v) = VT_I2;
511     V_I2(&v) = arg;
512     return stack_push(ctx, &v);
513 }
514
515 static HRESULT interp_double(exec_ctx_t *ctx)
516 {
517     const DOUBLE *arg = ctx->instr->arg1.dbl;
518     VARIANT v;
519
520     TRACE("%lf\n", *arg);
521
522     V_VT(&v) = VT_R8;
523     V_R8(&v) = *arg;
524     return stack_push(ctx, &v);
525 }
526
527 static HRESULT interp_empty(exec_ctx_t *ctx)
528 {
529     VARIANT v;
530
531     TRACE("\n");
532
533     V_VT(&v) = VT_EMPTY;
534     return stack_push(ctx, &v);
535 }
536
537 static HRESULT interp_null(exec_ctx_t *ctx)
538 {
539     VARIANT v;
540
541     TRACE("\n");
542
543     V_VT(&v) = VT_NULL;
544     return stack_push(ctx, &v);
545 }
546
547 static HRESULT interp_not(exec_ctx_t *ctx)
548 {
549     variant_val_t val;
550     VARIANT v;
551     HRESULT hres;
552
553     TRACE("\n");
554
555     hres = stack_pop_val(ctx, &val);
556     if(FAILED(hres))
557         return hres;
558
559     hres = VarNot(val.v, &v);
560     release_val(&val);
561     if(FAILED(hres))
562         return hres;
563
564     return stack_push(ctx, &v);
565 }
566
567 static HRESULT interp_and(exec_ctx_t *ctx)
568 {
569     variant_val_t r, l;
570     VARIANT v;
571     HRESULT hres;
572
573     TRACE("\n");
574
575     hres = stack_pop_val(ctx, &r);
576     if(FAILED(hres))
577         return hres;
578
579     hres = stack_pop_val(ctx, &l);
580     if(SUCCEEDED(hres)) {
581         hres = VarAnd(l.v, r.v, &v);
582         release_val(&l);
583     }
584     release_val(&r);
585     if(FAILED(hres))
586         return hres;
587
588     return stack_push(ctx, &v);
589 }
590
591 static HRESULT interp_or(exec_ctx_t *ctx)
592 {
593     variant_val_t r, l;
594     VARIANT v;
595     HRESULT hres;
596
597     TRACE("\n");
598
599     hres = stack_pop_val(ctx, &r);
600     if(FAILED(hres))
601         return hres;
602
603     hres = stack_pop_val(ctx, &l);
604     if(SUCCEEDED(hres)) {
605         hres = VarOr(l.v, r.v, &v);
606         release_val(&l);
607     }
608     release_val(&r);
609     if(FAILED(hres))
610         return hres;
611
612     return stack_push(ctx, &v);
613 }
614
615 static HRESULT interp_xor(exec_ctx_t *ctx)
616 {
617     variant_val_t r, l;
618     VARIANT v;
619     HRESULT hres;
620
621     TRACE("\n");
622
623     hres = stack_pop_val(ctx, &r);
624     if(FAILED(hres))
625         return hres;
626
627     hres = stack_pop_val(ctx, &l);
628     if(SUCCEEDED(hres)) {
629         hres = VarXor(l.v, r.v, &v);
630         release_val(&l);
631     }
632     release_val(&r);
633     if(FAILED(hres))
634         return hres;
635
636     return stack_push(ctx, &v);
637 }
638
639 static HRESULT interp_eqv(exec_ctx_t *ctx)
640 {
641     variant_val_t r, l;
642     VARIANT v;
643     HRESULT hres;
644
645     TRACE("\n");
646
647     hres = stack_pop_val(ctx, &r);
648     if(FAILED(hres))
649         return hres;
650
651     hres = stack_pop_val(ctx, &l);
652     if(SUCCEEDED(hres)) {
653         hres = VarEqv(l.v, r.v, &v);
654         release_val(&l);
655     }
656     release_val(&r);
657     if(FAILED(hres))
658         return hres;
659
660     return stack_push(ctx, &v);
661 }
662
663 static HRESULT interp_imp(exec_ctx_t *ctx)
664 {
665     FIXME("\n");
666     return E_NOTIMPL;
667 }
668
669 static HRESULT cmp_oper(exec_ctx_t *ctx)
670 {
671     variant_val_t l, r;
672     HRESULT hres;
673
674     hres = stack_pop_val(ctx, &r);
675     if(FAILED(hres))
676         return hres;
677
678     hres = stack_pop_val(ctx, &l);
679     if(SUCCEEDED(hres)) {
680         if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
681             FIXME("comparing nulls is not implemented\n");
682             hres = E_NOTIMPL;
683         }else {
684             hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
685         }
686     }
687
688     release_val(&r);
689     release_val(&l);
690     return hres;
691 }
692
693 static HRESULT interp_equal(exec_ctx_t *ctx)
694 {
695     VARIANT v;
696     HRESULT hres;
697
698     TRACE("\n");
699
700     hres = cmp_oper(ctx);
701     if(FAILED(hres))
702         return hres;
703
704     V_VT(&v) = VT_BOOL;
705     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
706     return stack_push(ctx, &v);
707 }
708
709 static HRESULT interp_nequal(exec_ctx_t *ctx)
710 {
711     VARIANT v;
712     HRESULT hres;
713
714     TRACE("\n");
715
716     hres = cmp_oper(ctx);
717     if(FAILED(hres))
718         return hres;
719
720     V_VT(&v) = VT_BOOL;
721     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
722     return stack_push(ctx, &v);
723 }
724
725 static HRESULT interp_concat(exec_ctx_t *ctx)
726 {
727     variant_val_t r, l;
728     VARIANT v;
729     HRESULT hres;
730
731     TRACE("\n");
732
733     hres = stack_pop_val(ctx, &r);
734     if(FAILED(hres))
735         return hres;
736
737     hres = stack_pop_val(ctx, &l);
738     if(SUCCEEDED(hres)) {
739         hres = VarCat(l.v, r.v, &v);
740         release_val(&l);
741     }
742     release_val(&r);
743     if(FAILED(hres))
744         return hres;
745
746     return stack_push(ctx, &v);
747 }
748
749 static HRESULT interp_add(exec_ctx_t *ctx)
750 {
751     variant_val_t r, l;
752     VARIANT v;
753     HRESULT hres;
754
755     TRACE("\n");
756
757     hres = stack_pop_val(ctx, &r);
758     if(FAILED(hres))
759         return hres;
760
761     hres = stack_pop_val(ctx, &l);
762     if(SUCCEEDED(hres)) {
763         hres = VarAdd(l.v, r.v, &v);
764         release_val(&l);
765     }
766     release_val(&r);
767     if(FAILED(hres))
768         return hres;
769
770     return stack_push(ctx, &v);
771 }
772
773 static HRESULT interp_sub(exec_ctx_t *ctx)
774 {
775     variant_val_t r, l;
776     VARIANT v;
777     HRESULT hres;
778
779     TRACE("\n");
780
781     hres = stack_pop_val(ctx, &r);
782     if(FAILED(hres))
783         return hres;
784
785     hres = stack_pop_val(ctx, &l);
786     if(SUCCEEDED(hres)) {
787         hres = VarSub(l.v, r.v, &v);
788         release_val(&l);
789     }
790     release_val(&r);
791     if(FAILED(hres))
792         return hres;
793
794     return stack_push(ctx, &v);
795 }
796
797 static HRESULT interp_mod(exec_ctx_t *ctx)
798 {
799     variant_val_t r, l;
800     VARIANT v;
801     HRESULT hres;
802
803     TRACE("\n");
804
805     hres = stack_pop_val(ctx, &r);
806     if(FAILED(hres))
807         return hres;
808
809     hres = stack_pop_val(ctx, &l);
810     if(SUCCEEDED(hres)) {
811         hres = VarMod(l.v, r.v, &v);
812         release_val(&l);
813     }
814     release_val(&r);
815     if(FAILED(hres))
816         return hres;
817
818     return stack_push(ctx, &v);
819 }
820
821 static HRESULT interp_idiv(exec_ctx_t *ctx)
822 {
823     variant_val_t r, l;
824     VARIANT v;
825     HRESULT hres;
826
827     TRACE("\n");
828
829     hres = stack_pop_val(ctx, &r);
830     if(FAILED(hres))
831         return hres;
832
833     hres = stack_pop_val(ctx, &l);
834     if(SUCCEEDED(hres)) {
835         hres = VarIdiv(l.v, r.v, &v);
836         release_val(&l);
837     }
838     release_val(&r);
839     if(FAILED(hres))
840         return hres;
841
842     return stack_push(ctx, &v);
843 }
844
845 static HRESULT interp_div(exec_ctx_t *ctx)
846 {
847     variant_val_t r, l;
848     VARIANT v;
849     HRESULT hres;
850
851     TRACE("\n");
852
853     hres = stack_pop_val(ctx, &r);
854     if(FAILED(hres))
855         return hres;
856
857     hres = stack_pop_val(ctx, &l);
858     if(SUCCEEDED(hres)) {
859         hres = VarDiv(l.v, r.v, &v);
860         release_val(&l);
861     }
862     release_val(&r);
863     if(FAILED(hres))
864         return hres;
865
866     return stack_push(ctx, &v);
867 }
868
869 static HRESULT interp_mul(exec_ctx_t *ctx)
870 {
871     variant_val_t r, l;
872     VARIANT v;
873     HRESULT hres;
874
875     TRACE("\n");
876
877     hres = stack_pop_val(ctx, &r);
878     if(FAILED(hres))
879         return hres;
880
881     hres = stack_pop_val(ctx, &l);
882     if(SUCCEEDED(hres)) {
883         hres = VarMul(l.v, r.v, &v);
884         release_val(&l);
885     }
886     release_val(&r);
887     if(FAILED(hres))
888         return hres;
889
890     return stack_push(ctx, &v);
891 }
892
893 static HRESULT interp_exp(exec_ctx_t *ctx)
894 {
895     variant_val_t r, l;
896     VARIANT v;
897     HRESULT hres;
898
899     TRACE("\n");
900
901     hres = stack_pop_val(ctx, &r);
902     if(FAILED(hres))
903         return hres;
904
905     hres = stack_pop_val(ctx, &l);
906     if(SUCCEEDED(hres)) {
907         hres = VarPow(l.v, r.v, &v);
908         release_val(&l);
909     }
910     release_val(&r);
911     if(FAILED(hres))
912         return hres;
913
914     return stack_push(ctx, &v);
915 }
916
917 static HRESULT interp_neg(exec_ctx_t *ctx)
918 {
919     variant_val_t val;
920     VARIANT v;
921     HRESULT hres;
922
923     hres = stack_pop_val(ctx, &val);
924     if(FAILED(hres))
925         return hres;
926
927     hres = VarNeg(val.v, &v);
928     release_val(&val);
929     if(FAILED(hres))
930         return hres;
931
932     return stack_push(ctx, &v);
933 }
934
935 static const instr_func_t op_funcs[] = {
936 #define X(x,n,a,b) interp_ ## x,
937 OP_LIST
938 #undef X
939 };
940
941 static const unsigned op_move[] = {
942 #define X(x,n,a,b) n,
943 OP_LIST
944 #undef X
945 };
946
947 static void release_exec(exec_ctx_t *ctx)
948 {
949     unsigned i;
950
951     VariantClear(&ctx->ret_val);
952
953     if(ctx->args) {
954         for(i=0; i < ctx->func->arg_cnt; i++)
955             VariantClear(ctx->args+i);
956     }
957
958     if(ctx->vars) {
959         for(i=0; i < ctx->func->var_cnt; i++)
960             VariantClear(ctx->vars+i);
961     }
962
963     heap_free(ctx->args);
964     heap_free(ctx->vars);
965     heap_free(ctx->stack);
966 }
967
968 HRESULT exec_script(script_ctx_t *ctx, function_t *func, DISPPARAMS *dp, VARIANT *res)
969 {
970     exec_ctx_t exec = {func->code_ctx};
971     vbsop_t op;
972     HRESULT hres = S_OK;
973
974     exec.code = func->code_ctx;
975
976     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
977         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
978         return E_FAIL;
979     }
980
981     if(func->arg_cnt) {
982         VARIANT *v;
983         unsigned i;
984
985         exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
986         if(!exec.args) {
987             release_exec(&exec);
988             return E_OUTOFMEMORY;
989         }
990
991         for(i=0; i < func->arg_cnt; i++) {
992             v = get_arg(dp, i);
993             if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
994                 if(func->args[i].by_ref)
995                     exec.args[i] = *v;
996                 else
997                     hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
998             }else {
999                 hres = VariantCopy(exec.args+i, v);
1000             }
1001             if(FAILED(hres)) {
1002                 release_exec(&exec);
1003                 return hres;
1004             }
1005         }
1006     }else {
1007         exec.args = NULL;
1008     }
1009
1010     if(func->var_cnt) {
1011         exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
1012         if(!exec.vars) {
1013             release_exec(&exec);
1014             return E_OUTOFMEMORY;
1015         }
1016     }else {
1017         exec.vars = NULL;
1018     }
1019
1020     exec.stack_size = 16;
1021     exec.top = 0;
1022     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
1023     if(!exec.stack) {
1024         release_exec(&exec);
1025         return E_OUTOFMEMORY;
1026     }
1027
1028     exec.instr = exec.code->instrs + func->code_off;
1029     exec.script = ctx;
1030     exec.func = func;
1031
1032     while(exec.instr) {
1033         op = exec.instr->op;
1034         hres = op_funcs[op](&exec);
1035         if(FAILED(hres)) {
1036             FIXME("Failed %08x\n", hres);
1037             stack_popn(&exec, exec.top);
1038             break;
1039         }
1040
1041         exec.instr += op_move[op];
1042     }
1043
1044     assert(!exec.top);
1045     if(func->type != FUNC_FUNCTION)
1046         assert(V_VT(&exec.ret_val) == VT_EMPTY);
1047
1048     if(SUCCEEDED(hres) && res) {
1049         *res = exec.ret_val;
1050         V_VT(&exec.ret_val) = VT_EMPTY;
1051     }
1052
1053     release_exec(&exec);
1054
1055     return hres;
1056 }