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