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