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