vbscript: Added interp_set_member 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 || 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     IDispatch *obj, *val;
506     DISPID id;
507     HRESULT hres;
508
509     TRACE("%s\n", debugstr_w(identifier));
510
511     hres = stack_pop_disp(ctx, &obj);
512     if(FAILED(hres))
513         return hres;
514
515     if(!obj) {
516         FIXME("NULL obj\n");
517         return E_FAIL;
518     }
519
520     hres = stack_pop_disp(ctx, &val);
521     if(FAILED(hres)) {
522         IDispatch_Release(obj);
523         return hres;
524     }
525
526     hres = disp_get_id(obj, identifier, VBDISP_SET, FALSE, &id);
527     if(SUCCEEDED(hres)) {
528         VARIANT v;
529
530         V_VT(&v) = VT_DISPATCH;
531         V_DISPATCH(&v) = val;
532         hres = disp_propput(ctx->script, obj, id, &v);
533     }
534
535     if(val)
536         IDispatch_Release(val);
537     IDispatch_Release(obj);
538     return hres;
539 }
540
541 static HRESULT interp_new(exec_ctx_t *ctx)
542 {
543     const WCHAR *arg = ctx->instr->arg1.bstr;
544     class_desc_t *class_desc;
545     vbdisp_t *obj;
546     VARIANT v;
547     HRESULT hres;
548
549     TRACE("%s\n", debugstr_w(arg));
550
551     for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
552         if(!strcmpiW(class_desc->name, arg))
553             break;
554     }
555     if(!class_desc) {
556         FIXME("Class %s not found\n", debugstr_w(arg));
557         return E_FAIL;
558     }
559
560     hres = create_vbdisp(class_desc, &obj);
561     if(FAILED(hres))
562         return hres;
563
564     V_VT(&v) = VT_DISPATCH;
565     V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
566     return stack_push(ctx, &v);
567 }
568
569 static HRESULT interp_jmp(exec_ctx_t *ctx)
570 {
571     const unsigned arg = ctx->instr->arg1.uint;
572
573     TRACE("%u\n", arg);
574
575     instr_jmp(ctx, arg);
576     return S_OK;
577 }
578
579 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
580 {
581     const unsigned arg = ctx->instr->arg1.uint;
582     variant_val_t val;
583     HRESULT hres;
584
585     TRACE("%u\n", arg);
586
587     hres = stack_pop_val(ctx, &val);
588     if(FAILED(hres))
589         return hres;
590
591     if(V_VT(val.v) != VT_BOOL) {
592         FIXME("unsupported for %s\n", debugstr_variant(val.v));
593         release_val(&val);
594         return E_NOTIMPL;
595     }
596
597     if(V_BOOL(val.v))
598         ctx->instr++;
599     else
600         instr_jmp(ctx, ctx->instr->arg1.uint);
601     return S_OK;
602 }
603
604 static HRESULT interp_ret(exec_ctx_t *ctx)
605 {
606     TRACE("\n");
607
608     ctx->instr = NULL;
609     return S_OK;
610 }
611
612 static HRESULT interp_stop(exec_ctx_t *ctx)
613 {
614     WARN("\n");
615
616     /* NOTE: this should have effect in debugging mode (that we don't support yet) */
617     return S_OK;
618 }
619
620 static HRESULT interp_bool(exec_ctx_t *ctx)
621 {
622     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
623     VARIANT v;
624
625     TRACE("%s\n", arg ? "true" : "false");
626
627     V_VT(&v) = VT_BOOL;
628     V_BOOL(&v) = arg;
629     return stack_push(ctx, &v);
630 }
631
632 static HRESULT interp_string(exec_ctx_t *ctx)
633 {
634     VARIANT v;
635
636     TRACE("\n");
637
638     V_VT(&v) = VT_BSTR;
639     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
640     if(!V_BSTR(&v))
641         return E_OUTOFMEMORY;
642
643     return stack_push(ctx, &v);
644 }
645
646 static HRESULT interp_long(exec_ctx_t *ctx)
647 {
648     const LONG arg = ctx->instr->arg1.lng;
649     VARIANT v;
650
651     TRACE("%d\n", arg);
652
653     V_VT(&v) = VT_I4;
654     V_I4(&v) = arg;
655     return stack_push(ctx, &v);
656 }
657
658 static HRESULT interp_short(exec_ctx_t *ctx)
659 {
660     const LONG arg = ctx->instr->arg1.lng;
661     VARIANT v;
662
663     TRACE("%d\n", arg);
664
665     V_VT(&v) = VT_I2;
666     V_I2(&v) = arg;
667     return stack_push(ctx, &v);
668 }
669
670 static HRESULT interp_double(exec_ctx_t *ctx)
671 {
672     const DOUBLE *arg = ctx->instr->arg1.dbl;
673     VARIANT v;
674
675     TRACE("%lf\n", *arg);
676
677     V_VT(&v) = VT_R8;
678     V_R8(&v) = *arg;
679     return stack_push(ctx, &v);
680 }
681
682 static HRESULT interp_empty(exec_ctx_t *ctx)
683 {
684     VARIANT v;
685
686     TRACE("\n");
687
688     V_VT(&v) = VT_EMPTY;
689     return stack_push(ctx, &v);
690 }
691
692 static HRESULT interp_null(exec_ctx_t *ctx)
693 {
694     VARIANT v;
695
696     TRACE("\n");
697
698     V_VT(&v) = VT_NULL;
699     return stack_push(ctx, &v);
700 }
701
702 static HRESULT interp_nothing(exec_ctx_t *ctx)
703 {
704     VARIANT v;
705
706     TRACE("\n");
707
708     V_VT(&v) = VT_DISPATCH;
709     V_DISPATCH(&v) = NULL;
710     return stack_push(ctx, &v);
711 }
712
713 static HRESULT interp_not(exec_ctx_t *ctx)
714 {
715     variant_val_t val;
716     VARIANT v;
717     HRESULT hres;
718
719     TRACE("\n");
720
721     hres = stack_pop_val(ctx, &val);
722     if(FAILED(hres))
723         return hres;
724
725     hres = VarNot(val.v, &v);
726     release_val(&val);
727     if(FAILED(hres))
728         return hres;
729
730     return stack_push(ctx, &v);
731 }
732
733 static HRESULT interp_and(exec_ctx_t *ctx)
734 {
735     variant_val_t r, l;
736     VARIANT v;
737     HRESULT hres;
738
739     TRACE("\n");
740
741     hres = stack_pop_val(ctx, &r);
742     if(FAILED(hres))
743         return hres;
744
745     hres = stack_pop_val(ctx, &l);
746     if(SUCCEEDED(hres)) {
747         hres = VarAnd(l.v, r.v, &v);
748         release_val(&l);
749     }
750     release_val(&r);
751     if(FAILED(hres))
752         return hres;
753
754     return stack_push(ctx, &v);
755 }
756
757 static HRESULT interp_or(exec_ctx_t *ctx)
758 {
759     variant_val_t r, l;
760     VARIANT v;
761     HRESULT hres;
762
763     TRACE("\n");
764
765     hres = stack_pop_val(ctx, &r);
766     if(FAILED(hres))
767         return hres;
768
769     hres = stack_pop_val(ctx, &l);
770     if(SUCCEEDED(hres)) {
771         hres = VarOr(l.v, r.v, &v);
772         release_val(&l);
773     }
774     release_val(&r);
775     if(FAILED(hres))
776         return hres;
777
778     return stack_push(ctx, &v);
779 }
780
781 static HRESULT interp_xor(exec_ctx_t *ctx)
782 {
783     variant_val_t r, l;
784     VARIANT v;
785     HRESULT hres;
786
787     TRACE("\n");
788
789     hres = stack_pop_val(ctx, &r);
790     if(FAILED(hres))
791         return hres;
792
793     hres = stack_pop_val(ctx, &l);
794     if(SUCCEEDED(hres)) {
795         hres = VarXor(l.v, r.v, &v);
796         release_val(&l);
797     }
798     release_val(&r);
799     if(FAILED(hres))
800         return hres;
801
802     return stack_push(ctx, &v);
803 }
804
805 static HRESULT interp_eqv(exec_ctx_t *ctx)
806 {
807     variant_val_t r, l;
808     VARIANT v;
809     HRESULT hres;
810
811     TRACE("\n");
812
813     hres = stack_pop_val(ctx, &r);
814     if(FAILED(hres))
815         return hres;
816
817     hres = stack_pop_val(ctx, &l);
818     if(SUCCEEDED(hres)) {
819         hres = VarEqv(l.v, r.v, &v);
820         release_val(&l);
821     }
822     release_val(&r);
823     if(FAILED(hres))
824         return hres;
825
826     return stack_push(ctx, &v);
827 }
828
829 static HRESULT interp_imp(exec_ctx_t *ctx)
830 {
831     variant_val_t r, l;
832     VARIANT v;
833     HRESULT hres;
834
835     TRACE("\n");
836
837     hres = stack_pop_val(ctx, &r);
838     if(FAILED(hres))
839         return hres;
840
841     hres = stack_pop_val(ctx, &l);
842     if(SUCCEEDED(hres)) {
843         hres = VarImp(l.v, r.v, &v);
844         release_val(&l);
845     }
846     release_val(&r);
847     if(FAILED(hres))
848         return hres;
849
850     return stack_push(ctx, &v);
851 }
852
853 static HRESULT cmp_oper(exec_ctx_t *ctx)
854 {
855     variant_val_t l, r;
856     HRESULT hres;
857
858     hres = stack_pop_val(ctx, &r);
859     if(FAILED(hres))
860         return hres;
861
862     hres = stack_pop_val(ctx, &l);
863     if(SUCCEEDED(hres)) {
864         if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
865             FIXME("comparing nulls is not implemented\n");
866             hres = E_NOTIMPL;
867         }else {
868             hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
869         }
870     }
871
872     release_val(&r);
873     release_val(&l);
874     return hres;
875 }
876
877 static HRESULT interp_equal(exec_ctx_t *ctx)
878 {
879     VARIANT v;
880     HRESULT hres;
881
882     TRACE("\n");
883
884     hres = cmp_oper(ctx);
885     if(FAILED(hres))
886         return hres;
887
888     V_VT(&v) = VT_BOOL;
889     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
890     return stack_push(ctx, &v);
891 }
892
893 static HRESULT interp_nequal(exec_ctx_t *ctx)
894 {
895     VARIANT v;
896     HRESULT hres;
897
898     TRACE("\n");
899
900     hres = cmp_oper(ctx);
901     if(FAILED(hres))
902         return hres;
903
904     V_VT(&v) = VT_BOOL;
905     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
906     return stack_push(ctx, &v);
907 }
908
909 static HRESULT interp_concat(exec_ctx_t *ctx)
910 {
911     variant_val_t r, l;
912     VARIANT v;
913     HRESULT hres;
914
915     TRACE("\n");
916
917     hres = stack_pop_val(ctx, &r);
918     if(FAILED(hres))
919         return hres;
920
921     hres = stack_pop_val(ctx, &l);
922     if(SUCCEEDED(hres)) {
923         hres = VarCat(l.v, r.v, &v);
924         release_val(&l);
925     }
926     release_val(&r);
927     if(FAILED(hres))
928         return hres;
929
930     return stack_push(ctx, &v);
931 }
932
933 static HRESULT interp_add(exec_ctx_t *ctx)
934 {
935     variant_val_t r, l;
936     VARIANT v;
937     HRESULT hres;
938
939     TRACE("\n");
940
941     hres = stack_pop_val(ctx, &r);
942     if(FAILED(hres))
943         return hres;
944
945     hres = stack_pop_val(ctx, &l);
946     if(SUCCEEDED(hres)) {
947         hres = VarAdd(l.v, r.v, &v);
948         release_val(&l);
949     }
950     release_val(&r);
951     if(FAILED(hres))
952         return hres;
953
954     return stack_push(ctx, &v);
955 }
956
957 static HRESULT interp_sub(exec_ctx_t *ctx)
958 {
959     variant_val_t r, l;
960     VARIANT v;
961     HRESULT hres;
962
963     TRACE("\n");
964
965     hres = stack_pop_val(ctx, &r);
966     if(FAILED(hres))
967         return hres;
968
969     hres = stack_pop_val(ctx, &l);
970     if(SUCCEEDED(hres)) {
971         hres = VarSub(l.v, r.v, &v);
972         release_val(&l);
973     }
974     release_val(&r);
975     if(FAILED(hres))
976         return hres;
977
978     return stack_push(ctx, &v);
979 }
980
981 static HRESULT interp_mod(exec_ctx_t *ctx)
982 {
983     variant_val_t r, l;
984     VARIANT v;
985     HRESULT hres;
986
987     TRACE("\n");
988
989     hres = stack_pop_val(ctx, &r);
990     if(FAILED(hres))
991         return hres;
992
993     hres = stack_pop_val(ctx, &l);
994     if(SUCCEEDED(hres)) {
995         hres = VarMod(l.v, r.v, &v);
996         release_val(&l);
997     }
998     release_val(&r);
999     if(FAILED(hres))
1000         return hres;
1001
1002     return stack_push(ctx, &v);
1003 }
1004
1005 static HRESULT interp_idiv(exec_ctx_t *ctx)
1006 {
1007     variant_val_t r, l;
1008     VARIANT v;
1009     HRESULT hres;
1010
1011     TRACE("\n");
1012
1013     hres = stack_pop_val(ctx, &r);
1014     if(FAILED(hres))
1015         return hres;
1016
1017     hres = stack_pop_val(ctx, &l);
1018     if(SUCCEEDED(hres)) {
1019         hres = VarIdiv(l.v, r.v, &v);
1020         release_val(&l);
1021     }
1022     release_val(&r);
1023     if(FAILED(hres))
1024         return hres;
1025
1026     return stack_push(ctx, &v);
1027 }
1028
1029 static HRESULT interp_div(exec_ctx_t *ctx)
1030 {
1031     variant_val_t r, l;
1032     VARIANT v;
1033     HRESULT hres;
1034
1035     TRACE("\n");
1036
1037     hres = stack_pop_val(ctx, &r);
1038     if(FAILED(hres))
1039         return hres;
1040
1041     hres = stack_pop_val(ctx, &l);
1042     if(SUCCEEDED(hres)) {
1043         hres = VarDiv(l.v, r.v, &v);
1044         release_val(&l);
1045     }
1046     release_val(&r);
1047     if(FAILED(hres))
1048         return hres;
1049
1050     return stack_push(ctx, &v);
1051 }
1052
1053 static HRESULT interp_mul(exec_ctx_t *ctx)
1054 {
1055     variant_val_t r, l;
1056     VARIANT v;
1057     HRESULT hres;
1058
1059     TRACE("\n");
1060
1061     hres = stack_pop_val(ctx, &r);
1062     if(FAILED(hres))
1063         return hres;
1064
1065     hres = stack_pop_val(ctx, &l);
1066     if(SUCCEEDED(hres)) {
1067         hres = VarMul(l.v, r.v, &v);
1068         release_val(&l);
1069     }
1070     release_val(&r);
1071     if(FAILED(hres))
1072         return hres;
1073
1074     return stack_push(ctx, &v);
1075 }
1076
1077 static HRESULT interp_exp(exec_ctx_t *ctx)
1078 {
1079     variant_val_t r, l;
1080     VARIANT v;
1081     HRESULT hres;
1082
1083     TRACE("\n");
1084
1085     hres = stack_pop_val(ctx, &r);
1086     if(FAILED(hres))
1087         return hres;
1088
1089     hres = stack_pop_val(ctx, &l);
1090     if(SUCCEEDED(hres)) {
1091         hres = VarPow(l.v, r.v, &v);
1092         release_val(&l);
1093     }
1094     release_val(&r);
1095     if(FAILED(hres))
1096         return hres;
1097
1098     return stack_push(ctx, &v);
1099 }
1100
1101 static HRESULT interp_neg(exec_ctx_t *ctx)
1102 {
1103     variant_val_t val;
1104     VARIANT v;
1105     HRESULT hres;
1106
1107     hres = stack_pop_val(ctx, &val);
1108     if(FAILED(hres))
1109         return hres;
1110
1111     hres = VarNeg(val.v, &v);
1112     release_val(&val);
1113     if(FAILED(hres))
1114         return hres;
1115
1116     return stack_push(ctx, &v);
1117 }
1118
1119 static const instr_func_t op_funcs[] = {
1120 #define X(x,n,a,b) interp_ ## x,
1121 OP_LIST
1122 #undef X
1123 };
1124
1125 static const unsigned op_move[] = {
1126 #define X(x,n,a,b) n,
1127 OP_LIST
1128 #undef X
1129 };
1130
1131 static void release_exec(exec_ctx_t *ctx)
1132 {
1133     unsigned i;
1134
1135     VariantClear(&ctx->ret_val);
1136
1137     if(ctx->this_obj)
1138         IDispatch_Release(ctx->this_obj);
1139
1140     if(ctx->args) {
1141         for(i=0; i < ctx->func->arg_cnt; i++)
1142             VariantClear(ctx->args+i);
1143     }
1144
1145     if(ctx->vars) {
1146         for(i=0; i < ctx->func->var_cnt; i++)
1147             VariantClear(ctx->vars+i);
1148     }
1149
1150     heap_free(ctx->args);
1151     heap_free(ctx->vars);
1152     heap_free(ctx->stack);
1153 }
1154
1155 HRESULT exec_script(script_ctx_t *ctx, function_t *func, IDispatch *this_obj, DISPPARAMS *dp, VARIANT *res)
1156 {
1157     exec_ctx_t exec = {func->code_ctx};
1158     vbsop_t op;
1159     HRESULT hres = S_OK;
1160
1161     exec.code = func->code_ctx;
1162
1163     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
1164         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
1165         return E_FAIL;
1166     }
1167
1168     if(func->arg_cnt) {
1169         VARIANT *v;
1170         unsigned i;
1171
1172         exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
1173         if(!exec.args) {
1174             release_exec(&exec);
1175             return E_OUTOFMEMORY;
1176         }
1177
1178         for(i=0; i < func->arg_cnt; i++) {
1179             v = get_arg(dp, i);
1180             if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
1181                 if(func->args[i].by_ref)
1182                     exec.args[i] = *v;
1183                 else
1184                     hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
1185             }else {
1186                 hres = VariantCopy(exec.args+i, v);
1187             }
1188             if(FAILED(hres)) {
1189                 release_exec(&exec);
1190                 return hres;
1191             }
1192         }
1193     }else {
1194         exec.args = NULL;
1195     }
1196
1197     if(func->var_cnt) {
1198         exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
1199         if(!exec.vars) {
1200             release_exec(&exec);
1201             return E_OUTOFMEMORY;
1202         }
1203     }else {
1204         exec.vars = NULL;
1205     }
1206
1207     exec.stack_size = 16;
1208     exec.top = 0;
1209     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
1210     if(!exec.stack) {
1211         release_exec(&exec);
1212         return E_OUTOFMEMORY;
1213     }
1214
1215     if(this_obj)
1216         exec.this_obj = this_obj;
1217     else if (ctx->host_global)
1218         exec.this_obj = ctx->host_global;
1219     else
1220         exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface;
1221     IDispatch_AddRef(exec.this_obj);
1222
1223     exec.instr = exec.code->instrs + func->code_off;
1224     exec.script = ctx;
1225     exec.func = func;
1226
1227     while(exec.instr) {
1228         op = exec.instr->op;
1229         hres = op_funcs[op](&exec);
1230         if(FAILED(hres)) {
1231             FIXME("Failed %08x\n", hres);
1232             stack_popn(&exec, exec.top);
1233             break;
1234         }
1235
1236         exec.instr += op_move[op];
1237     }
1238
1239     assert(!exec.top);
1240     if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET)
1241         assert(V_VT(&exec.ret_val) == VT_EMPTY);
1242
1243     if(SUCCEEDED(hres) && res) {
1244         *res = exec.ret_val;
1245         V_VT(&exec.ret_val) = VT_EMPTY;
1246     }
1247
1248     release_exec(&exec);
1249
1250     return hres;
1251 }