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