vbscript: Added ME expression 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     FIXME("\n");
714     return E_NOTIMPL;
715 }
716
717 static HRESULT interp_bool(exec_ctx_t *ctx)
718 {
719     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
720     VARIANT v;
721
722     TRACE("%s\n", arg ? "true" : "false");
723
724     V_VT(&v) = VT_BOOL;
725     V_BOOL(&v) = arg;
726     return stack_push(ctx, &v);
727 }
728
729 static HRESULT interp_string(exec_ctx_t *ctx)
730 {
731     VARIANT v;
732
733     TRACE("\n");
734
735     V_VT(&v) = VT_BSTR;
736     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
737     if(!V_BSTR(&v))
738         return E_OUTOFMEMORY;
739
740     return stack_push(ctx, &v);
741 }
742
743 static HRESULT interp_long(exec_ctx_t *ctx)
744 {
745     const LONG arg = ctx->instr->arg1.lng;
746     VARIANT v;
747
748     TRACE("%d\n", arg);
749
750     V_VT(&v) = VT_I4;
751     V_I4(&v) = arg;
752     return stack_push(ctx, &v);
753 }
754
755 static HRESULT interp_short(exec_ctx_t *ctx)
756 {
757     const LONG arg = ctx->instr->arg1.lng;
758     VARIANT v;
759
760     TRACE("%d\n", arg);
761
762     V_VT(&v) = VT_I2;
763     V_I2(&v) = arg;
764     return stack_push(ctx, &v);
765 }
766
767 static HRESULT interp_double(exec_ctx_t *ctx)
768 {
769     const DOUBLE *arg = ctx->instr->arg1.dbl;
770     VARIANT v;
771
772     TRACE("%lf\n", *arg);
773
774     V_VT(&v) = VT_R8;
775     V_R8(&v) = *arg;
776     return stack_push(ctx, &v);
777 }
778
779 static HRESULT interp_empty(exec_ctx_t *ctx)
780 {
781     VARIANT v;
782
783     TRACE("\n");
784
785     V_VT(&v) = VT_EMPTY;
786     return stack_push(ctx, &v);
787 }
788
789 static HRESULT interp_null(exec_ctx_t *ctx)
790 {
791     VARIANT v;
792
793     TRACE("\n");
794
795     V_VT(&v) = VT_NULL;
796     return stack_push(ctx, &v);
797 }
798
799 static HRESULT interp_nothing(exec_ctx_t *ctx)
800 {
801     VARIANT v;
802
803     TRACE("\n");
804
805     V_VT(&v) = VT_DISPATCH;
806     V_DISPATCH(&v) = NULL;
807     return stack_push(ctx, &v);
808 }
809
810 static HRESULT interp_not(exec_ctx_t *ctx)
811 {
812     variant_val_t val;
813     VARIANT v;
814     HRESULT hres;
815
816     TRACE("\n");
817
818     hres = stack_pop_val(ctx, &val);
819     if(FAILED(hres))
820         return hres;
821
822     hres = VarNot(val.v, &v);
823     release_val(&val);
824     if(FAILED(hres))
825         return hres;
826
827     return stack_push(ctx, &v);
828 }
829
830 static HRESULT interp_and(exec_ctx_t *ctx)
831 {
832     variant_val_t r, l;
833     VARIANT v;
834     HRESULT hres;
835
836     TRACE("\n");
837
838     hres = stack_pop_val(ctx, &r);
839     if(FAILED(hres))
840         return hres;
841
842     hres = stack_pop_val(ctx, &l);
843     if(SUCCEEDED(hres)) {
844         hres = VarAnd(l.v, r.v, &v);
845         release_val(&l);
846     }
847     release_val(&r);
848     if(FAILED(hres))
849         return hres;
850
851     return stack_push(ctx, &v);
852 }
853
854 static HRESULT interp_or(exec_ctx_t *ctx)
855 {
856     variant_val_t r, l;
857     VARIANT v;
858     HRESULT hres;
859
860     TRACE("\n");
861
862     hres = stack_pop_val(ctx, &r);
863     if(FAILED(hres))
864         return hres;
865
866     hres = stack_pop_val(ctx, &l);
867     if(SUCCEEDED(hres)) {
868         hres = VarOr(l.v, r.v, &v);
869         release_val(&l);
870     }
871     release_val(&r);
872     if(FAILED(hres))
873         return hres;
874
875     return stack_push(ctx, &v);
876 }
877
878 static HRESULT interp_xor(exec_ctx_t *ctx)
879 {
880     variant_val_t r, l;
881     VARIANT v;
882     HRESULT hres;
883
884     TRACE("\n");
885
886     hres = stack_pop_val(ctx, &r);
887     if(FAILED(hres))
888         return hres;
889
890     hres = stack_pop_val(ctx, &l);
891     if(SUCCEEDED(hres)) {
892         hres = VarXor(l.v, r.v, &v);
893         release_val(&l);
894     }
895     release_val(&r);
896     if(FAILED(hres))
897         return hres;
898
899     return stack_push(ctx, &v);
900 }
901
902 static HRESULT interp_eqv(exec_ctx_t *ctx)
903 {
904     variant_val_t r, l;
905     VARIANT v;
906     HRESULT hres;
907
908     TRACE("\n");
909
910     hres = stack_pop_val(ctx, &r);
911     if(FAILED(hres))
912         return hres;
913
914     hres = stack_pop_val(ctx, &l);
915     if(SUCCEEDED(hres)) {
916         hres = VarEqv(l.v, r.v, &v);
917         release_val(&l);
918     }
919     release_val(&r);
920     if(FAILED(hres))
921         return hres;
922
923     return stack_push(ctx, &v);
924 }
925
926 static HRESULT interp_imp(exec_ctx_t *ctx)
927 {
928     variant_val_t r, l;
929     VARIANT v;
930     HRESULT hres;
931
932     TRACE("\n");
933
934     hres = stack_pop_val(ctx, &r);
935     if(FAILED(hres))
936         return hres;
937
938     hres = stack_pop_val(ctx, &l);
939     if(SUCCEEDED(hres)) {
940         hres = VarImp(l.v, r.v, &v);
941         release_val(&l);
942     }
943     release_val(&r);
944     if(FAILED(hres))
945         return hres;
946
947     return stack_push(ctx, &v);
948 }
949
950 static HRESULT cmp_oper(exec_ctx_t *ctx)
951 {
952     variant_val_t l, r;
953     HRESULT hres;
954
955     hres = stack_pop_val(ctx, &r);
956     if(FAILED(hres))
957         return hres;
958
959     hres = stack_pop_val(ctx, &l);
960     if(SUCCEEDED(hres)) {
961         if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
962             FIXME("comparing nulls is not implemented\n");
963             hres = E_NOTIMPL;
964         }else {
965             hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
966         }
967     }
968
969     release_val(&r);
970     release_val(&l);
971     return hres;
972 }
973
974 static HRESULT interp_equal(exec_ctx_t *ctx)
975 {
976     VARIANT v;
977     HRESULT hres;
978
979     TRACE("\n");
980
981     hres = cmp_oper(ctx);
982     if(FAILED(hres))
983         return hres;
984
985     V_VT(&v) = VT_BOOL;
986     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
987     return stack_push(ctx, &v);
988 }
989
990 static HRESULT interp_nequal(exec_ctx_t *ctx)
991 {
992     VARIANT v;
993     HRESULT hres;
994
995     TRACE("\n");
996
997     hres = cmp_oper(ctx);
998     if(FAILED(hres))
999         return hres;
1000
1001     V_VT(&v) = VT_BOOL;
1002     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1003     return stack_push(ctx, &v);
1004 }
1005
1006 static HRESULT interp_gt(exec_ctx_t *ctx)
1007 {
1008     VARIANT v;
1009     HRESULT hres;
1010
1011     TRACE("\n");
1012
1013     hres = cmp_oper(ctx);
1014     if(FAILED(hres))
1015         return hres;
1016
1017     V_VT(&v) = VT_BOOL;
1018     V_BOOL(&v) = hres == VARCMP_GT ? VARIANT_TRUE : VARIANT_FALSE;
1019     return stack_push(ctx, &v);
1020 }
1021
1022 static HRESULT interp_gteq(exec_ctx_t *ctx)
1023 {
1024     VARIANT v;
1025     HRESULT hres;
1026
1027     TRACE("\n");
1028
1029     hres = cmp_oper(ctx);
1030     if(FAILED(hres))
1031         return hres;
1032
1033     V_VT(&v) = VT_BOOL;
1034     V_BOOL(&v) = hres == VARCMP_GT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1035     return stack_push(ctx, &v);
1036 }
1037
1038 static HRESULT interp_lt(exec_ctx_t *ctx)
1039 {
1040     VARIANT v;
1041     HRESULT hres;
1042
1043     TRACE("\n");
1044
1045     hres = cmp_oper(ctx);
1046     if(FAILED(hres))
1047         return hres;
1048
1049     V_VT(&v) = VT_BOOL;
1050     V_BOOL(&v) = hres == VARCMP_LT ? VARIANT_TRUE : VARIANT_FALSE;
1051     return stack_push(ctx, &v);
1052 }
1053
1054 static HRESULT interp_lteq(exec_ctx_t *ctx)
1055 {
1056     VARIANT v;
1057     HRESULT hres;
1058
1059     TRACE("\n");
1060
1061     hres = cmp_oper(ctx);
1062     if(FAILED(hres))
1063         return hres;
1064
1065     V_VT(&v) = VT_BOOL;
1066     V_BOOL(&v) = hres == VARCMP_LT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1067     return stack_push(ctx, &v);
1068 }
1069
1070 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, VARIANT_BOOL *ret)
1071 {
1072     IObjectIdentity *identity;
1073     IUnknown *unk1, *unk2;
1074     HRESULT hres;
1075
1076     if(disp1 == disp2) {
1077         *ret = VARIANT_TRUE;
1078         return S_OK;
1079     }
1080
1081     if(!disp1 || !disp2) {
1082         *ret = VARIANT_FALSE;
1083         return S_OK;
1084     }
1085
1086     hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
1087     if(FAILED(hres))
1088         return hres;
1089
1090     hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
1091     if(FAILED(hres)) {
1092         IUnknown_Release(unk1);
1093         return hres;
1094     }
1095
1096     if(unk1 == unk2) {
1097         *ret = VARIANT_TRUE;
1098     }else {
1099         hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
1100         if(SUCCEEDED(hres)) {
1101             hres = IObjectIdentity_IsEqualObject(identity, unk2);
1102             IObjectIdentity_Release(identity);
1103             *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
1104         }else {
1105             *ret = VARIANT_FALSE;
1106         }
1107     }
1108
1109     IUnknown_Release(unk1);
1110     IUnknown_Release(unk2);
1111     return S_OK;
1112 }
1113
1114 static HRESULT interp_is(exec_ctx_t *ctx)
1115 {
1116     IDispatch *l, *r;
1117     VARIANT v;
1118     HRESULT hres;
1119
1120     TRACE("\n");
1121
1122     hres = stack_pop_disp(ctx, &r);
1123     if(FAILED(hres))
1124         return hres;
1125
1126     hres = stack_pop_disp(ctx, &l);
1127     if(SUCCEEDED(hres)) {
1128         V_VT(&v) = VT_BOOL;
1129         hres = disp_cmp(l, r, &V_BOOL(&v));
1130         if(l)
1131             IDispatch_Release(l);
1132     }
1133     if(r)
1134         IDispatch_Release(r);
1135     if(FAILED(hres))
1136         return hres;
1137
1138     return stack_push(ctx, &v);
1139 }
1140
1141 static HRESULT interp_concat(exec_ctx_t *ctx)
1142 {
1143     variant_val_t r, l;
1144     VARIANT v;
1145     HRESULT hres;
1146
1147     TRACE("\n");
1148
1149     hres = stack_pop_val(ctx, &r);
1150     if(FAILED(hres))
1151         return hres;
1152
1153     hres = stack_pop_val(ctx, &l);
1154     if(SUCCEEDED(hres)) {
1155         hres = VarCat(l.v, r.v, &v);
1156         release_val(&l);
1157     }
1158     release_val(&r);
1159     if(FAILED(hres))
1160         return hres;
1161
1162     return stack_push(ctx, &v);
1163 }
1164
1165 static HRESULT interp_add(exec_ctx_t *ctx)
1166 {
1167     variant_val_t r, l;
1168     VARIANT v;
1169     HRESULT hres;
1170
1171     TRACE("\n");
1172
1173     hres = stack_pop_val(ctx, &r);
1174     if(FAILED(hres))
1175         return hres;
1176
1177     hres = stack_pop_val(ctx, &l);
1178     if(SUCCEEDED(hres)) {
1179         hres = VarAdd(l.v, r.v, &v);
1180         release_val(&l);
1181     }
1182     release_val(&r);
1183     if(FAILED(hres))
1184         return hres;
1185
1186     return stack_push(ctx, &v);
1187 }
1188
1189 static HRESULT interp_sub(exec_ctx_t *ctx)
1190 {
1191     variant_val_t r, l;
1192     VARIANT v;
1193     HRESULT hres;
1194
1195     TRACE("\n");
1196
1197     hres = stack_pop_val(ctx, &r);
1198     if(FAILED(hres))
1199         return hres;
1200
1201     hres = stack_pop_val(ctx, &l);
1202     if(SUCCEEDED(hres)) {
1203         hres = VarSub(l.v, r.v, &v);
1204         release_val(&l);
1205     }
1206     release_val(&r);
1207     if(FAILED(hres))
1208         return hres;
1209
1210     return stack_push(ctx, &v);
1211 }
1212
1213 static HRESULT interp_mod(exec_ctx_t *ctx)
1214 {
1215     variant_val_t r, l;
1216     VARIANT v;
1217     HRESULT hres;
1218
1219     TRACE("\n");
1220
1221     hres = stack_pop_val(ctx, &r);
1222     if(FAILED(hres))
1223         return hres;
1224
1225     hres = stack_pop_val(ctx, &l);
1226     if(SUCCEEDED(hres)) {
1227         hres = VarMod(l.v, r.v, &v);
1228         release_val(&l);
1229     }
1230     release_val(&r);
1231     if(FAILED(hres))
1232         return hres;
1233
1234     return stack_push(ctx, &v);
1235 }
1236
1237 static HRESULT interp_idiv(exec_ctx_t *ctx)
1238 {
1239     variant_val_t r, l;
1240     VARIANT v;
1241     HRESULT hres;
1242
1243     TRACE("\n");
1244
1245     hres = stack_pop_val(ctx, &r);
1246     if(FAILED(hres))
1247         return hres;
1248
1249     hres = stack_pop_val(ctx, &l);
1250     if(SUCCEEDED(hres)) {
1251         hres = VarIdiv(l.v, r.v, &v);
1252         release_val(&l);
1253     }
1254     release_val(&r);
1255     if(FAILED(hres))
1256         return hres;
1257
1258     return stack_push(ctx, &v);
1259 }
1260
1261 static HRESULT interp_div(exec_ctx_t *ctx)
1262 {
1263     variant_val_t r, l;
1264     VARIANT v;
1265     HRESULT hres;
1266
1267     TRACE("\n");
1268
1269     hres = stack_pop_val(ctx, &r);
1270     if(FAILED(hres))
1271         return hres;
1272
1273     hres = stack_pop_val(ctx, &l);
1274     if(SUCCEEDED(hres)) {
1275         hres = VarDiv(l.v, r.v, &v);
1276         release_val(&l);
1277     }
1278     release_val(&r);
1279     if(FAILED(hres))
1280         return hres;
1281
1282     return stack_push(ctx, &v);
1283 }
1284
1285 static HRESULT interp_mul(exec_ctx_t *ctx)
1286 {
1287     variant_val_t r, l;
1288     VARIANT v;
1289     HRESULT hres;
1290
1291     TRACE("\n");
1292
1293     hres = stack_pop_val(ctx, &r);
1294     if(FAILED(hres))
1295         return hres;
1296
1297     hres = stack_pop_val(ctx, &l);
1298     if(SUCCEEDED(hres)) {
1299         hres = VarMul(l.v, r.v, &v);
1300         release_val(&l);
1301     }
1302     release_val(&r);
1303     if(FAILED(hres))
1304         return hres;
1305
1306     return stack_push(ctx, &v);
1307 }
1308
1309 static HRESULT interp_exp(exec_ctx_t *ctx)
1310 {
1311     variant_val_t r, l;
1312     VARIANT v;
1313     HRESULT hres;
1314
1315     TRACE("\n");
1316
1317     hres = stack_pop_val(ctx, &r);
1318     if(FAILED(hres))
1319         return hres;
1320
1321     hres = stack_pop_val(ctx, &l);
1322     if(SUCCEEDED(hres)) {
1323         hres = VarPow(l.v, r.v, &v);
1324         release_val(&l);
1325     }
1326     release_val(&r);
1327     if(FAILED(hres))
1328         return hres;
1329
1330     return stack_push(ctx, &v);
1331 }
1332
1333 static HRESULT interp_neg(exec_ctx_t *ctx)
1334 {
1335     variant_val_t val;
1336     VARIANT v;
1337     HRESULT hres;
1338
1339     hres = stack_pop_val(ctx, &val);
1340     if(FAILED(hres))
1341         return hres;
1342
1343     hres = VarNeg(val.v, &v);
1344     release_val(&val);
1345     if(FAILED(hres))
1346         return hres;
1347
1348     return stack_push(ctx, &v);
1349 }
1350
1351 static const instr_func_t op_funcs[] = {
1352 #define X(x,n,a,b) interp_ ## x,
1353 OP_LIST
1354 #undef X
1355 };
1356
1357 static const unsigned op_move[] = {
1358 #define X(x,n,a,b) n,
1359 OP_LIST
1360 #undef X
1361 };
1362
1363 static void release_exec(exec_ctx_t *ctx)
1364 {
1365     unsigned i;
1366
1367     VariantClear(&ctx->ret_val);
1368
1369     if(ctx->this_obj)
1370         IDispatch_Release(ctx->this_obj);
1371
1372     if(ctx->args) {
1373         for(i=0; i < ctx->func->arg_cnt; i++)
1374             VariantClear(ctx->args+i);
1375     }
1376
1377     if(ctx->vars) {
1378         for(i=0; i < ctx->func->var_cnt; i++)
1379             VariantClear(ctx->vars+i);
1380     }
1381
1382     heap_free(ctx->args);
1383     heap_free(ctx->vars);
1384     heap_free(ctx->stack);
1385 }
1386
1387 HRESULT exec_script(script_ctx_t *ctx, function_t *func, IDispatch *this_obj, DISPPARAMS *dp, VARIANT *res)
1388 {
1389     exec_ctx_t exec = {func->code_ctx};
1390     vbsop_t op;
1391     HRESULT hres = S_OK;
1392
1393     exec.code = func->code_ctx;
1394
1395     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
1396         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
1397         return E_FAIL;
1398     }
1399
1400     if(func->arg_cnt) {
1401         VARIANT *v;
1402         unsigned i;
1403
1404         exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
1405         if(!exec.args) {
1406             release_exec(&exec);
1407             return E_OUTOFMEMORY;
1408         }
1409
1410         for(i=0; i < func->arg_cnt; i++) {
1411             v = get_arg(dp, i);
1412             if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
1413                 if(func->args[i].by_ref)
1414                     exec.args[i] = *v;
1415                 else
1416                     hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
1417             }else {
1418                 hres = VariantCopy(exec.args+i, v);
1419             }
1420             if(FAILED(hres)) {
1421                 release_exec(&exec);
1422                 return hres;
1423             }
1424         }
1425     }else {
1426         exec.args = NULL;
1427     }
1428
1429     if(func->var_cnt) {
1430         exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
1431         if(!exec.vars) {
1432             release_exec(&exec);
1433             return E_OUTOFMEMORY;
1434         }
1435     }else {
1436         exec.vars = NULL;
1437     }
1438
1439     exec.stack_size = 16;
1440     exec.top = 0;
1441     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
1442     if(!exec.stack) {
1443         release_exec(&exec);
1444         return E_OUTOFMEMORY;
1445     }
1446
1447     if(this_obj)
1448         exec.this_obj = this_obj;
1449     else if (ctx->host_global)
1450         exec.this_obj = ctx->host_global;
1451     else
1452         exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface;
1453     IDispatch_AddRef(exec.this_obj);
1454
1455     exec.instr = exec.code->instrs + func->code_off;
1456     exec.script = ctx;
1457     exec.func = func;
1458
1459     while(exec.instr) {
1460         op = exec.instr->op;
1461         hres = op_funcs[op](&exec);
1462         if(FAILED(hres)) {
1463             FIXME("Failed %08x\n", hres);
1464             stack_popn(&exec, exec.top);
1465             break;
1466         }
1467
1468         exec.instr += op_move[op];
1469     }
1470
1471     assert(!exec.top);
1472     if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)
1473         assert(V_VT(&exec.ret_val) == VT_EMPTY);
1474
1475     if(SUCCEEDED(hres) && res) {
1476         *res = exec.ret_val;
1477         V_VT(&exec.ret_val) = VT_EMPTY;
1478     }
1479
1480     release_exec(&exec);
1481
1482     return hres;
1483 }