vbscript: Added const statement tests.
[wine] / dlls / vbscript / interp.c
1 /*
2  * Copyright 2011 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <assert.h>
20
21 #include "vbscript.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
26
27 typedef struct {
28     vbscode_t *code;
29     instr_t *instr;
30     script_ctx_t *script;
31     function_t *func;
32     IDispatch *this_obj;
33
34     VARIANT *args;
35     VARIANT *vars;
36
37     dynamic_var_t *dynamic_vars;
38     vbsheap_t heap;
39
40     unsigned stack_size;
41     unsigned top;
42     VARIANT *stack;
43
44     VARIANT ret_val;
45 } exec_ctx_t;
46
47 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
48
49 typedef enum {
50     REF_NONE,
51     REF_DISP,
52     REF_VAR,
53     REF_OBJ,
54     REF_CONST,
55     REF_FUNC
56 } ref_type_t;
57
58 typedef struct {
59     ref_type_t type;
60     union {
61         struct {
62             IDispatch *disp;
63             DISPID id;
64         } d;
65         VARIANT *v;
66         function_t *f;
67         IDispatch *obj;
68     } u;
69 } ref_t;
70
71 typedef struct {
72     VARIANT *v;
73     VARIANT store;
74     BOOL owned;
75 } variant_val_t;
76
77 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
78 {
79     while(var) {
80         if(!strcmpiW(var->name, name)) {
81             ref->type = var->is_const ? REF_CONST : REF_VAR;
82             ref->u.v = &var->v;
83             return TRUE;
84         }
85
86         var = var->next;
87     }
88
89     return FALSE;
90 }
91
92 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref)
93 {
94     named_item_t *item;
95     function_t *func;
96     unsigned i;
97     DISPID id;
98     HRESULT hres;
99
100     static const WCHAR errW[] = {'e','r','r',0};
101
102     if(invoke_type == VBDISP_LET
103             && (ctx->func->type == FUNC_FUNCTION || ctx->func->type == FUNC_PROPGET || ctx->func->type == FUNC_DEFGET)
104             && !strcmpiW(name, ctx->func->name)) {
105         ref->type = REF_VAR;
106         ref->u.v = &ctx->ret_val;
107         return S_OK;
108     }
109
110     for(i=0; i < ctx->func->var_cnt; i++) {
111         if(!strcmpiW(ctx->func->vars[i].name, name)) {
112             ref->type = REF_VAR;
113             ref->u.v = ctx->vars+i;
114             return TRUE;
115         }
116     }
117
118     for(i=0; i < ctx->func->arg_cnt; i++) {
119         if(!strcmpiW(ctx->func->args[i].name, name)) {
120             ref->type = REF_VAR;
121             ref->u.v = ctx->args+i;
122             return S_OK;
123         }
124     }
125
126     if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? ctx->script->global_vars : ctx->dynamic_vars, name, ref))
127         return S_OK;
128
129     hres = disp_get_id(ctx->this_obj, name, invoke_type, TRUE, &id);
130     if(SUCCEEDED(hres)) {
131         ref->type = REF_DISP;
132         ref->u.d.disp = ctx->this_obj;
133         ref->u.d.id = id;
134         return S_OK;
135     }
136
137     if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(ctx->script->global_vars, name, ref))
138         return S_OK;
139
140     for(func = ctx->script->global_funcs; func; func = func->next) {
141         if(!strcmpiW(func->name, name)) {
142             ref->type = REF_FUNC;
143             ref->u.f = func;
144             return S_OK;
145         }
146     }
147
148     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
149         if((item->flags & SCRIPTITEM_GLOBALMEMBERS) && item->disp != ctx->this_obj) {
150             hres = disp_get_id(item->disp, name, invoke_type, FALSE, &id);
151             if(SUCCEEDED(hres)) {
152                 ref->type = REF_DISP;
153                 ref->u.d.disp = item->disp;
154                 ref->u.d.id = id;
155                 return S_OK;
156             }
157         }
158
159         if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpiW(item->name, name)) {
160             if(!item->disp) {
161                 IUnknown *unk;
162
163                 hres = IActiveScriptSite_GetItemInfo(ctx->script->site, name, SCRIPTINFO_IUNKNOWN, &unk, NULL);
164                 if(FAILED(hres)) {
165                     WARN("GetItemInfo failed: %08x\n", hres);
166                     continue;
167                 }
168
169                 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp);
170                 IUnknown_Release(unk);
171                 if(FAILED(hres)) {
172                     WARN("object does not implement IDispatch\n");
173                     continue;
174                 }
175             }
176
177             ref->type = REF_OBJ;
178             ref->u.obj = item->disp;
179             return S_OK;
180         }
181     }
182
183     if(!strcmpiW(name, errW)) {
184         ref->type = REF_OBJ;
185         ref->u.obj = (IDispatch*)&ctx->script->err_obj->IDispatchEx_iface;
186         return S_OK;
187     }
188
189     hres = vbdisp_get_id(ctx->script->global_obj, name, invoke_type, TRUE, &id);
190     if(SUCCEEDED(hres)) {
191         ref->type = REF_DISP;
192         ref->u.d.disp = (IDispatch*)&ctx->script->global_obj->IDispatchEx_iface;
193         ref->u.d.id = id;
194         return S_OK;
195     }
196
197     ref->type = REF_NONE;
198     return S_OK;
199 }
200
201 static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name, BOOL is_const, VARIANT *val, BOOL own_val)
202 {
203     dynamic_var_t *new_var;
204     vbsheap_t *heap;
205     WCHAR *str;
206     unsigned size;
207     HRESULT hres;
208
209     heap = ctx->func->type == FUNC_GLOBAL ? &ctx->script->heap : &ctx->heap;
210
211     new_var = vbsheap_alloc(heap, sizeof(*new_var));
212     if(!new_var)
213         return E_OUTOFMEMORY;
214
215     size = (strlenW(name)+1)*sizeof(WCHAR);
216     str = vbsheap_alloc(heap, size);
217     if(!str)
218         return E_OUTOFMEMORY;
219     memcpy(str, name, size);
220     new_var->name = str;
221     new_var->is_const = is_const;
222
223     if(own_val) {
224         new_var->v = *val;
225     }else {
226         hres = VariantCopy(&new_var->v, val);
227         if(FAILED(hres))
228             return hres;
229     }
230
231     if(ctx->func->type == FUNC_GLOBAL) {
232         new_var->next = ctx->script->global_vars;
233         ctx->script->global_vars = new_var;
234     }else {
235         new_var->next = ctx->dynamic_vars;
236         ctx->dynamic_vars = new_var;
237     }
238
239     return S_OK;
240 }
241
242 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
243 {
244     assert(ctx->top);
245     return ctx->stack + --ctx->top;
246 }
247
248 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
249 {
250     if(ctx->stack_size == ctx->top) {
251         VARIANT *new_stack;
252
253         new_stack = heap_realloc(ctx->stack, ctx->stack_size*2);
254         if(!new_stack) {
255             VariantClear(v);
256             return E_OUTOFMEMORY;
257         }
258
259         ctx->stack = new_stack;
260         ctx->stack_size *= 2;
261     }
262
263     ctx->stack[ctx->top++] = *v;
264     return S_OK;
265 }
266
267 static void stack_popn(exec_ctx_t *ctx, unsigned n)
268 {
269     while(n--)
270         VariantClear(stack_pop(ctx));
271 }
272
273 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *v)
274 {
275     VARIANT *var;
276
277     var = stack_pop(ctx);
278
279     if(V_VT(var) == (VT_BYREF|VT_VARIANT)) {
280         v->owned = FALSE;
281         var = V_VARIANTREF(var);
282     }else {
283         v->owned = TRUE;
284     }
285
286     if(V_VT(var) == VT_DISPATCH) {
287         DISPPARAMS dp = {0};
288         HRESULT hres;
289
290         hres = disp_call(ctx->script, V_DISPATCH(var), DISPID_VALUE, &dp, &v->store);
291         if(v->owned)
292             IDispatch_Release(V_DISPATCH(var));
293         if(FAILED(hres))
294             return hres;
295
296         v->owned = TRUE;
297         v->v = &v->store;
298     }else {
299         v->v = var;
300     }
301
302     return S_OK;
303 }
304
305 static inline void release_val(variant_val_t *v)
306 {
307     if(v->owned)
308         VariantClear(v->v);
309 }
310
311 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
312 {
313     VARIANT *v = stack_pop(ctx);
314
315     if(V_VT(v) == VT_DISPATCH) {
316         *ret = V_DISPATCH(v);
317         return S_OK;
318     }
319
320     if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
321         FIXME("not supported type: %s\n", debugstr_variant(v));
322         VariantClear(v);
323         return E_FAIL;
324     }
325
326     v = V_BYREF(v);
327     if(V_VT(v) != VT_DISPATCH) {
328         FIXME("not disp %s\n", debugstr_variant(v));
329         return E_FAIL;
330     }
331
332     if(V_DISPATCH(v))
333         IDispatch_AddRef(V_DISPATCH(v));
334     *ret = V_DISPATCH(v);
335     return S_OK;
336 }
337
338 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
339 {
340     ctx->instr = ctx->code->instrs + addr;
341 }
342
343 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, DISPPARAMS *dp)
344 {
345     dp->cArgs = arg_cnt;
346     dp->rgdispidNamedArgs = NULL;
347     dp->cNamedArgs = 0;
348
349     if(arg_cnt) {
350         VARIANT tmp;
351         unsigned i;
352
353         assert(ctx->top >= arg_cnt);
354
355         for(i=1; i*2 <= arg_cnt; i++) {
356             tmp = ctx->stack[ctx->top-i];
357             ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
358             ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
359         }
360
361         dp->rgvarg = ctx->stack + ctx->top-arg_cnt;
362     }else {
363         dp->rgvarg = NULL;
364     }
365 }
366
367 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
368 {
369     BSTR identifier = ctx->instr->arg1.bstr;
370     const unsigned arg_cnt = ctx->instr->arg2.uint;
371     DISPPARAMS dp;
372     ref_t ref;
373     HRESULT hres;
374
375     hres = lookup_identifier(ctx, identifier, VBDISP_CALLGET, &ref);
376     if(FAILED(hres))
377         return hres;
378
379     vbstack_to_dp(ctx, arg_cnt, &dp);
380
381     switch(ref.type) {
382     case REF_VAR:
383     case REF_CONST:
384         if(!res) {
385             FIXME("REF_VAR no res\n");
386             return E_NOTIMPL;
387         }
388
389         if(arg_cnt) {
390             FIXME("arguments not implemented\n");
391             return E_NOTIMPL;
392         }
393
394         V_VT(res) = VT_BYREF|VT_VARIANT;
395         V_BYREF(res) = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
396         break;
397     case REF_DISP:
398         hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
399         if(FAILED(hres))
400             return hres;
401         break;
402     case REF_FUNC:
403         hres = exec_script(ctx->script, ref.u.f, NULL, &dp, res);
404         if(FAILED(hres))
405             return hres;
406         break;
407     case REF_OBJ:
408         if(arg_cnt) {
409             FIXME("arguments on object\n");
410             return E_NOTIMPL;
411         }
412
413         if(res) {
414             IDispatch_AddRef(ref.u.obj);
415             V_VT(res) = VT_DISPATCH;
416             V_DISPATCH(res) = ref.u.obj;
417         }
418         break;
419     case REF_NONE:
420         FIXME("%s not found\n", debugstr_w(identifier));
421         return DISP_E_UNKNOWNNAME;
422     }
423
424     stack_popn(ctx, arg_cnt);
425     return S_OK;
426 }
427
428 static HRESULT interp_icall(exec_ctx_t *ctx)
429 {
430     VARIANT v;
431     HRESULT hres;
432
433     TRACE("\n");
434
435     hres = do_icall(ctx, &v);
436     if(FAILED(hres))
437         return hres;
438
439     return stack_push(ctx, &v);
440 }
441
442 static HRESULT interp_icallv(exec_ctx_t *ctx)
443 {
444     TRACE("\n");
445     return do_icall(ctx, NULL);
446 }
447
448 static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res)
449 {
450     const BSTR identifier = ctx->instr->arg1.bstr;
451     const unsigned arg_cnt = ctx->instr->arg2.uint;
452     IDispatch *obj;
453     DISPPARAMS dp;
454     DISPID id;
455     HRESULT hres;
456
457     hres = stack_pop_disp(ctx, &obj);
458     if(FAILED(hres))
459         return hres;
460
461     if(!obj) {
462         FIXME("NULL obj\n");
463         return E_FAIL;
464     }
465
466     vbstack_to_dp(ctx, arg_cnt, &dp);
467
468     hres = disp_get_id(obj, identifier, VBDISP_CALLGET, FALSE, &id);
469     if(SUCCEEDED(hres))
470         hres = disp_call(ctx->script, obj, id, &dp, res);
471     IDispatch_Release(obj);
472     if(FAILED(hres))
473         return hres;
474
475     stack_popn(ctx, arg_cnt);
476     return S_OK;
477 }
478
479 static HRESULT interp_mcall(exec_ctx_t *ctx)
480 {
481     VARIANT res;
482     HRESULT hres;
483
484     TRACE("\n");
485
486     hres = do_mcall(ctx, &res);
487     if(FAILED(hres))
488         return hres;
489
490     return stack_push(ctx, &res);
491 }
492
493 static HRESULT interp_mcallv(exec_ctx_t *ctx)
494 {
495     TRACE("\n");
496
497     return do_mcall(ctx, NULL);
498 }
499
500 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
501 {
502     ref_t ref;
503     HRESULT hres;
504
505     hres = lookup_identifier(ctx, name, VBDISP_LET, &ref);
506     if(FAILED(hres))
507         return hres;
508
509     switch(ref.type) {
510     case REF_VAR: {
511         VARIANT *v = ref.u.v;
512
513         if(V_VT(v) == (VT_VARIANT|VT_BYREF))
514             v = V_VARIANTREF(v);
515
516         if(own_val) {
517             VariantClear(v);
518             *v = *val;
519             hres = S_OK;
520         }else {
521             hres = VariantCopy(v, val);
522         }
523         break;
524     }
525     case REF_DISP:
526         hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, val);
527         if(own_val)
528             VariantClear(val);
529         break;
530     case REF_FUNC:
531         FIXME("functions not implemented\n");
532         return E_NOTIMPL;
533     case REF_OBJ:
534         FIXME("REF_OBJ\n");
535         return E_NOTIMPL;
536     case REF_CONST:
537         FIXME("REF_CONST\n");
538         return E_NOTIMPL;
539     case REF_NONE:
540         if(ctx->func->code_ctx->option_explicit) {
541             FIXME("throw exception\n");
542             hres = E_FAIL;
543         }else {
544             TRACE("creating variable %s\n", debugstr_w(name));
545             hres = add_dynamic_var(ctx, name, FALSE, val, own_val);
546         }
547     }
548
549     return hres;
550 }
551
552 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
553 {
554     const BSTR arg = ctx->instr->arg1.bstr;
555     variant_val_t v;
556     HRESULT hres;
557
558     TRACE("%s\n", debugstr_w(arg));
559
560     hres = stack_pop_val(ctx, &v);
561     if(FAILED(hres))
562         return hres;
563
564     return assign_ident(ctx, arg, v.v, v.owned);
565 }
566
567 static HRESULT interp_set_ident(exec_ctx_t *ctx)
568 {
569     const BSTR arg = ctx->instr->arg1.bstr;
570     IDispatch *disp;
571     VARIANT v;
572     HRESULT hres;
573
574     TRACE("%s\n", debugstr_w(arg));
575
576     hres = stack_pop_disp(ctx, &disp);
577     if(FAILED(hres))
578         return hres;
579
580     V_VT(&v) = VT_DISPATCH;
581     V_DISPATCH(&v) = disp;
582     return assign_ident(ctx, ctx->instr->arg1.bstr, &v, TRUE);
583 }
584
585 static HRESULT interp_assign_member(exec_ctx_t *ctx)
586 {
587     BSTR identifier = ctx->instr->arg1.bstr;
588     variant_val_t val;
589     IDispatch *obj;
590     DISPID id;
591     HRESULT hres;
592
593     TRACE("%s\n", debugstr_w(identifier));
594
595     hres = stack_pop_disp(ctx, &obj);
596     if(FAILED(hres))
597         return hres;
598
599     if(!obj) {
600         FIXME("NULL obj\n");
601         return E_FAIL;
602     }
603
604     hres = stack_pop_val(ctx, &val);
605     if(FAILED(hres)) {
606         IDispatch_Release(obj);
607         return hres;
608     }
609
610     hres = disp_get_id(obj, identifier, VBDISP_LET, FALSE, &id);
611     if(SUCCEEDED(hres))
612         hres = disp_propput(ctx->script, obj, id, val.v);
613
614     release_val(&val);
615     IDispatch_Release(obj);
616     return hres;
617 }
618
619 static HRESULT interp_set_member(exec_ctx_t *ctx)
620 {
621     BSTR identifier = ctx->instr->arg1.bstr;
622     IDispatch *obj, *val;
623     DISPID id;
624     HRESULT hres;
625
626     TRACE("%s\n", debugstr_w(identifier));
627
628     hres = stack_pop_disp(ctx, &obj);
629     if(FAILED(hres))
630         return hres;
631
632     if(!obj) {
633         FIXME("NULL obj\n");
634         return E_FAIL;
635     }
636
637     hres = stack_pop_disp(ctx, &val);
638     if(FAILED(hres)) {
639         IDispatch_Release(obj);
640         return hres;
641     }
642
643     hres = disp_get_id(obj, identifier, VBDISP_SET, FALSE, &id);
644     if(SUCCEEDED(hres)) {
645         VARIANT v;
646
647         V_VT(&v) = VT_DISPATCH;
648         V_DISPATCH(&v) = val;
649         hres = disp_propput(ctx->script, obj, id, &v);
650     }
651
652     if(val)
653         IDispatch_Release(val);
654     IDispatch_Release(obj);
655     return hres;
656 }
657
658 static HRESULT interp_const(exec_ctx_t *ctx)
659 {
660     BSTR arg = ctx->instr->arg1.bstr;
661     variant_val_t val;
662     ref_t ref;
663     HRESULT hres;
664
665     TRACE("%s\n", debugstr_w(arg));
666
667     assert(ctx->func->type == FUNC_GLOBAL);
668
669     hres = lookup_identifier(ctx, arg, VBDISP_CALLGET, &ref);
670     if(FAILED(hres))
671         return hres;
672
673     if(ref.type != REF_NONE) {
674         FIXME("%s already defined\n", debugstr_w(arg));
675         return E_FAIL;
676     }
677
678     hres = stack_pop_val(ctx, &val);
679     if(FAILED(hres))
680         return hres;
681
682     return add_dynamic_var(ctx, arg, TRUE, val.v, val.owned);
683 }
684
685 static HRESULT interp_new(exec_ctx_t *ctx)
686 {
687     const WCHAR *arg = ctx->instr->arg1.bstr;
688     class_desc_t *class_desc;
689     vbdisp_t *obj;
690     VARIANT v;
691     HRESULT hres;
692
693     TRACE("%s\n", debugstr_w(arg));
694
695     for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
696         if(!strcmpiW(class_desc->name, arg))
697             break;
698     }
699     if(!class_desc) {
700         FIXME("Class %s not found\n", debugstr_w(arg));
701         return E_FAIL;
702     }
703
704     hres = create_vbdisp(class_desc, &obj);
705     if(FAILED(hres))
706         return hres;
707
708     V_VT(&v) = VT_DISPATCH;
709     V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
710     return stack_push(ctx, &v);
711 }
712
713 static HRESULT interp_jmp(exec_ctx_t *ctx)
714 {
715     const unsigned arg = ctx->instr->arg1.uint;
716
717     TRACE("%u\n", arg);
718
719     instr_jmp(ctx, arg);
720     return S_OK;
721 }
722
723 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
724 {
725     const unsigned arg = ctx->instr->arg1.uint;
726     variant_val_t val;
727     HRESULT hres;
728
729     TRACE("%u\n", arg);
730
731     hres = stack_pop_val(ctx, &val);
732     if(FAILED(hres))
733         return hres;
734
735     if(V_VT(val.v) != VT_BOOL) {
736         FIXME("unsupported for %s\n", debugstr_variant(val.v));
737         release_val(&val);
738         return E_NOTIMPL;
739     }
740
741     if(V_BOOL(val.v))
742         ctx->instr++;
743     else
744         instr_jmp(ctx, ctx->instr->arg1.uint);
745     return S_OK;
746 }
747
748 static HRESULT interp_jmp_true(exec_ctx_t *ctx)
749 {
750     const unsigned arg = ctx->instr->arg1.uint;
751     variant_val_t val;
752     HRESULT hres;
753
754     TRACE("%u\n", arg);
755
756     hres = stack_pop_val(ctx, &val);
757     if(FAILED(hres))
758         return hres;
759
760     if(V_VT(val.v) != VT_BOOL) {
761         FIXME("unsupported for %s\n", debugstr_variant(val.v));
762         release_val(&val);
763         return E_NOTIMPL;
764     }
765
766     if(V_BOOL(val.v))
767         instr_jmp(ctx, ctx->instr->arg1.uint);
768     else
769         ctx->instr++;
770     return S_OK;
771 }
772
773 static HRESULT interp_ret(exec_ctx_t *ctx)
774 {
775     TRACE("\n");
776
777     ctx->instr = NULL;
778     return S_OK;
779 }
780
781 static HRESULT interp_stop(exec_ctx_t *ctx)
782 {
783     WARN("\n");
784
785     /* NOTE: this should have effect in debugging mode (that we don't support yet) */
786     return S_OK;
787 }
788
789 static HRESULT interp_me(exec_ctx_t *ctx)
790 {
791     VARIANT v;
792
793     TRACE("\n");
794
795     IDispatch_AddRef(ctx->this_obj);
796     V_VT(&v) = VT_DISPATCH;
797     V_DISPATCH(&v) = ctx->this_obj;
798     return stack_push(ctx, &v);
799 }
800
801 static HRESULT interp_bool(exec_ctx_t *ctx)
802 {
803     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
804     VARIANT v;
805
806     TRACE("%s\n", arg ? "true" : "false");
807
808     V_VT(&v) = VT_BOOL;
809     V_BOOL(&v) = arg;
810     return stack_push(ctx, &v);
811 }
812
813 static HRESULT interp_errmode(exec_ctx_t *ctx)
814 {
815     const int err_mode = ctx->instr->arg1.uint;
816     FIXME("%d\n", err_mode);
817     return E_NOTIMPL;
818 }
819
820 static HRESULT interp_string(exec_ctx_t *ctx)
821 {
822     VARIANT v;
823
824     TRACE("\n");
825
826     V_VT(&v) = VT_BSTR;
827     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
828     if(!V_BSTR(&v))
829         return E_OUTOFMEMORY;
830
831     return stack_push(ctx, &v);
832 }
833
834 static HRESULT interp_long(exec_ctx_t *ctx)
835 {
836     const LONG arg = ctx->instr->arg1.lng;
837     VARIANT v;
838
839     TRACE("%d\n", arg);
840
841     V_VT(&v) = VT_I4;
842     V_I4(&v) = arg;
843     return stack_push(ctx, &v);
844 }
845
846 static HRESULT interp_short(exec_ctx_t *ctx)
847 {
848     const LONG arg = ctx->instr->arg1.lng;
849     VARIANT v;
850
851     TRACE("%d\n", arg);
852
853     V_VT(&v) = VT_I2;
854     V_I2(&v) = arg;
855     return stack_push(ctx, &v);
856 }
857
858 static HRESULT interp_double(exec_ctx_t *ctx)
859 {
860     const DOUBLE *arg = ctx->instr->arg1.dbl;
861     VARIANT v;
862
863     TRACE("%lf\n", *arg);
864
865     V_VT(&v) = VT_R8;
866     V_R8(&v) = *arg;
867     return stack_push(ctx, &v);
868 }
869
870 static HRESULT interp_empty(exec_ctx_t *ctx)
871 {
872     VARIANT v;
873
874     TRACE("\n");
875
876     V_VT(&v) = VT_EMPTY;
877     return stack_push(ctx, &v);
878 }
879
880 static HRESULT interp_null(exec_ctx_t *ctx)
881 {
882     VARIANT v;
883
884     TRACE("\n");
885
886     V_VT(&v) = VT_NULL;
887     return stack_push(ctx, &v);
888 }
889
890 static HRESULT interp_nothing(exec_ctx_t *ctx)
891 {
892     VARIANT v;
893
894     TRACE("\n");
895
896     V_VT(&v) = VT_DISPATCH;
897     V_DISPATCH(&v) = NULL;
898     return stack_push(ctx, &v);
899 }
900
901 static HRESULT interp_not(exec_ctx_t *ctx)
902 {
903     variant_val_t val;
904     VARIANT v;
905     HRESULT hres;
906
907     TRACE("\n");
908
909     hres = stack_pop_val(ctx, &val);
910     if(FAILED(hres))
911         return hres;
912
913     hres = VarNot(val.v, &v);
914     release_val(&val);
915     if(FAILED(hres))
916         return hres;
917
918     return stack_push(ctx, &v);
919 }
920
921 static HRESULT interp_and(exec_ctx_t *ctx)
922 {
923     variant_val_t r, l;
924     VARIANT v;
925     HRESULT hres;
926
927     TRACE("\n");
928
929     hres = stack_pop_val(ctx, &r);
930     if(FAILED(hres))
931         return hres;
932
933     hres = stack_pop_val(ctx, &l);
934     if(SUCCEEDED(hres)) {
935         hres = VarAnd(l.v, r.v, &v);
936         release_val(&l);
937     }
938     release_val(&r);
939     if(FAILED(hres))
940         return hres;
941
942     return stack_push(ctx, &v);
943 }
944
945 static HRESULT interp_or(exec_ctx_t *ctx)
946 {
947     variant_val_t r, l;
948     VARIANT v;
949     HRESULT hres;
950
951     TRACE("\n");
952
953     hres = stack_pop_val(ctx, &r);
954     if(FAILED(hres))
955         return hres;
956
957     hres = stack_pop_val(ctx, &l);
958     if(SUCCEEDED(hres)) {
959         hres = VarOr(l.v, r.v, &v);
960         release_val(&l);
961     }
962     release_val(&r);
963     if(FAILED(hres))
964         return hres;
965
966     return stack_push(ctx, &v);
967 }
968
969 static HRESULT interp_xor(exec_ctx_t *ctx)
970 {
971     variant_val_t r, l;
972     VARIANT v;
973     HRESULT hres;
974
975     TRACE("\n");
976
977     hres = stack_pop_val(ctx, &r);
978     if(FAILED(hres))
979         return hres;
980
981     hres = stack_pop_val(ctx, &l);
982     if(SUCCEEDED(hres)) {
983         hres = VarXor(l.v, r.v, &v);
984         release_val(&l);
985     }
986     release_val(&r);
987     if(FAILED(hres))
988         return hres;
989
990     return stack_push(ctx, &v);
991 }
992
993 static HRESULT interp_eqv(exec_ctx_t *ctx)
994 {
995     variant_val_t r, l;
996     VARIANT v;
997     HRESULT hres;
998
999     TRACE("\n");
1000
1001     hres = stack_pop_val(ctx, &r);
1002     if(FAILED(hres))
1003         return hres;
1004
1005     hres = stack_pop_val(ctx, &l);
1006     if(SUCCEEDED(hres)) {
1007         hres = VarEqv(l.v, r.v, &v);
1008         release_val(&l);
1009     }
1010     release_val(&r);
1011     if(FAILED(hres))
1012         return hres;
1013
1014     return stack_push(ctx, &v);
1015 }
1016
1017 static HRESULT interp_imp(exec_ctx_t *ctx)
1018 {
1019     variant_val_t r, l;
1020     VARIANT v;
1021     HRESULT hres;
1022
1023     TRACE("\n");
1024
1025     hres = stack_pop_val(ctx, &r);
1026     if(FAILED(hres))
1027         return hres;
1028
1029     hres = stack_pop_val(ctx, &l);
1030     if(SUCCEEDED(hres)) {
1031         hres = VarImp(l.v, r.v, &v);
1032         release_val(&l);
1033     }
1034     release_val(&r);
1035     if(FAILED(hres))
1036         return hres;
1037
1038     return stack_push(ctx, &v);
1039 }
1040
1041 static HRESULT cmp_oper(exec_ctx_t *ctx)
1042 {
1043     variant_val_t l, r;
1044     HRESULT hres;
1045
1046     hres = stack_pop_val(ctx, &r);
1047     if(FAILED(hres))
1048         return hres;
1049
1050     hres = stack_pop_val(ctx, &l);
1051     if(SUCCEEDED(hres)) {
1052         if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
1053             FIXME("comparing nulls is not implemented\n");
1054             hres = E_NOTIMPL;
1055         }else {
1056             hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
1057         }
1058     }
1059
1060     release_val(&r);
1061     release_val(&l);
1062     return hres;
1063 }
1064
1065 static HRESULT interp_equal(exec_ctx_t *ctx)
1066 {
1067     VARIANT v;
1068     HRESULT hres;
1069
1070     TRACE("\n");
1071
1072     hres = cmp_oper(ctx);
1073     if(FAILED(hres))
1074         return hres;
1075
1076     V_VT(&v) = VT_BOOL;
1077     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1078     return stack_push(ctx, &v);
1079 }
1080
1081 static HRESULT interp_nequal(exec_ctx_t *ctx)
1082 {
1083     VARIANT v;
1084     HRESULT hres;
1085
1086     TRACE("\n");
1087
1088     hres = cmp_oper(ctx);
1089     if(FAILED(hres))
1090         return hres;
1091
1092     V_VT(&v) = VT_BOOL;
1093     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1094     return stack_push(ctx, &v);
1095 }
1096
1097 static HRESULT interp_gt(exec_ctx_t *ctx)
1098 {
1099     VARIANT v;
1100     HRESULT hres;
1101
1102     TRACE("\n");
1103
1104     hres = cmp_oper(ctx);
1105     if(FAILED(hres))
1106         return hres;
1107
1108     V_VT(&v) = VT_BOOL;
1109     V_BOOL(&v) = hres == VARCMP_GT ? VARIANT_TRUE : VARIANT_FALSE;
1110     return stack_push(ctx, &v);
1111 }
1112
1113 static HRESULT interp_gteq(exec_ctx_t *ctx)
1114 {
1115     VARIANT v;
1116     HRESULT hres;
1117
1118     TRACE("\n");
1119
1120     hres = cmp_oper(ctx);
1121     if(FAILED(hres))
1122         return hres;
1123
1124     V_VT(&v) = VT_BOOL;
1125     V_BOOL(&v) = hres == VARCMP_GT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1126     return stack_push(ctx, &v);
1127 }
1128
1129 static HRESULT interp_lt(exec_ctx_t *ctx)
1130 {
1131     VARIANT v;
1132     HRESULT hres;
1133
1134     TRACE("\n");
1135
1136     hres = cmp_oper(ctx);
1137     if(FAILED(hres))
1138         return hres;
1139
1140     V_VT(&v) = VT_BOOL;
1141     V_BOOL(&v) = hres == VARCMP_LT ? VARIANT_TRUE : VARIANT_FALSE;
1142     return stack_push(ctx, &v);
1143 }
1144
1145 static HRESULT interp_lteq(exec_ctx_t *ctx)
1146 {
1147     VARIANT v;
1148     HRESULT hres;
1149
1150     TRACE("\n");
1151
1152     hres = cmp_oper(ctx);
1153     if(FAILED(hres))
1154         return hres;
1155
1156     V_VT(&v) = VT_BOOL;
1157     V_BOOL(&v) = hres == VARCMP_LT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1158     return stack_push(ctx, &v);
1159 }
1160
1161 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, VARIANT_BOOL *ret)
1162 {
1163     IObjectIdentity *identity;
1164     IUnknown *unk1, *unk2;
1165     HRESULT hres;
1166
1167     if(disp1 == disp2) {
1168         *ret = VARIANT_TRUE;
1169         return S_OK;
1170     }
1171
1172     if(!disp1 || !disp2) {
1173         *ret = VARIANT_FALSE;
1174         return S_OK;
1175     }
1176
1177     hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
1178     if(FAILED(hres))
1179         return hres;
1180
1181     hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
1182     if(FAILED(hres)) {
1183         IUnknown_Release(unk1);
1184         return hres;
1185     }
1186
1187     if(unk1 == unk2) {
1188         *ret = VARIANT_TRUE;
1189     }else {
1190         hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
1191         if(SUCCEEDED(hres)) {
1192             hres = IObjectIdentity_IsEqualObject(identity, unk2);
1193             IObjectIdentity_Release(identity);
1194             *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
1195         }else {
1196             *ret = VARIANT_FALSE;
1197         }
1198     }
1199
1200     IUnknown_Release(unk1);
1201     IUnknown_Release(unk2);
1202     return S_OK;
1203 }
1204
1205 static HRESULT interp_is(exec_ctx_t *ctx)
1206 {
1207     IDispatch *l, *r;
1208     VARIANT v;
1209     HRESULT hres;
1210
1211     TRACE("\n");
1212
1213     hres = stack_pop_disp(ctx, &r);
1214     if(FAILED(hres))
1215         return hres;
1216
1217     hres = stack_pop_disp(ctx, &l);
1218     if(SUCCEEDED(hres)) {
1219         V_VT(&v) = VT_BOOL;
1220         hres = disp_cmp(l, r, &V_BOOL(&v));
1221         if(l)
1222             IDispatch_Release(l);
1223     }
1224     if(r)
1225         IDispatch_Release(r);
1226     if(FAILED(hres))
1227         return hres;
1228
1229     return stack_push(ctx, &v);
1230 }
1231
1232 static HRESULT interp_concat(exec_ctx_t *ctx)
1233 {
1234     variant_val_t r, l;
1235     VARIANT v;
1236     HRESULT hres;
1237
1238     TRACE("\n");
1239
1240     hres = stack_pop_val(ctx, &r);
1241     if(FAILED(hres))
1242         return hres;
1243
1244     hres = stack_pop_val(ctx, &l);
1245     if(SUCCEEDED(hres)) {
1246         hres = VarCat(l.v, r.v, &v);
1247         release_val(&l);
1248     }
1249     release_val(&r);
1250     if(FAILED(hres))
1251         return hres;
1252
1253     return stack_push(ctx, &v);
1254 }
1255
1256 static HRESULT interp_add(exec_ctx_t *ctx)
1257 {
1258     variant_val_t r, l;
1259     VARIANT v;
1260     HRESULT hres;
1261
1262     TRACE("\n");
1263
1264     hres = stack_pop_val(ctx, &r);
1265     if(FAILED(hres))
1266         return hres;
1267
1268     hres = stack_pop_val(ctx, &l);
1269     if(SUCCEEDED(hres)) {
1270         hres = VarAdd(l.v, r.v, &v);
1271         release_val(&l);
1272     }
1273     release_val(&r);
1274     if(FAILED(hres))
1275         return hres;
1276
1277     return stack_push(ctx, &v);
1278 }
1279
1280 static HRESULT interp_sub(exec_ctx_t *ctx)
1281 {
1282     variant_val_t r, l;
1283     VARIANT v;
1284     HRESULT hres;
1285
1286     TRACE("\n");
1287
1288     hres = stack_pop_val(ctx, &r);
1289     if(FAILED(hres))
1290         return hres;
1291
1292     hres = stack_pop_val(ctx, &l);
1293     if(SUCCEEDED(hres)) {
1294         hres = VarSub(l.v, r.v, &v);
1295         release_val(&l);
1296     }
1297     release_val(&r);
1298     if(FAILED(hres))
1299         return hres;
1300
1301     return stack_push(ctx, &v);
1302 }
1303
1304 static HRESULT interp_mod(exec_ctx_t *ctx)
1305 {
1306     variant_val_t r, l;
1307     VARIANT v;
1308     HRESULT hres;
1309
1310     TRACE("\n");
1311
1312     hres = stack_pop_val(ctx, &r);
1313     if(FAILED(hres))
1314         return hres;
1315
1316     hres = stack_pop_val(ctx, &l);
1317     if(SUCCEEDED(hres)) {
1318         hres = VarMod(l.v, r.v, &v);
1319         release_val(&l);
1320     }
1321     release_val(&r);
1322     if(FAILED(hres))
1323         return hres;
1324
1325     return stack_push(ctx, &v);
1326 }
1327
1328 static HRESULT interp_idiv(exec_ctx_t *ctx)
1329 {
1330     variant_val_t r, l;
1331     VARIANT v;
1332     HRESULT hres;
1333
1334     TRACE("\n");
1335
1336     hres = stack_pop_val(ctx, &r);
1337     if(FAILED(hres))
1338         return hres;
1339
1340     hres = stack_pop_val(ctx, &l);
1341     if(SUCCEEDED(hres)) {
1342         hres = VarIdiv(l.v, r.v, &v);
1343         release_val(&l);
1344     }
1345     release_val(&r);
1346     if(FAILED(hres))
1347         return hres;
1348
1349     return stack_push(ctx, &v);
1350 }
1351
1352 static HRESULT interp_div(exec_ctx_t *ctx)
1353 {
1354     variant_val_t r, l;
1355     VARIANT v;
1356     HRESULT hres;
1357
1358     TRACE("\n");
1359
1360     hres = stack_pop_val(ctx, &r);
1361     if(FAILED(hres))
1362         return hres;
1363
1364     hres = stack_pop_val(ctx, &l);
1365     if(SUCCEEDED(hres)) {
1366         hres = VarDiv(l.v, r.v, &v);
1367         release_val(&l);
1368     }
1369     release_val(&r);
1370     if(FAILED(hres))
1371         return hres;
1372
1373     return stack_push(ctx, &v);
1374 }
1375
1376 static HRESULT interp_mul(exec_ctx_t *ctx)
1377 {
1378     variant_val_t r, l;
1379     VARIANT v;
1380     HRESULT hres;
1381
1382     TRACE("\n");
1383
1384     hres = stack_pop_val(ctx, &r);
1385     if(FAILED(hres))
1386         return hres;
1387
1388     hres = stack_pop_val(ctx, &l);
1389     if(SUCCEEDED(hres)) {
1390         hres = VarMul(l.v, r.v, &v);
1391         release_val(&l);
1392     }
1393     release_val(&r);
1394     if(FAILED(hres))
1395         return hres;
1396
1397     return stack_push(ctx, &v);
1398 }
1399
1400 static HRESULT interp_exp(exec_ctx_t *ctx)
1401 {
1402     variant_val_t r, l;
1403     VARIANT v;
1404     HRESULT hres;
1405
1406     TRACE("\n");
1407
1408     hres = stack_pop_val(ctx, &r);
1409     if(FAILED(hres))
1410         return hres;
1411
1412     hres = stack_pop_val(ctx, &l);
1413     if(SUCCEEDED(hres)) {
1414         hres = VarPow(l.v, r.v, &v);
1415         release_val(&l);
1416     }
1417     release_val(&r);
1418     if(FAILED(hres))
1419         return hres;
1420
1421     return stack_push(ctx, &v);
1422 }
1423
1424 static HRESULT interp_neg(exec_ctx_t *ctx)
1425 {
1426     variant_val_t val;
1427     VARIANT v;
1428     HRESULT hres;
1429
1430     hres = stack_pop_val(ctx, &val);
1431     if(FAILED(hres))
1432         return hres;
1433
1434     hres = VarNeg(val.v, &v);
1435     release_val(&val);
1436     if(FAILED(hres))
1437         return hres;
1438
1439     return stack_push(ctx, &v);
1440 }
1441
1442 static const instr_func_t op_funcs[] = {
1443 #define X(x,n,a,b) interp_ ## x,
1444 OP_LIST
1445 #undef X
1446 };
1447
1448 static const unsigned op_move[] = {
1449 #define X(x,n,a,b) n,
1450 OP_LIST
1451 #undef X
1452 };
1453
1454 static void release_exec(exec_ctx_t *ctx)
1455 {
1456     unsigned i;
1457
1458     VariantClear(&ctx->ret_val);
1459
1460     if(ctx->this_obj)
1461         IDispatch_Release(ctx->this_obj);
1462
1463     if(ctx->args) {
1464         for(i=0; i < ctx->func->arg_cnt; i++)
1465             VariantClear(ctx->args+i);
1466     }
1467
1468     if(ctx->vars) {
1469         for(i=0; i < ctx->func->var_cnt; i++)
1470             VariantClear(ctx->vars+i);
1471     }
1472
1473     vbsheap_free(&ctx->heap);
1474     heap_free(ctx->args);
1475     heap_free(ctx->vars);
1476     heap_free(ctx->stack);
1477 }
1478
1479 HRESULT exec_script(script_ctx_t *ctx, function_t *func, IDispatch *this_obj, DISPPARAMS *dp, VARIANT *res)
1480 {
1481     exec_ctx_t exec = {func->code_ctx};
1482     vbsop_t op;
1483     HRESULT hres = S_OK;
1484
1485     exec.code = func->code_ctx;
1486
1487     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
1488         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
1489         return E_FAIL;
1490     }
1491
1492     vbsheap_init(&exec.heap);
1493
1494     if(func->arg_cnt) {
1495         VARIANT *v;
1496         unsigned i;
1497
1498         exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
1499         if(!exec.args) {
1500             release_exec(&exec);
1501             return E_OUTOFMEMORY;
1502         }
1503
1504         for(i=0; i < func->arg_cnt; i++) {
1505             v = get_arg(dp, i);
1506             if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
1507                 if(func->args[i].by_ref)
1508                     exec.args[i] = *v;
1509                 else
1510                     hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
1511             }else {
1512                 hres = VariantCopy(exec.args+i, v);
1513             }
1514             if(FAILED(hres)) {
1515                 release_exec(&exec);
1516                 return hres;
1517             }
1518         }
1519     }else {
1520         exec.args = NULL;
1521     }
1522
1523     if(func->var_cnt) {
1524         exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
1525         if(!exec.vars) {
1526             release_exec(&exec);
1527             return E_OUTOFMEMORY;
1528         }
1529     }else {
1530         exec.vars = NULL;
1531     }
1532
1533     exec.stack_size = 16;
1534     exec.top = 0;
1535     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
1536     if(!exec.stack) {
1537         release_exec(&exec);
1538         return E_OUTOFMEMORY;
1539     }
1540
1541     if(this_obj)
1542         exec.this_obj = this_obj;
1543     else if (ctx->host_global)
1544         exec.this_obj = ctx->host_global;
1545     else
1546         exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface;
1547     IDispatch_AddRef(exec.this_obj);
1548
1549     exec.instr = exec.code->instrs + func->code_off;
1550     exec.script = ctx;
1551     exec.func = func;
1552
1553     while(exec.instr) {
1554         op = exec.instr->op;
1555         hres = op_funcs[op](&exec);
1556         if(FAILED(hres)) {
1557             FIXME("Failed %08x\n", hres);
1558             stack_popn(&exec, exec.top);
1559             break;
1560         }
1561
1562         exec.instr += op_move[op];
1563     }
1564
1565     assert(!exec.top);
1566     if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)
1567         assert(V_VT(&exec.ret_val) == VT_EMPTY);
1568
1569     if(SUCCEEDED(hres) && res) {
1570         *res = exec.ret_val;
1571         V_VT(&exec.ret_val) = VT_EMPTY;
1572     }
1573
1574     release_exec(&exec);
1575     return hres;
1576 }