vbscript: Added for..to statement compiler implementation.
[wine] / dlls / vbscript / interp.c
1 /*
2  * Copyright 2011 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <assert.h>
20
21 #include "vbscript.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
26
27 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_val(exec_ctx_t *ctx)
686 {
687     FIXME("\n");
688     return E_NOTIMPL;
689 }
690
691 static HRESULT interp_pop(exec_ctx_t *ctx)
692 {
693     const unsigned n = ctx->instr->arg1.uint;
694
695     TRACE("%u\n", n);
696
697     stack_popn(ctx, n);
698     return S_OK;
699 }
700
701 static HRESULT interp_new(exec_ctx_t *ctx)
702 {
703     const WCHAR *arg = ctx->instr->arg1.bstr;
704     class_desc_t *class_desc;
705     vbdisp_t *obj;
706     VARIANT v;
707     HRESULT hres;
708
709     TRACE("%s\n", debugstr_w(arg));
710
711     for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
712         if(!strcmpiW(class_desc->name, arg))
713             break;
714     }
715     if(!class_desc) {
716         FIXME("Class %s not found\n", debugstr_w(arg));
717         return E_FAIL;
718     }
719
720     hres = create_vbdisp(class_desc, &obj);
721     if(FAILED(hres))
722         return hres;
723
724     V_VT(&v) = VT_DISPATCH;
725     V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
726     return stack_push(ctx, &v);
727 }
728
729 static HRESULT interp_step(exec_ctx_t *ctx)
730 {
731     const BSTR ident = ctx->instr->arg2.bstr;
732     FIXME("%s\n", debugstr_w(ident));
733     return E_NOTIMPL;
734 }
735
736 static HRESULT interp_jmp(exec_ctx_t *ctx)
737 {
738     const unsigned arg = ctx->instr->arg1.uint;
739
740     TRACE("%u\n", arg);
741
742     instr_jmp(ctx, arg);
743     return S_OK;
744 }
745
746 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
747 {
748     const unsigned arg = ctx->instr->arg1.uint;
749     variant_val_t val;
750     HRESULT hres;
751
752     TRACE("%u\n", arg);
753
754     hres = stack_pop_val(ctx, &val);
755     if(FAILED(hres))
756         return hres;
757
758     if(V_VT(val.v) != VT_BOOL) {
759         FIXME("unsupported for %s\n", debugstr_variant(val.v));
760         release_val(&val);
761         return E_NOTIMPL;
762     }
763
764     if(V_BOOL(val.v))
765         ctx->instr++;
766     else
767         instr_jmp(ctx, ctx->instr->arg1.uint);
768     return S_OK;
769 }
770
771 static HRESULT interp_jmp_true(exec_ctx_t *ctx)
772 {
773     const unsigned arg = ctx->instr->arg1.uint;
774     variant_val_t val;
775     HRESULT hres;
776
777     TRACE("%u\n", arg);
778
779     hres = stack_pop_val(ctx, &val);
780     if(FAILED(hres))
781         return hres;
782
783     if(V_VT(val.v) != VT_BOOL) {
784         FIXME("unsupported for %s\n", debugstr_variant(val.v));
785         release_val(&val);
786         return E_NOTIMPL;
787     }
788
789     if(V_BOOL(val.v))
790         instr_jmp(ctx, ctx->instr->arg1.uint);
791     else
792         ctx->instr++;
793     return S_OK;
794 }
795
796 static HRESULT interp_ret(exec_ctx_t *ctx)
797 {
798     TRACE("\n");
799
800     ctx->instr = NULL;
801     return S_OK;
802 }
803
804 static HRESULT interp_stop(exec_ctx_t *ctx)
805 {
806     WARN("\n");
807
808     /* NOTE: this should have effect in debugging mode (that we don't support yet) */
809     return S_OK;
810 }
811
812 static HRESULT interp_me(exec_ctx_t *ctx)
813 {
814     VARIANT v;
815
816     TRACE("\n");
817
818     IDispatch_AddRef(ctx->this_obj);
819     V_VT(&v) = VT_DISPATCH;
820     V_DISPATCH(&v) = ctx->this_obj;
821     return stack_push(ctx, &v);
822 }
823
824 static HRESULT interp_bool(exec_ctx_t *ctx)
825 {
826     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
827     VARIANT v;
828
829     TRACE("%s\n", arg ? "true" : "false");
830
831     V_VT(&v) = VT_BOOL;
832     V_BOOL(&v) = arg;
833     return stack_push(ctx, &v);
834 }
835
836 static HRESULT interp_errmode(exec_ctx_t *ctx)
837 {
838     const int err_mode = ctx->instr->arg1.uint;
839     FIXME("%d\n", err_mode);
840     return E_NOTIMPL;
841 }
842
843 static HRESULT interp_string(exec_ctx_t *ctx)
844 {
845     VARIANT v;
846
847     TRACE("\n");
848
849     V_VT(&v) = VT_BSTR;
850     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
851     if(!V_BSTR(&v))
852         return E_OUTOFMEMORY;
853
854     return stack_push(ctx, &v);
855 }
856
857 static HRESULT interp_long(exec_ctx_t *ctx)
858 {
859     const LONG arg = ctx->instr->arg1.lng;
860     VARIANT v;
861
862     TRACE("%d\n", arg);
863
864     V_VT(&v) = VT_I4;
865     V_I4(&v) = arg;
866     return stack_push(ctx, &v);
867 }
868
869 static HRESULT interp_short(exec_ctx_t *ctx)
870 {
871     const LONG arg = ctx->instr->arg1.lng;
872     VARIANT v;
873
874     TRACE("%d\n", arg);
875
876     V_VT(&v) = VT_I2;
877     V_I2(&v) = arg;
878     return stack_push(ctx, &v);
879 }
880
881 static HRESULT interp_double(exec_ctx_t *ctx)
882 {
883     const DOUBLE *arg = ctx->instr->arg1.dbl;
884     VARIANT v;
885
886     TRACE("%lf\n", *arg);
887
888     V_VT(&v) = VT_R8;
889     V_R8(&v) = *arg;
890     return stack_push(ctx, &v);
891 }
892
893 static HRESULT interp_empty(exec_ctx_t *ctx)
894 {
895     VARIANT v;
896
897     TRACE("\n");
898
899     V_VT(&v) = VT_EMPTY;
900     return stack_push(ctx, &v);
901 }
902
903 static HRESULT interp_null(exec_ctx_t *ctx)
904 {
905     VARIANT v;
906
907     TRACE("\n");
908
909     V_VT(&v) = VT_NULL;
910     return stack_push(ctx, &v);
911 }
912
913 static HRESULT interp_nothing(exec_ctx_t *ctx)
914 {
915     VARIANT v;
916
917     TRACE("\n");
918
919     V_VT(&v) = VT_DISPATCH;
920     V_DISPATCH(&v) = NULL;
921     return stack_push(ctx, &v);
922 }
923
924 static HRESULT interp_not(exec_ctx_t *ctx)
925 {
926     variant_val_t val;
927     VARIANT v;
928     HRESULT hres;
929
930     TRACE("\n");
931
932     hres = stack_pop_val(ctx, &val);
933     if(FAILED(hres))
934         return hres;
935
936     hres = VarNot(val.v, &v);
937     release_val(&val);
938     if(FAILED(hres))
939         return hres;
940
941     return stack_push(ctx, &v);
942 }
943
944 static HRESULT interp_and(exec_ctx_t *ctx)
945 {
946     variant_val_t r, l;
947     VARIANT v;
948     HRESULT hres;
949
950     TRACE("\n");
951
952     hres = stack_pop_val(ctx, &r);
953     if(FAILED(hres))
954         return hres;
955
956     hres = stack_pop_val(ctx, &l);
957     if(SUCCEEDED(hres)) {
958         hres = VarAnd(l.v, r.v, &v);
959         release_val(&l);
960     }
961     release_val(&r);
962     if(FAILED(hres))
963         return hres;
964
965     return stack_push(ctx, &v);
966 }
967
968 static HRESULT interp_or(exec_ctx_t *ctx)
969 {
970     variant_val_t r, l;
971     VARIANT v;
972     HRESULT hres;
973
974     TRACE("\n");
975
976     hres = stack_pop_val(ctx, &r);
977     if(FAILED(hres))
978         return hres;
979
980     hres = stack_pop_val(ctx, &l);
981     if(SUCCEEDED(hres)) {
982         hres = VarOr(l.v, r.v, &v);
983         release_val(&l);
984     }
985     release_val(&r);
986     if(FAILED(hres))
987         return hres;
988
989     return stack_push(ctx, &v);
990 }
991
992 static HRESULT interp_xor(exec_ctx_t *ctx)
993 {
994     variant_val_t r, l;
995     VARIANT v;
996     HRESULT hres;
997
998     TRACE("\n");
999
1000     hres = stack_pop_val(ctx, &r);
1001     if(FAILED(hres))
1002         return hres;
1003
1004     hres = stack_pop_val(ctx, &l);
1005     if(SUCCEEDED(hres)) {
1006         hres = VarXor(l.v, r.v, &v);
1007         release_val(&l);
1008     }
1009     release_val(&r);
1010     if(FAILED(hres))
1011         return hres;
1012
1013     return stack_push(ctx, &v);
1014 }
1015
1016 static HRESULT interp_eqv(exec_ctx_t *ctx)
1017 {
1018     variant_val_t r, l;
1019     VARIANT v;
1020     HRESULT hres;
1021
1022     TRACE("\n");
1023
1024     hres = stack_pop_val(ctx, &r);
1025     if(FAILED(hres))
1026         return hres;
1027
1028     hres = stack_pop_val(ctx, &l);
1029     if(SUCCEEDED(hres)) {
1030         hres = VarEqv(l.v, r.v, &v);
1031         release_val(&l);
1032     }
1033     release_val(&r);
1034     if(FAILED(hres))
1035         return hres;
1036
1037     return stack_push(ctx, &v);
1038 }
1039
1040 static HRESULT interp_imp(exec_ctx_t *ctx)
1041 {
1042     variant_val_t r, l;
1043     VARIANT v;
1044     HRESULT hres;
1045
1046     TRACE("\n");
1047
1048     hres = stack_pop_val(ctx, &r);
1049     if(FAILED(hres))
1050         return hres;
1051
1052     hres = stack_pop_val(ctx, &l);
1053     if(SUCCEEDED(hres)) {
1054         hres = VarImp(l.v, r.v, &v);
1055         release_val(&l);
1056     }
1057     release_val(&r);
1058     if(FAILED(hres))
1059         return hres;
1060
1061     return stack_push(ctx, &v);
1062 }
1063
1064 static HRESULT cmp_oper(exec_ctx_t *ctx)
1065 {
1066     variant_val_t l, r;
1067     HRESULT hres;
1068
1069     hres = stack_pop_val(ctx, &r);
1070     if(FAILED(hres))
1071         return hres;
1072
1073     hres = stack_pop_val(ctx, &l);
1074     if(SUCCEEDED(hres)) {
1075         if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
1076             FIXME("comparing nulls is not implemented\n");
1077             hres = E_NOTIMPL;
1078         }else {
1079             hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
1080         }
1081     }
1082
1083     release_val(&r);
1084     release_val(&l);
1085     return hres;
1086 }
1087
1088 static HRESULT interp_equal(exec_ctx_t *ctx)
1089 {
1090     VARIANT v;
1091     HRESULT hres;
1092
1093     TRACE("\n");
1094
1095     hres = cmp_oper(ctx);
1096     if(FAILED(hres))
1097         return hres;
1098
1099     V_VT(&v) = VT_BOOL;
1100     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1101     return stack_push(ctx, &v);
1102 }
1103
1104 static HRESULT interp_nequal(exec_ctx_t *ctx)
1105 {
1106     VARIANT v;
1107     HRESULT hres;
1108
1109     TRACE("\n");
1110
1111     hres = cmp_oper(ctx);
1112     if(FAILED(hres))
1113         return hres;
1114
1115     V_VT(&v) = VT_BOOL;
1116     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1117     return stack_push(ctx, &v);
1118 }
1119
1120 static HRESULT interp_gt(exec_ctx_t *ctx)
1121 {
1122     VARIANT v;
1123     HRESULT hres;
1124
1125     TRACE("\n");
1126
1127     hres = cmp_oper(ctx);
1128     if(FAILED(hres))
1129         return hres;
1130
1131     V_VT(&v) = VT_BOOL;
1132     V_BOOL(&v) = hres == VARCMP_GT ? VARIANT_TRUE : VARIANT_FALSE;
1133     return stack_push(ctx, &v);
1134 }
1135
1136 static HRESULT interp_gteq(exec_ctx_t *ctx)
1137 {
1138     VARIANT v;
1139     HRESULT hres;
1140
1141     TRACE("\n");
1142
1143     hres = cmp_oper(ctx);
1144     if(FAILED(hres))
1145         return hres;
1146
1147     V_VT(&v) = VT_BOOL;
1148     V_BOOL(&v) = hres == VARCMP_GT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1149     return stack_push(ctx, &v);
1150 }
1151
1152 static HRESULT interp_lt(exec_ctx_t *ctx)
1153 {
1154     VARIANT v;
1155     HRESULT hres;
1156
1157     TRACE("\n");
1158
1159     hres = cmp_oper(ctx);
1160     if(FAILED(hres))
1161         return hres;
1162
1163     V_VT(&v) = VT_BOOL;
1164     V_BOOL(&v) = hres == VARCMP_LT ? VARIANT_TRUE : VARIANT_FALSE;
1165     return stack_push(ctx, &v);
1166 }
1167
1168 static HRESULT interp_lteq(exec_ctx_t *ctx)
1169 {
1170     VARIANT v;
1171     HRESULT hres;
1172
1173     TRACE("\n");
1174
1175     hres = cmp_oper(ctx);
1176     if(FAILED(hres))
1177         return hres;
1178
1179     V_VT(&v) = VT_BOOL;
1180     V_BOOL(&v) = hres == VARCMP_LT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1181     return stack_push(ctx, &v);
1182 }
1183
1184 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, VARIANT_BOOL *ret)
1185 {
1186     IObjectIdentity *identity;
1187     IUnknown *unk1, *unk2;
1188     HRESULT hres;
1189
1190     if(disp1 == disp2) {
1191         *ret = VARIANT_TRUE;
1192         return S_OK;
1193     }
1194
1195     if(!disp1 || !disp2) {
1196         *ret = VARIANT_FALSE;
1197         return S_OK;
1198     }
1199
1200     hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
1201     if(FAILED(hres))
1202         return hres;
1203
1204     hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
1205     if(FAILED(hres)) {
1206         IUnknown_Release(unk1);
1207         return hres;
1208     }
1209
1210     if(unk1 == unk2) {
1211         *ret = VARIANT_TRUE;
1212     }else {
1213         hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
1214         if(SUCCEEDED(hres)) {
1215             hres = IObjectIdentity_IsEqualObject(identity, unk2);
1216             IObjectIdentity_Release(identity);
1217             *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
1218         }else {
1219             *ret = VARIANT_FALSE;
1220         }
1221     }
1222
1223     IUnknown_Release(unk1);
1224     IUnknown_Release(unk2);
1225     return S_OK;
1226 }
1227
1228 static HRESULT interp_is(exec_ctx_t *ctx)
1229 {
1230     IDispatch *l, *r;
1231     VARIANT v;
1232     HRESULT hres;
1233
1234     TRACE("\n");
1235
1236     hres = stack_pop_disp(ctx, &r);
1237     if(FAILED(hres))
1238         return hres;
1239
1240     hres = stack_pop_disp(ctx, &l);
1241     if(SUCCEEDED(hres)) {
1242         V_VT(&v) = VT_BOOL;
1243         hres = disp_cmp(l, r, &V_BOOL(&v));
1244         if(l)
1245             IDispatch_Release(l);
1246     }
1247     if(r)
1248         IDispatch_Release(r);
1249     if(FAILED(hres))
1250         return hres;
1251
1252     return stack_push(ctx, &v);
1253 }
1254
1255 static HRESULT interp_concat(exec_ctx_t *ctx)
1256 {
1257     variant_val_t r, l;
1258     VARIANT v;
1259     HRESULT hres;
1260
1261     TRACE("\n");
1262
1263     hres = stack_pop_val(ctx, &r);
1264     if(FAILED(hres))
1265         return hres;
1266
1267     hres = stack_pop_val(ctx, &l);
1268     if(SUCCEEDED(hres)) {
1269         hres = VarCat(l.v, r.v, &v);
1270         release_val(&l);
1271     }
1272     release_val(&r);
1273     if(FAILED(hres))
1274         return hres;
1275
1276     return stack_push(ctx, &v);
1277 }
1278
1279 static HRESULT interp_add(exec_ctx_t *ctx)
1280 {
1281     variant_val_t r, l;
1282     VARIANT v;
1283     HRESULT hres;
1284
1285     TRACE("\n");
1286
1287     hres = stack_pop_val(ctx, &r);
1288     if(FAILED(hres))
1289         return hres;
1290
1291     hres = stack_pop_val(ctx, &l);
1292     if(SUCCEEDED(hres)) {
1293         hres = VarAdd(l.v, r.v, &v);
1294         release_val(&l);
1295     }
1296     release_val(&r);
1297     if(FAILED(hres))
1298         return hres;
1299
1300     return stack_push(ctx, &v);
1301 }
1302
1303 static HRESULT interp_sub(exec_ctx_t *ctx)
1304 {
1305     variant_val_t r, l;
1306     VARIANT v;
1307     HRESULT hres;
1308
1309     TRACE("\n");
1310
1311     hres = stack_pop_val(ctx, &r);
1312     if(FAILED(hres))
1313         return hres;
1314
1315     hres = stack_pop_val(ctx, &l);
1316     if(SUCCEEDED(hres)) {
1317         hres = VarSub(l.v, r.v, &v);
1318         release_val(&l);
1319     }
1320     release_val(&r);
1321     if(FAILED(hres))
1322         return hres;
1323
1324     return stack_push(ctx, &v);
1325 }
1326
1327 static HRESULT interp_mod(exec_ctx_t *ctx)
1328 {
1329     variant_val_t r, l;
1330     VARIANT v;
1331     HRESULT hres;
1332
1333     TRACE("\n");
1334
1335     hres = stack_pop_val(ctx, &r);
1336     if(FAILED(hres))
1337         return hres;
1338
1339     hres = stack_pop_val(ctx, &l);
1340     if(SUCCEEDED(hres)) {
1341         hres = VarMod(l.v, r.v, &v);
1342         release_val(&l);
1343     }
1344     release_val(&r);
1345     if(FAILED(hres))
1346         return hres;
1347
1348     return stack_push(ctx, &v);
1349 }
1350
1351 static HRESULT interp_idiv(exec_ctx_t *ctx)
1352 {
1353     variant_val_t r, l;
1354     VARIANT v;
1355     HRESULT hres;
1356
1357     TRACE("\n");
1358
1359     hres = stack_pop_val(ctx, &r);
1360     if(FAILED(hres))
1361         return hres;
1362
1363     hres = stack_pop_val(ctx, &l);
1364     if(SUCCEEDED(hres)) {
1365         hres = VarIdiv(l.v, r.v, &v);
1366         release_val(&l);
1367     }
1368     release_val(&r);
1369     if(FAILED(hres))
1370         return hres;
1371
1372     return stack_push(ctx, &v);
1373 }
1374
1375 static HRESULT interp_div(exec_ctx_t *ctx)
1376 {
1377     variant_val_t r, l;
1378     VARIANT v;
1379     HRESULT hres;
1380
1381     TRACE("\n");
1382
1383     hres = stack_pop_val(ctx, &r);
1384     if(FAILED(hres))
1385         return hres;
1386
1387     hres = stack_pop_val(ctx, &l);
1388     if(SUCCEEDED(hres)) {
1389         hres = VarDiv(l.v, r.v, &v);
1390         release_val(&l);
1391     }
1392     release_val(&r);
1393     if(FAILED(hres))
1394         return hres;
1395
1396     return stack_push(ctx, &v);
1397 }
1398
1399 static HRESULT interp_mul(exec_ctx_t *ctx)
1400 {
1401     variant_val_t r, l;
1402     VARIANT v;
1403     HRESULT hres;
1404
1405     TRACE("\n");
1406
1407     hres = stack_pop_val(ctx, &r);
1408     if(FAILED(hres))
1409         return hres;
1410
1411     hres = stack_pop_val(ctx, &l);
1412     if(SUCCEEDED(hres)) {
1413         hres = VarMul(l.v, r.v, &v);
1414         release_val(&l);
1415     }
1416     release_val(&r);
1417     if(FAILED(hres))
1418         return hres;
1419
1420     return stack_push(ctx, &v);
1421 }
1422
1423 static HRESULT interp_exp(exec_ctx_t *ctx)
1424 {
1425     variant_val_t r, l;
1426     VARIANT v;
1427     HRESULT hres;
1428
1429     TRACE("\n");
1430
1431     hres = stack_pop_val(ctx, &r);
1432     if(FAILED(hres))
1433         return hres;
1434
1435     hres = stack_pop_val(ctx, &l);
1436     if(SUCCEEDED(hres)) {
1437         hres = VarPow(l.v, r.v, &v);
1438         release_val(&l);
1439     }
1440     release_val(&r);
1441     if(FAILED(hres))
1442         return hres;
1443
1444     return stack_push(ctx, &v);
1445 }
1446
1447 static HRESULT interp_neg(exec_ctx_t *ctx)
1448 {
1449     variant_val_t val;
1450     VARIANT v;
1451     HRESULT hres;
1452
1453     hres = stack_pop_val(ctx, &val);
1454     if(FAILED(hres))
1455         return hres;
1456
1457     hres = VarNeg(val.v, &v);
1458     release_val(&val);
1459     if(FAILED(hres))
1460         return hres;
1461
1462     return stack_push(ctx, &v);
1463 }
1464
1465 static HRESULT interp_incc(exec_ctx_t *ctx)
1466 {
1467     const BSTR ident = ctx->instr->arg1.bstr;
1468     FIXME("%s\n", debugstr_w(ident));
1469     return E_NOTIMPL;
1470 }
1471
1472 static const instr_func_t op_funcs[] = {
1473 #define X(x,n,a,b) interp_ ## x,
1474 OP_LIST
1475 #undef X
1476 };
1477
1478 static const unsigned op_move[] = {
1479 #define X(x,n,a,b) n,
1480 OP_LIST
1481 #undef X
1482 };
1483
1484 static void release_exec(exec_ctx_t *ctx)
1485 {
1486     unsigned i;
1487
1488     VariantClear(&ctx->ret_val);
1489
1490     if(ctx->this_obj)
1491         IDispatch_Release(ctx->this_obj);
1492
1493     if(ctx->args) {
1494         for(i=0; i < ctx->func->arg_cnt; i++)
1495             VariantClear(ctx->args+i);
1496     }
1497
1498     if(ctx->vars) {
1499         for(i=0; i < ctx->func->var_cnt; i++)
1500             VariantClear(ctx->vars+i);
1501     }
1502
1503     vbsheap_free(&ctx->heap);
1504     heap_free(ctx->args);
1505     heap_free(ctx->vars);
1506     heap_free(ctx->stack);
1507 }
1508
1509 HRESULT exec_script(script_ctx_t *ctx, function_t *func, IDispatch *this_obj, DISPPARAMS *dp, VARIANT *res)
1510 {
1511     exec_ctx_t exec = {func->code_ctx};
1512     vbsop_t op;
1513     HRESULT hres = S_OK;
1514
1515     exec.code = func->code_ctx;
1516
1517     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
1518         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
1519         return E_FAIL;
1520     }
1521
1522     vbsheap_init(&exec.heap);
1523
1524     if(func->arg_cnt) {
1525         VARIANT *v;
1526         unsigned i;
1527
1528         exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
1529         if(!exec.args) {
1530             release_exec(&exec);
1531             return E_OUTOFMEMORY;
1532         }
1533
1534         for(i=0; i < func->arg_cnt; i++) {
1535             v = get_arg(dp, i);
1536             if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
1537                 if(func->args[i].by_ref)
1538                     exec.args[i] = *v;
1539                 else
1540                     hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
1541             }else {
1542                 hres = VariantCopy(exec.args+i, v);
1543             }
1544             if(FAILED(hres)) {
1545                 release_exec(&exec);
1546                 return hres;
1547             }
1548         }
1549     }else {
1550         exec.args = NULL;
1551     }
1552
1553     if(func->var_cnt) {
1554         exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
1555         if(!exec.vars) {
1556             release_exec(&exec);
1557             return E_OUTOFMEMORY;
1558         }
1559     }else {
1560         exec.vars = NULL;
1561     }
1562
1563     exec.stack_size = 16;
1564     exec.top = 0;
1565     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
1566     if(!exec.stack) {
1567         release_exec(&exec);
1568         return E_OUTOFMEMORY;
1569     }
1570
1571     if(this_obj)
1572         exec.this_obj = this_obj;
1573     else if (ctx->host_global)
1574         exec.this_obj = ctx->host_global;
1575     else
1576         exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface;
1577     IDispatch_AddRef(exec.this_obj);
1578
1579     exec.instr = exec.code->instrs + func->code_off;
1580     exec.script = ctx;
1581     exec.func = func;
1582
1583     while(exec.instr) {
1584         op = exec.instr->op;
1585         hres = op_funcs[op](&exec);
1586         if(FAILED(hres)) {
1587             FIXME("Failed %08x\n", hres);
1588             stack_popn(&exec, exec.top);
1589             break;
1590         }
1591
1592         exec.instr += op_move[op];
1593     }
1594
1595     assert(!exec.top);
1596     if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)
1597         assert(V_VT(&exec.ret_val) == VT_EMPTY);
1598
1599     if(SUCCEEDED(hres) && res) {
1600         *res = exec.ret_val;
1601         V_VT(&exec.ret_val) = VT_EMPTY;
1602     }
1603
1604     release_exec(&exec);
1605     return hres;
1606 }