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