xref: /reactos/dll/win32/vbscript/interp.c (revision 51fd824e)
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 "vbscript.h"
20 
21 static DISPID propput_dispid = DISPID_PROPERTYPUT;
22 
23 typedef struct {
24     vbscode_t *code;
25     instr_t *instr;
26     script_ctx_t *script;
27     function_t *func;
28     IDispatch *this_obj;
29     vbdisp_t *vbthis;
30 
31     VARIANT *args;
32     VARIANT *vars;
33     SAFEARRAY **arrays;
34 
35     dynamic_var_t *dynamic_vars;
36     heap_pool_t heap;
37 
38     BOOL resume_next;
39 
40     unsigned stack_size;
41     unsigned top;
42     VARIANT *stack;
43 
44     VARIANT ret_val;
45 } exec_ctx_t;
46 
47 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
48 
49 typedef enum {
50     REF_NONE,
51     REF_DISP,
52     REF_VAR,
53     REF_OBJ,
54     REF_CONST,
55     REF_FUNC
56 } ref_type_t;
57 
58 typedef struct {
59     ref_type_t type;
60     union {
61         struct {
62             IDispatch *disp;
63             DISPID id;
64         } d;
65         VARIANT *v;
66         function_t *f;
67         IDispatch *obj;
68     } u;
69 } ref_t;
70 
71 typedef struct {
72     VARIANT *v;
73     VARIANT store;
74     BOOL owned;
75 } variant_val_t;
76 
77 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
78 {
79     while(var) {
80         if(!strcmpiW(var->name, name)) {
81             ref->type = var->is_const ? REF_CONST : REF_VAR;
82             ref->u.v = &var->v;
83             return TRUE;
84         }
85 
86         var = var->next;
87     }
88 
89     return FALSE;
90 }
91 
92 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref)
93 {
94     named_item_t *item;
95     function_t *func;
96     unsigned i;
97     DISPID id;
98     HRESULT hres;
99 
100     static const WCHAR errW[] = {'e','r','r',0};
101 
102     if(invoke_type == VBDISP_LET
103             && (ctx->func->type == FUNC_FUNCTION || ctx->func->type == FUNC_PROPGET || ctx->func->type == FUNC_DEFGET)
104             && !strcmpiW(name, ctx->func->name)) {
105         ref->type = REF_VAR;
106         ref->u.v = &ctx->ret_val;
107         return S_OK;
108     }
109 
110     for(i=0; i < ctx->func->var_cnt; i++) {
111         if(!strcmpiW(ctx->func->vars[i].name, name)) {
112             ref->type = REF_VAR;
113             ref->u.v = ctx->vars+i;
114             return TRUE;
115         }
116     }
117 
118     for(i=0; i < ctx->func->arg_cnt; i++) {
119         if(!strcmpiW(ctx->func->args[i].name, name)) {
120             ref->type = REF_VAR;
121             ref->u.v = ctx->args+i;
122             return S_OK;
123         }
124     }
125 
126     if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? ctx->script->global_vars : ctx->dynamic_vars, name, ref))
127         return S_OK;
128 
129     if(ctx->func->type != FUNC_GLOBAL) {
130         if(ctx->vbthis) {
131             /* FIXME: Bind such identifier while generating bytecode. */
132             for(i=0; i < ctx->vbthis->desc->prop_cnt; i++) {
133                 if(!strcmpiW(ctx->vbthis->desc->props[i].name, name)) {
134                     ref->type = REF_VAR;
135                     ref->u.v = ctx->vbthis->props+i;
136                     return S_OK;
137                 }
138             }
139         }
140 
141         hres = disp_get_id(ctx->this_obj, name, invoke_type, TRUE, &id);
142         if(SUCCEEDED(hres)) {
143             ref->type = REF_DISP;
144             ref->u.d.disp = ctx->this_obj;
145             ref->u.d.id = id;
146             return S_OK;
147         }
148     }
149 
150     if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(ctx->script->global_vars, name, ref))
151         return S_OK;
152 
153     for(func = ctx->script->global_funcs; func; func = func->next) {
154         if(!strcmpiW(func->name, name)) {
155             ref->type = REF_FUNC;
156             ref->u.f = func;
157             return S_OK;
158         }
159     }
160 
161     if(!strcmpiW(name, errW)) {
162         ref->type = REF_OBJ;
163         ref->u.obj = (IDispatch*)&ctx->script->err_obj->IDispatchEx_iface;
164         return S_OK;
165     }
166 
167     hres = vbdisp_get_id(ctx->script->global_obj, name, invoke_type, TRUE, &id);
168     if(SUCCEEDED(hres)) {
169         ref->type = REF_DISP;
170         ref->u.d.disp = (IDispatch*)&ctx->script->global_obj->IDispatchEx_iface;
171         ref->u.d.id = id;
172         return S_OK;
173     }
174 
175     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
176         if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpiW(item->name, name)) {
177             if(!item->disp) {
178                 IUnknown *unk;
179 
180                 hres = IActiveScriptSite_GetItemInfo(ctx->script->site, item->name, SCRIPTINFO_IUNKNOWN, &unk, NULL);
181                 if(FAILED(hres)) {
182                     WARN("GetItemInfo failed: %08x\n", hres);
183                     continue;
184                 }
185 
186                 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp);
187                 IUnknown_Release(unk);
188                 if(FAILED(hres)) {
189                     WARN("object does not implement IDispatch\n");
190                     continue;
191                 }
192             }
193 
194             ref->type = REF_OBJ;
195             ref->u.obj = item->disp;
196             return S_OK;
197         }
198     }
199 
200     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
201         if((item->flags & SCRIPTITEM_GLOBALMEMBERS)) {
202             hres = disp_get_id(item->disp, name, invoke_type, FALSE, &id);
203             if(SUCCEEDED(hres)) {
204                 ref->type = REF_DISP;
205                 ref->u.d.disp = item->disp;
206                 ref->u.d.id = id;
207                 return S_OK;
208             }
209         }
210     }
211 
212     ref->type = REF_NONE;
213     return S_OK;
214 }
215 
216 static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name,
217         BOOL is_const, VARIANT **out_var)
218 {
219     dynamic_var_t *new_var;
220     heap_pool_t *heap;
221     WCHAR *str;
222     unsigned size;
223 
224     heap = ctx->func->type == FUNC_GLOBAL ? &ctx->script->heap : &ctx->heap;
225 
226     new_var = heap_pool_alloc(heap, sizeof(*new_var));
227     if(!new_var)
228         return E_OUTOFMEMORY;
229 
230     size = (strlenW(name)+1)*sizeof(WCHAR);
231     str = heap_pool_alloc(heap, size);
232     if(!str)
233         return E_OUTOFMEMORY;
234     memcpy(str, name, size);
235     new_var->name = str;
236     new_var->is_const = is_const;
237     V_VT(&new_var->v) = VT_EMPTY;
238 
239     if(ctx->func->type == FUNC_GLOBAL) {
240         new_var->next = ctx->script->global_vars;
241         ctx->script->global_vars = new_var;
242     }else {
243         new_var->next = ctx->dynamic_vars;
244         ctx->dynamic_vars = new_var;
245     }
246 
247     *out_var = &new_var->v;
248     return S_OK;
249 }
250 
251 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
252 {
253     assert(ctx->top);
254     return ctx->stack + --ctx->top;
255 }
256 
257 static inline VARIANT *stack_top(exec_ctx_t *ctx, unsigned n)
258 {
259     assert(ctx->top >= n);
260     return ctx->stack + (ctx->top-n-1);
261 }
262 
263 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
264 {
265     if(ctx->stack_size == ctx->top) {
266         VARIANT *new_stack;
267 
268         new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(*ctx->stack));
269         if(!new_stack) {
270             VariantClear(v);
271             return E_OUTOFMEMORY;
272         }
273 
274         ctx->stack = new_stack;
275         ctx->stack_size *= 2;
276     }
277 
278     ctx->stack[ctx->top++] = *v;
279     return S_OK;
280 }
281 
282 static inline HRESULT stack_push_null(exec_ctx_t *ctx)
283 {
284     VARIANT v;
285     V_VT(&v) = VT_NULL;
286     return stack_push(ctx, &v);
287 }
288 
289 static void stack_popn(exec_ctx_t *ctx, unsigned n)
290 {
291     while(n--)
292         VariantClear(stack_pop(ctx));
293 }
294 
295 static void stack_pop_deref(exec_ctx_t *ctx, variant_val_t *r)
296 {
297     VARIANT *v;
298 
299     v = stack_pop(ctx);
300     if(V_VT(v) == (VT_BYREF|VT_VARIANT)) {
301         r->owned = FALSE;
302         r->v = V_VARIANTREF(v);
303     }else {
304         r->owned = TRUE;
305         r->v = v;
306     }
307 }
308 
309 static inline void release_val(variant_val_t *v)
310 {
311     if(v->owned)
312         VariantClear(v->v);
313 }
314 
315 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *r)
316 {
317     stack_pop_deref(ctx, r);
318 
319     if(V_VT(r->v) == VT_DISPATCH) {
320         HRESULT hres;
321 
322         hres = get_disp_value(ctx->script, V_DISPATCH(r->v), &r->store);
323         if(r->owned)
324             IDispatch_Release(V_DISPATCH(r->v));
325         if(FAILED(hres))
326             return hres;
327 
328         r->owned = TRUE;
329         r->v = &r->store;
330     }
331 
332     return S_OK;
333 }
334 
335 static HRESULT stack_assume_val(exec_ctx_t *ctx, unsigned n)
336 {
337     VARIANT *v = stack_top(ctx, n);
338     HRESULT hres;
339 
340     if(V_VT(v) == (VT_BYREF|VT_VARIANT)) {
341         VARIANT *ref = V_VARIANTREF(v);
342 
343         V_VT(v) = VT_EMPTY;
344         hres = VariantCopy(v, ref);
345         if(FAILED(hres))
346             return hres;
347     }
348 
349     if(V_VT(v) == VT_DISPATCH) {
350         IDispatch *disp;
351 
352         disp = V_DISPATCH(v);
353         hres = get_disp_value(ctx->script, disp, v);
354         IDispatch_Release(disp);
355         if(FAILED(hres))
356             return hres;
357     }
358 
359     return S_OK;
360 }
361 
362 static int stack_pop_bool(exec_ctx_t *ctx, BOOL *b)
363 {
364     variant_val_t val;
365     HRESULT hres;
366 
367     hres = stack_pop_val(ctx, &val);
368     if(FAILED(hres))
369         return hres;
370 
371     switch (V_VT(val.v))
372     {
373     case VT_BOOL:
374         *b = V_BOOL(val.v);
375         break;
376     case VT_NULL:
377         *b = FALSE;
378         break;
379     case VT_I2:
380         *b = V_I2(val.v);
381         break;
382     case VT_I4:
383         *b = V_I4(val.v);
384         break;
385     default:
386         FIXME("unsupported for %s\n", debugstr_variant(val.v));
387         release_val(&val);
388         return E_NOTIMPL;
389     }
390     return S_OK;
391 }
392 
393 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
394 {
395     VARIANT *v = stack_pop(ctx);
396 
397     if(V_VT(v) == VT_DISPATCH) {
398         *ret = V_DISPATCH(v);
399         return S_OK;
400     }
401 
402     if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
403         FIXME("not supported type: %s\n", debugstr_variant(v));
404         VariantClear(v);
405         return E_FAIL;
406     }
407 
408     v = V_BYREF(v);
409     if(V_VT(v) != VT_DISPATCH) {
410         FIXME("not disp %s\n", debugstr_variant(v));
411         return E_FAIL;
412     }
413 
414     if(V_DISPATCH(v))
415         IDispatch_AddRef(V_DISPATCH(v));
416     *ret = V_DISPATCH(v);
417     return S_OK;
418 }
419 
420 static HRESULT stack_assume_disp(exec_ctx_t *ctx, unsigned n, IDispatch **disp)
421 {
422     VARIANT *v = stack_top(ctx, n), *ref;
423 
424     if(V_VT(v) != VT_DISPATCH) {
425         if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
426             FIXME("not supported type: %s\n", debugstr_variant(v));
427             return E_FAIL;
428         }
429 
430         ref = V_VARIANTREF(v);
431         if(V_VT(ref) != VT_DISPATCH) {
432             FIXME("not disp %s\n", debugstr_variant(ref));
433             return E_FAIL;
434         }
435 
436         V_VT(v) = VT_DISPATCH;
437         V_DISPATCH(v) = V_DISPATCH(ref);
438         if(V_DISPATCH(v))
439             IDispatch_AddRef(V_DISPATCH(v));
440     }
441 
442     if(disp)
443         *disp = V_DISPATCH(v);
444     return S_OK;
445 }
446 
447 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
448 {
449     ctx->instr = ctx->code->instrs + addr;
450 }
451 
452 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, BOOL is_propput, DISPPARAMS *dp)
453 {
454     dp->cNamedArgs = is_propput ? 1 : 0;
455     dp->cArgs = arg_cnt + dp->cNamedArgs;
456     dp->rgdispidNamedArgs = is_propput ? &propput_dispid : NULL;
457 
458     if(arg_cnt) {
459         VARIANT tmp;
460         unsigned i;
461 
462         assert(ctx->top >= arg_cnt);
463 
464         for(i=1; i*2 <= arg_cnt; i++) {
465             tmp = ctx->stack[ctx->top-i];
466             ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
467             ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
468         }
469 
470         dp->rgvarg = ctx->stack + ctx->top-dp->cArgs;
471     }else {
472         dp->rgvarg = is_propput ? ctx->stack+ctx->top-1 : NULL;
473     }
474 }
475 
476 static HRESULT array_access(exec_ctx_t *ctx, SAFEARRAY *array, DISPPARAMS *dp, VARIANT **ret)
477 {
478     unsigned i, argc = arg_cnt(dp);
479     LONG *indices;
480     HRESULT hres;
481 
482     if(!array) {
483         FIXME("NULL array\n");
484         return E_FAIL;
485     }
486 
487     hres = SafeArrayLock(array);
488     if(FAILED(hres))
489         return hres;
490 
491     if(array->cDims != argc) {
492         FIXME("argc %d does not match cDims %d\n", dp->cArgs, array->cDims);
493         SafeArrayUnlock(array);
494         return E_FAIL;
495     }
496 
497     indices = heap_alloc(sizeof(*indices) * argc);
498     if(!indices) {
499         SafeArrayUnlock(array);
500         return E_OUTOFMEMORY;
501     }
502 
503     for(i=0; i<argc; i++) {
504         hres = to_int(get_arg(dp, i), indices+i);
505         if(FAILED(hres)) {
506             heap_free(indices);
507             SafeArrayUnlock(array);
508             return hres;
509         }
510     }
511 
512     hres = SafeArrayPtrOfIndex(array, indices, (void**)ret);
513     SafeArrayUnlock(array);
514     heap_free(indices);
515     return hres;
516 }
517 
518 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
519 {
520     BSTR identifier = ctx->instr->arg1.bstr;
521     const unsigned arg_cnt = ctx->instr->arg2.uint;
522     DISPPARAMS dp;
523     ref_t ref;
524     HRESULT hres;
525 
526     hres = lookup_identifier(ctx, identifier, VBDISP_CALLGET, &ref);
527     if(FAILED(hres))
528         return hres;
529 
530     switch(ref.type) {
531     case REF_VAR:
532     case REF_CONST: {
533         VARIANT *v;
534 
535         if(!res) {
536             FIXME("REF_VAR no res\n");
537             return E_NOTIMPL;
538         }
539 
540         v = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
541 
542         if(arg_cnt) {
543             SAFEARRAY *array = NULL;
544 
545             switch(V_VT(v)) {
546             case VT_ARRAY|VT_BYREF|VT_VARIANT:
547                 array = *V_ARRAYREF(ref.u.v);
548                 break;
549             case VT_ARRAY|VT_VARIANT:
550                 array = V_ARRAY(ref.u.v);
551                 break;
552             case VT_DISPATCH:
553                 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
554                 hres = disp_call(ctx->script, V_DISPATCH(v), DISPID_VALUE, &dp, res);
555                 if(FAILED(hres))
556                     return hres;
557                 break;
558             default:
559                 FIXME("arguments not implemented\n");
560                 return E_NOTIMPL;
561             }
562 
563             if(!array)
564                 break;
565 
566             vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
567             hres = array_access(ctx, array, &dp, &v);
568             if(FAILED(hres))
569                 return hres;
570         }
571 
572         V_VT(res) = VT_BYREF|VT_VARIANT;
573         V_BYREF(res) = v;
574         break;
575     }
576     case REF_DISP:
577         vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
578         hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
579         if(FAILED(hres))
580             return hres;
581         break;
582     case REF_FUNC:
583         vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
584         hres = exec_script(ctx->script, ref.u.f, NULL, &dp, res);
585         if(FAILED(hres))
586             return hres;
587         break;
588     case REF_OBJ:
589         if(arg_cnt) {
590             FIXME("arguments on object\n");
591             return E_NOTIMPL;
592         }
593 
594         if(res) {
595             IDispatch_AddRef(ref.u.obj);
596             V_VT(res) = VT_DISPATCH;
597             V_DISPATCH(res) = ref.u.obj;
598         }
599         break;
600     case REF_NONE:
601         if(res && !ctx->func->code_ctx->option_explicit && arg_cnt == 0) {
602             VARIANT *new;
603             hres = add_dynamic_var(ctx, identifier, FALSE, &new);
604             if(FAILED(hres))
605                 return hres;
606             V_VT(res) = VT_BYREF|VT_VARIANT;
607             V_BYREF(res) = new;
608             break;
609         }
610         FIXME("%s not found\n", debugstr_w(identifier));
611         return DISP_E_UNKNOWNNAME;
612     }
613 
614     stack_popn(ctx, arg_cnt);
615     return S_OK;
616 }
617 
618 static HRESULT interp_icall(exec_ctx_t *ctx)
619 {
620     VARIANT v;
621     HRESULT hres;
622 
623     TRACE("\n");
624 
625     hres = do_icall(ctx, &v);
626     if(FAILED(hres))
627         return hres;
628 
629     return stack_push(ctx, &v);
630 }
631 
632 static HRESULT interp_icallv(exec_ctx_t *ctx)
633 {
634     TRACE("\n");
635     return do_icall(ctx, NULL);
636 }
637 
638 static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res)
639 {
640     const BSTR identifier = ctx->instr->arg1.bstr;
641     const unsigned arg_cnt = ctx->instr->arg2.uint;
642     IDispatch *obj;
643     DISPPARAMS dp;
644     DISPID id;
645     HRESULT hres;
646 
647     hres = stack_pop_disp(ctx, &obj);
648     if(FAILED(hres))
649         return hres;
650 
651     if(!obj) {
652         FIXME("NULL obj\n");
653         return E_FAIL;
654     }
655 
656     vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
657 
658     hres = disp_get_id(obj, identifier, VBDISP_CALLGET, FALSE, &id);
659     if(SUCCEEDED(hres))
660         hres = disp_call(ctx->script, obj, id, &dp, res);
661     IDispatch_Release(obj);
662     if(FAILED(hres))
663         return hres;
664 
665     stack_popn(ctx, arg_cnt);
666     return S_OK;
667 }
668 
669 static HRESULT interp_mcall(exec_ctx_t *ctx)
670 {
671     VARIANT res;
672     HRESULT hres;
673 
674     TRACE("\n");
675 
676     hres = do_mcall(ctx, &res);
677     if(FAILED(hres))
678         return hres;
679 
680     return stack_push(ctx, &res);
681 }
682 
683 static HRESULT interp_mcallv(exec_ctx_t *ctx)
684 {
685     TRACE("\n");
686 
687     return do_mcall(ctx, NULL);
688 }
689 
690 static HRESULT assign_value(exec_ctx_t *ctx, VARIANT *dst, VARIANT *src, WORD flags)
691 {
692     HRESULT hres;
693 
694     hres = VariantCopyInd(dst, src);
695     if(FAILED(hres))
696         return hres;
697 
698     if(V_VT(dst) == VT_DISPATCH && !(flags & DISPATCH_PROPERTYPUTREF)) {
699         VARIANT value;
700 
701         hres = get_disp_value(ctx->script, V_DISPATCH(dst), &value);
702         IDispatch_Release(V_DISPATCH(dst));
703         if(FAILED(hres))
704             return hres;
705 
706         *dst = value;
707     }
708 
709     return S_OK;
710 }
711 
712 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, WORD flags, DISPPARAMS *dp)
713 {
714     ref_t ref;
715     HRESULT hres;
716 
717     hres = lookup_identifier(ctx, name, VBDISP_LET, &ref);
718     if(FAILED(hres))
719         return hres;
720 
721     switch(ref.type) {
722     case REF_VAR: {
723         VARIANT *v = ref.u.v;
724 
725         if(V_VT(v) == (VT_VARIANT|VT_BYREF))
726             v = V_VARIANTREF(v);
727 
728         if(arg_cnt(dp)) {
729             SAFEARRAY *array;
730 
731             if(!(V_VT(v) & VT_ARRAY)) {
732                 FIXME("array assign on type %d\n", V_VT(v));
733                 return E_FAIL;
734             }
735 
736             switch(V_VT(v)) {
737             case VT_ARRAY|VT_BYREF|VT_VARIANT:
738                 array = *V_ARRAYREF(v);
739                 break;
740             case VT_ARRAY|VT_VARIANT:
741                 array = V_ARRAY(v);
742                 break;
743             default:
744                 FIXME("Unsupported array type %x\n", V_VT(v));
745                 return E_NOTIMPL;
746             }
747 
748             if(!array) {
749                 FIXME("null array\n");
750                 return E_FAIL;
751             }
752 
753             hres = array_access(ctx, array, dp, &v);
754             if(FAILED(hres))
755                 return hres;
756         }else if(V_VT(v) == (VT_ARRAY|VT_BYREF|VT_VARIANT)) {
757             FIXME("non-array assign\n");
758             return E_NOTIMPL;
759         }
760 
761         hres = assign_value(ctx, v, dp->rgvarg, flags);
762         break;
763     }
764     case REF_DISP:
765         hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, flags, dp);
766         break;
767     case REF_FUNC:
768         FIXME("functions not implemented\n");
769         return E_NOTIMPL;
770     case REF_OBJ:
771         FIXME("REF_OBJ\n");
772         return E_NOTIMPL;
773     case REF_CONST:
774         FIXME("REF_CONST\n");
775         return E_NOTIMPL;
776     case REF_NONE:
777         if(ctx->func->code_ctx->option_explicit) {
778             FIXME("throw exception\n");
779             hres = E_FAIL;
780         }else {
781             VARIANT *new_var;
782 
783             if(arg_cnt(dp)) {
784                 FIXME("arg_cnt %d not supported\n", arg_cnt(dp));
785                 return E_NOTIMPL;
786             }
787 
788             TRACE("creating variable %s\n", debugstr_w(name));
789             hres = add_dynamic_var(ctx, name, FALSE, &new_var);
790             if(SUCCEEDED(hres))
791                 hres = assign_value(ctx, new_var, dp->rgvarg, flags);
792         }
793     }
794 
795     return hres;
796 }
797 
798 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
799 {
800     const BSTR arg = ctx->instr->arg1.bstr;
801     const unsigned arg_cnt = ctx->instr->arg2.uint;
802     DISPPARAMS dp;
803     HRESULT hres;
804 
805     TRACE("%s\n", debugstr_w(arg));
806 
807     vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
808     hres = assign_ident(ctx, arg, DISPATCH_PROPERTYPUT, &dp);
809     if(FAILED(hres))
810         return hres;
811 
812     stack_popn(ctx, arg_cnt+1);
813     return S_OK;
814 }
815 
816 static HRESULT interp_set_ident(exec_ctx_t *ctx)
817 {
818     const BSTR arg = ctx->instr->arg1.bstr;
819     const unsigned arg_cnt = ctx->instr->arg2.uint;
820     DISPPARAMS dp;
821     HRESULT hres;
822 
823     TRACE("%s\n", debugstr_w(arg));
824 
825     if(arg_cnt) {
826         FIXME("arguments not supported\n");
827         return E_NOTIMPL;
828     }
829 
830     hres = stack_assume_disp(ctx, 0, NULL);
831     if(FAILED(hres))
832         return hres;
833 
834     vbstack_to_dp(ctx, 0, TRUE, &dp);
835     hres = assign_ident(ctx, ctx->instr->arg1.bstr, DISPATCH_PROPERTYPUTREF, &dp);
836     if(FAILED(hres))
837         return hres;
838 
839     stack_popn(ctx, 1);
840     return S_OK;
841 }
842 
843 static HRESULT interp_assign_member(exec_ctx_t *ctx)
844 {
845     BSTR identifier = ctx->instr->arg1.bstr;
846     const unsigned arg_cnt = ctx->instr->arg2.uint;
847     IDispatch *obj;
848     DISPPARAMS dp;
849     DISPID id;
850     HRESULT hres;
851 
852     TRACE("%s\n", debugstr_w(identifier));
853 
854     hres = stack_assume_disp(ctx, arg_cnt+1, &obj);
855     if(FAILED(hres))
856         return hres;
857 
858     if(!obj) {
859         FIXME("NULL obj\n");
860         return E_FAIL;
861     }
862 
863     hres = disp_get_id(obj, identifier, VBDISP_LET, FALSE, &id);
864     if(SUCCEEDED(hres)) {
865         vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
866         hres = disp_propput(ctx->script, obj, id, DISPATCH_PROPERTYPUT, &dp);
867     }
868     if(FAILED(hres))
869         return hres;
870 
871     stack_popn(ctx, arg_cnt+2);
872     return S_OK;
873 }
874 
875 static HRESULT interp_set_member(exec_ctx_t *ctx)
876 {
877     BSTR identifier = ctx->instr->arg1.bstr;
878     const unsigned arg_cnt = ctx->instr->arg2.uint;
879     IDispatch *obj;
880     DISPPARAMS dp;
881     DISPID id;
882     HRESULT hres;
883 
884     TRACE("%s\n", debugstr_w(identifier));
885 
886     if(arg_cnt) {
887         FIXME("arguments not supported\n");
888         return E_NOTIMPL;
889     }
890 
891     hres = stack_assume_disp(ctx, 1, &obj);
892     if(FAILED(hres))
893         return hres;
894 
895     if(!obj) {
896         FIXME("NULL obj\n");
897         return E_FAIL;
898     }
899 
900     hres = stack_assume_disp(ctx, 0, NULL);
901     if(FAILED(hres))
902         return hres;
903 
904     hres = disp_get_id(obj, identifier, VBDISP_SET, FALSE, &id);
905     if(SUCCEEDED(hres)) {
906         vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
907         hres = disp_propput(ctx->script, obj, id, DISPATCH_PROPERTYPUTREF, &dp);
908     }
909     if(FAILED(hres))
910         return hres;
911 
912     stack_popn(ctx, 2);
913     return S_OK;
914 }
915 
916 static HRESULT interp_const(exec_ctx_t *ctx)
917 {
918     BSTR arg = ctx->instr->arg1.bstr;
919     VARIANT *v;
920     ref_t ref;
921     HRESULT hres;
922 
923     TRACE("%s\n", debugstr_w(arg));
924 
925     assert(ctx->func->type == FUNC_GLOBAL);
926 
927     hres = lookup_identifier(ctx, arg, VBDISP_CALLGET, &ref);
928     if(FAILED(hres))
929         return hres;
930 
931     if(ref.type != REF_NONE) {
932         FIXME("%s already defined\n", debugstr_w(arg));
933         return E_FAIL;
934     }
935 
936     hres = stack_assume_val(ctx, 0);
937     if(FAILED(hres))
938         return hres;
939 
940     hres = add_dynamic_var(ctx, arg, TRUE, &v);
941     if(FAILED(hres))
942         return hres;
943 
944     *v = *stack_pop(ctx);
945     return S_OK;
946 }
947 
948 static HRESULT interp_val(exec_ctx_t *ctx)
949 {
950     variant_val_t val;
951     VARIANT v;
952     HRESULT hres;
953 
954     TRACE("\n");
955 
956     hres = stack_pop_val(ctx, &val);
957     if(FAILED(hres))
958         return hres;
959 
960     if(!val.owned) {
961         V_VT(&v) = VT_EMPTY;
962         hres = VariantCopy(&v, val.v);
963         if(FAILED(hres))
964             return hres;
965     }
966 
967     return stack_push(ctx, val.owned ? val.v : &v);
968 }
969 
970 static HRESULT interp_pop(exec_ctx_t *ctx)
971 {
972     const unsigned n = ctx->instr->arg1.uint;
973 
974     TRACE("%u\n", n);
975 
976     stack_popn(ctx, n);
977     return S_OK;
978 }
979 
980 static HRESULT interp_new(exec_ctx_t *ctx)
981 {
982     const WCHAR *arg = ctx->instr->arg1.bstr;
983     class_desc_t *class_desc;
984     vbdisp_t *obj;
985     VARIANT v;
986     HRESULT hres;
987 
988     static const WCHAR regexpW[] = {'r','e','g','e','x','p',0};
989 
990     TRACE("%s\n", debugstr_w(arg));
991 
992     if(!strcmpiW(arg, regexpW)) {
993         V_VT(&v) = VT_DISPATCH;
994         hres = create_regexp(&V_DISPATCH(&v));
995         if(FAILED(hres))
996             return hres;
997 
998         return stack_push(ctx, &v);
999     }
1000 
1001     for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
1002         if(!strcmpiW(class_desc->name, arg))
1003             break;
1004     }
1005     if(!class_desc) {
1006         FIXME("Class %s not found\n", debugstr_w(arg));
1007         return E_FAIL;
1008     }
1009 
1010     hres = create_vbdisp(class_desc, &obj);
1011     if(FAILED(hres))
1012         return hres;
1013 
1014     V_VT(&v) = VT_DISPATCH;
1015     V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
1016     return stack_push(ctx, &v);
1017 }
1018 
1019 static HRESULT interp_dim(exec_ctx_t *ctx)
1020 {
1021     const BSTR ident = ctx->instr->arg1.bstr;
1022     const unsigned array_id = ctx->instr->arg2.uint;
1023     const array_desc_t *array_desc;
1024     ref_t ref;
1025     HRESULT hres;
1026 
1027     TRACE("%s\n", debugstr_w(ident));
1028 
1029     assert(array_id < ctx->func->array_cnt);
1030     if(!ctx->arrays) {
1031         ctx->arrays = heap_alloc_zero(ctx->func->array_cnt * sizeof(SAFEARRAY*));
1032         if(!ctx->arrays)
1033             return E_OUTOFMEMORY;
1034     }
1035 
1036     hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref);
1037     if(FAILED(hres)) {
1038         FIXME("lookup %s failed: %08x\n", debugstr_w(ident), hres);
1039         return hres;
1040     }
1041 
1042     if(ref.type != REF_VAR) {
1043         FIXME("got ref.type = %d\n", ref.type);
1044         return E_FAIL;
1045     }
1046 
1047     if(ctx->arrays[array_id]) {
1048         FIXME("Array already initialized\n");
1049         return E_FAIL;
1050     }
1051 
1052     array_desc = ctx->func->array_descs + array_id;
1053     if(array_desc->dim_cnt) {
1054         ctx->arrays[array_id] = SafeArrayCreate(VT_VARIANT, array_desc->dim_cnt, array_desc->bounds);
1055         if(!ctx->arrays[array_id])
1056             return E_OUTOFMEMORY;
1057     }
1058 
1059     V_VT(ref.u.v) = VT_ARRAY|VT_BYREF|VT_VARIANT;
1060     V_ARRAYREF(ref.u.v) = ctx->arrays+array_id;
1061     return S_OK;
1062 }
1063 
1064 static HRESULT interp_step(exec_ctx_t *ctx)
1065 {
1066     const BSTR ident = ctx->instr->arg2.bstr;
1067     BOOL gteq_zero;
1068     VARIANT zero;
1069     ref_t ref;
1070     HRESULT hres;
1071 
1072     TRACE("%s\n", debugstr_w(ident));
1073 
1074     V_VT(&zero) = VT_I2;
1075     V_I2(&zero) = 0;
1076     hres = VarCmp(stack_top(ctx, 0), &zero, ctx->script->lcid, 0);
1077     if(FAILED(hres))
1078         return hres;
1079 
1080     gteq_zero = hres == VARCMP_GT || hres == VARCMP_EQ;
1081 
1082     hres = lookup_identifier(ctx, ident, VBDISP_ANY, &ref);
1083     if(FAILED(hres))
1084         return hres;
1085 
1086     if(ref.type != REF_VAR) {
1087         FIXME("%s is not REF_VAR\n", debugstr_w(ident));
1088         return E_FAIL;
1089     }
1090 
1091     hres = VarCmp(ref.u.v, stack_top(ctx, 1), ctx->script->lcid, 0);
1092     if(FAILED(hres))
1093         return hres;
1094 
1095     if(hres == VARCMP_EQ || hres == (gteq_zero ? VARCMP_LT : VARCMP_GT)) {
1096         ctx->instr++;
1097     }else {
1098         stack_popn(ctx, 2);
1099         instr_jmp(ctx, ctx->instr->arg1.uint);
1100     }
1101     return S_OK;
1102 }
1103 
1104 static HRESULT interp_newenum(exec_ctx_t *ctx)
1105 {
1106     variant_val_t v;
1107     VARIANT *r;
1108     HRESULT hres;
1109 
1110     TRACE("\n");
1111 
1112     stack_pop_deref(ctx, &v);
1113     assert(V_VT(stack_top(ctx, 0)) == VT_EMPTY);
1114     r = stack_top(ctx, 0);
1115 
1116     switch(V_VT(v.v)) {
1117     case VT_DISPATCH|VT_BYREF:
1118     case VT_DISPATCH: {
1119         IEnumVARIANT *iter;
1120         DISPPARAMS dp = {0};
1121         VARIANT iterv;
1122 
1123         hres = disp_call(ctx->script, V_ISBYREF(v.v) ? *V_DISPATCHREF(v.v) : V_DISPATCH(v.v), DISPID_NEWENUM, &dp, &iterv);
1124         release_val(&v);
1125         if(FAILED(hres))
1126             return hres;
1127 
1128         if(V_VT(&iterv) != VT_UNKNOWN && V_VT(&iterv) != VT_DISPATCH) {
1129             FIXME("Unsupported iterv %s\n", debugstr_variant(&iterv));
1130             VariantClear(&iterv);
1131             return hres;
1132         }
1133 
1134         hres = IUnknown_QueryInterface(V_UNKNOWN(&iterv), &IID_IEnumVARIANT, (void**)&iter);
1135         IUnknown_Release(V_UNKNOWN(&iterv));
1136         if(FAILED(hres)) {
1137             FIXME("Could not get IEnumVARIANT iface: %08x\n", hres);
1138             return hres;
1139         }
1140 
1141         V_VT(r) = VT_UNKNOWN;
1142         V_UNKNOWN(r) = (IUnknown*)iter;
1143         break;
1144     }
1145     case VT_VARIANT|VT_ARRAY:
1146     case VT_VARIANT|VT_ARRAY|VT_BYREF: {
1147         IEnumVARIANT *iter;
1148 
1149         hres = create_safearray_iter(V_ISBYREF(v.v) ? *V_ARRAYREF(v.v) : V_ARRAY(v.v), &iter);
1150         if(FAILED(hres))
1151             return hres;
1152 
1153         V_VT(r) = VT_UNKNOWN;
1154         V_UNKNOWN(r) = (IUnknown*)iter;
1155         break;
1156     }
1157     default:
1158         FIXME("Unsupported for %s\n", debugstr_variant(v.v));
1159         release_val(&v);
1160         return E_NOTIMPL;
1161     }
1162 
1163     return S_OK;
1164 }
1165 
1166 static HRESULT interp_enumnext(exec_ctx_t *ctx)
1167 {
1168     const unsigned loop_end = ctx->instr->arg1.uint;
1169     const BSTR ident = ctx->instr->arg2.bstr;
1170     VARIANT v;
1171     DISPPARAMS dp = {&v, &propput_dispid, 1, 1};
1172     IEnumVARIANT *iter;
1173     BOOL do_continue;
1174     HRESULT hres;
1175 
1176     TRACE("\n");
1177 
1178     if(V_VT(stack_top(ctx, 0)) == VT_EMPTY) {
1179         FIXME("uninitialized\n");
1180         return E_FAIL;
1181     }
1182 
1183     assert(V_VT(stack_top(ctx, 0)) == VT_UNKNOWN);
1184     iter = (IEnumVARIANT*)V_UNKNOWN(stack_top(ctx, 0));
1185 
1186     V_VT(&v) = VT_EMPTY;
1187     hres = IEnumVARIANT_Next(iter, 1, &v, NULL);
1188     if(FAILED(hres))
1189         return hres;
1190 
1191     do_continue = hres == S_OK;
1192     hres = assign_ident(ctx, ident, DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF, &dp);
1193     VariantClear(&v);
1194     if(FAILED(hres))
1195         return hres;
1196 
1197     if(do_continue) {
1198         ctx->instr++;
1199     }else {
1200         stack_popn(ctx, 1);
1201         instr_jmp(ctx, loop_end);
1202     }
1203     return S_OK;
1204 }
1205 
1206 static HRESULT interp_jmp(exec_ctx_t *ctx)
1207 {
1208     const unsigned arg = ctx->instr->arg1.uint;
1209 
1210     TRACE("%u\n", arg);
1211 
1212     instr_jmp(ctx, arg);
1213     return S_OK;
1214 }
1215 
1216 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
1217 {
1218     const unsigned arg = ctx->instr->arg1.uint;
1219     HRESULT hres;
1220     BOOL b;
1221 
1222     TRACE("%u\n", arg);
1223 
1224     hres = stack_pop_bool(ctx, &b);
1225     if(FAILED(hres))
1226         return hres;
1227 
1228     if(b)
1229         ctx->instr++;
1230     else
1231         instr_jmp(ctx, ctx->instr->arg1.uint);
1232     return S_OK;
1233 }
1234 
1235 static HRESULT interp_jmp_true(exec_ctx_t *ctx)
1236 {
1237     const unsigned arg = ctx->instr->arg1.uint;
1238     HRESULT hres;
1239     BOOL b;
1240 
1241     TRACE("%u\n", arg);
1242 
1243     hres = stack_pop_bool(ctx, &b);
1244     if(FAILED(hres))
1245         return hres;
1246 
1247     if(b)
1248         instr_jmp(ctx, ctx->instr->arg1.uint);
1249     else
1250         ctx->instr++;
1251     return S_OK;
1252 }
1253 
1254 static HRESULT interp_ret(exec_ctx_t *ctx)
1255 {
1256     TRACE("\n");
1257 
1258     ctx->instr = NULL;
1259     return S_OK;
1260 }
1261 
1262 static HRESULT interp_stop(exec_ctx_t *ctx)
1263 {
1264     WARN("\n");
1265 
1266     /* NOTE: this should have effect in debugging mode (that we don't support yet) */
1267     return S_OK;
1268 }
1269 
1270 static HRESULT interp_me(exec_ctx_t *ctx)
1271 {
1272     VARIANT v;
1273 
1274     TRACE("\n");
1275 
1276     IDispatch_AddRef(ctx->this_obj);
1277     V_VT(&v) = VT_DISPATCH;
1278     V_DISPATCH(&v) = ctx->this_obj;
1279     return stack_push(ctx, &v);
1280 }
1281 
1282 static HRESULT interp_bool(exec_ctx_t *ctx)
1283 {
1284     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
1285     VARIANT v;
1286 
1287     TRACE("%s\n", arg ? "true" : "false");
1288 
1289     V_VT(&v) = VT_BOOL;
1290     V_BOOL(&v) = arg;
1291     return stack_push(ctx, &v);
1292 }
1293 
1294 static HRESULT interp_errmode(exec_ctx_t *ctx)
1295 {
1296     const int err_mode = ctx->instr->arg1.uint;
1297 
1298     TRACE("%d\n", err_mode);
1299 
1300     ctx->resume_next = err_mode;
1301     ctx->script->err_number = S_OK;
1302     return S_OK;
1303 }
1304 
1305 static HRESULT interp_string(exec_ctx_t *ctx)
1306 {
1307     VARIANT v;
1308 
1309     TRACE("\n");
1310 
1311     V_VT(&v) = VT_BSTR;
1312     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
1313     if(!V_BSTR(&v))
1314         return E_OUTOFMEMORY;
1315 
1316     return stack_push(ctx, &v);
1317 }
1318 
1319 static HRESULT interp_long(exec_ctx_t *ctx)
1320 {
1321     const LONG arg = ctx->instr->arg1.lng;
1322     VARIANT v;
1323 
1324     TRACE("%d\n", arg);
1325 
1326     V_VT(&v) = VT_I4;
1327     V_I4(&v) = arg;
1328     return stack_push(ctx, &v);
1329 }
1330 
1331 static HRESULT interp_short(exec_ctx_t *ctx)
1332 {
1333     const LONG arg = ctx->instr->arg1.lng;
1334     VARIANT v;
1335 
1336     TRACE("%d\n", arg);
1337 
1338     V_VT(&v) = VT_I2;
1339     V_I2(&v) = arg;
1340     return stack_push(ctx, &v);
1341 }
1342 
1343 static HRESULT interp_double(exec_ctx_t *ctx)
1344 {
1345     const DOUBLE *arg = ctx->instr->arg1.dbl;
1346     VARIANT v;
1347 
1348     TRACE("%lf\n", *arg);
1349 
1350     V_VT(&v) = VT_R8;
1351     V_R8(&v) = *arg;
1352     return stack_push(ctx, &v);
1353 }
1354 
1355 static HRESULT interp_empty(exec_ctx_t *ctx)
1356 {
1357     VARIANT v;
1358 
1359     TRACE("\n");
1360 
1361     V_VT(&v) = VT_EMPTY;
1362     return stack_push(ctx, &v);
1363 }
1364 
1365 static HRESULT interp_null(exec_ctx_t *ctx)
1366 {
1367     TRACE("\n");
1368     return stack_push_null(ctx);
1369 }
1370 
1371 static HRESULT interp_nothing(exec_ctx_t *ctx)
1372 {
1373     VARIANT v;
1374 
1375     TRACE("\n");
1376 
1377     V_VT(&v) = VT_DISPATCH;
1378     V_DISPATCH(&v) = NULL;
1379     return stack_push(ctx, &v);
1380 }
1381 
1382 static HRESULT interp_hres(exec_ctx_t *ctx)
1383 {
1384     const unsigned arg = ctx->instr->arg1.uint;
1385     VARIANT v;
1386 
1387     TRACE("%d\n", arg);
1388 
1389     V_VT(&v) = VT_ERROR;
1390     V_ERROR(&v) = arg;
1391     return stack_push(ctx, &v);
1392 }
1393 
1394 static HRESULT interp_not(exec_ctx_t *ctx)
1395 {
1396     variant_val_t val;
1397     VARIANT v;
1398     HRESULT hres;
1399 
1400     TRACE("\n");
1401 
1402     hres = stack_pop_val(ctx, &val);
1403     if(FAILED(hres))
1404         return hres;
1405 
1406     hres = VarNot(val.v, &v);
1407     release_val(&val);
1408     if(FAILED(hres))
1409         return hres;
1410 
1411     return stack_push(ctx, &v);
1412 }
1413 
1414 static HRESULT interp_and(exec_ctx_t *ctx)
1415 {
1416     variant_val_t r, l;
1417     VARIANT v;
1418     HRESULT hres;
1419 
1420     TRACE("\n");
1421 
1422     hres = stack_pop_val(ctx, &r);
1423     if(FAILED(hres))
1424         return hres;
1425 
1426     hres = stack_pop_val(ctx, &l);
1427     if(SUCCEEDED(hres)) {
1428         hres = VarAnd(l.v, r.v, &v);
1429         release_val(&l);
1430     }
1431     release_val(&r);
1432     if(FAILED(hres))
1433         return hres;
1434 
1435     return stack_push(ctx, &v);
1436 }
1437 
1438 static HRESULT interp_or(exec_ctx_t *ctx)
1439 {
1440     variant_val_t r, l;
1441     VARIANT v;
1442     HRESULT hres;
1443 
1444     TRACE("\n");
1445 
1446     hres = stack_pop_val(ctx, &r);
1447     if(FAILED(hres))
1448         return hres;
1449 
1450     hres = stack_pop_val(ctx, &l);
1451     if(SUCCEEDED(hres)) {
1452         hres = VarOr(l.v, r.v, &v);
1453         release_val(&l);
1454     }
1455     release_val(&r);
1456     if(FAILED(hres))
1457         return hres;
1458 
1459     return stack_push(ctx, &v);
1460 }
1461 
1462 static HRESULT interp_xor(exec_ctx_t *ctx)
1463 {
1464     variant_val_t r, l;
1465     VARIANT v;
1466     HRESULT hres;
1467 
1468     TRACE("\n");
1469 
1470     hres = stack_pop_val(ctx, &r);
1471     if(FAILED(hres))
1472         return hres;
1473 
1474     hres = stack_pop_val(ctx, &l);
1475     if(SUCCEEDED(hres)) {
1476         hres = VarXor(l.v, r.v, &v);
1477         release_val(&l);
1478     }
1479     release_val(&r);
1480     if(FAILED(hres))
1481         return hres;
1482 
1483     return stack_push(ctx, &v);
1484 }
1485 
1486 static HRESULT interp_eqv(exec_ctx_t *ctx)
1487 {
1488     variant_val_t r, l;
1489     VARIANT v;
1490     HRESULT hres;
1491 
1492     TRACE("\n");
1493 
1494     hres = stack_pop_val(ctx, &r);
1495     if(FAILED(hres))
1496         return hres;
1497 
1498     hres = stack_pop_val(ctx, &l);
1499     if(SUCCEEDED(hres)) {
1500         hres = VarEqv(l.v, r.v, &v);
1501         release_val(&l);
1502     }
1503     release_val(&r);
1504     if(FAILED(hres))
1505         return hres;
1506 
1507     return stack_push(ctx, &v);
1508 }
1509 
1510 static HRESULT interp_imp(exec_ctx_t *ctx)
1511 {
1512     variant_val_t r, l;
1513     VARIANT v;
1514     HRESULT hres;
1515 
1516     TRACE("\n");
1517 
1518     hres = stack_pop_val(ctx, &r);
1519     if(FAILED(hres))
1520         return hres;
1521 
1522     hres = stack_pop_val(ctx, &l);
1523     if(SUCCEEDED(hres)) {
1524         hres = VarImp(l.v, r.v, &v);
1525         release_val(&l);
1526     }
1527     release_val(&r);
1528     if(FAILED(hres))
1529         return hres;
1530 
1531     return stack_push(ctx, &v);
1532 }
1533 
1534 static HRESULT var_cmp(exec_ctx_t *ctx, VARIANT *l, VARIANT *r)
1535 {
1536     TRACE("%s %s\n", debugstr_variant(l), debugstr_variant(r));
1537 
1538     /* FIXME: Fix comparing string to number */
1539 
1540     return VarCmp(l, r, ctx->script->lcid, 0);
1541  }
1542 
1543 static HRESULT cmp_oper(exec_ctx_t *ctx)
1544 {
1545     variant_val_t l, r;
1546     HRESULT hres;
1547 
1548     hres = stack_pop_val(ctx, &r);
1549     if(FAILED(hres))
1550         return hres;
1551 
1552     hres = stack_pop_val(ctx, &l);
1553     if(SUCCEEDED(hres)) {
1554         hres = var_cmp(ctx, l.v, r.v);
1555         release_val(&l);
1556     }
1557 
1558     release_val(&r);
1559     return hres;
1560 }
1561 
1562 static HRESULT interp_equal(exec_ctx_t *ctx)
1563 {
1564     VARIANT v;
1565     HRESULT hres;
1566 
1567     TRACE("\n");
1568 
1569     hres = cmp_oper(ctx);
1570     if(FAILED(hres))
1571         return hres;
1572     if(hres == VARCMP_NULL)
1573         return stack_push_null(ctx);
1574 
1575     V_VT(&v) = VT_BOOL;
1576     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1577     return stack_push(ctx, &v);
1578 }
1579 
1580 static HRESULT interp_nequal(exec_ctx_t *ctx)
1581 {
1582     VARIANT v;
1583     HRESULT hres;
1584 
1585     TRACE("\n");
1586 
1587     hres = cmp_oper(ctx);
1588     if(FAILED(hres))
1589         return hres;
1590     if(hres == VARCMP_NULL)
1591         return stack_push_null(ctx);
1592 
1593     V_VT(&v) = VT_BOOL;
1594     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1595     return stack_push(ctx, &v);
1596 }
1597 
1598 static HRESULT interp_gt(exec_ctx_t *ctx)
1599 {
1600     VARIANT v;
1601     HRESULT hres;
1602 
1603     TRACE("\n");
1604 
1605     hres = cmp_oper(ctx);
1606     if(FAILED(hres))
1607         return hres;
1608     if(hres == VARCMP_NULL)
1609         return stack_push_null(ctx);
1610 
1611     V_VT(&v) = VT_BOOL;
1612     V_BOOL(&v) = hres == VARCMP_GT ? VARIANT_TRUE : VARIANT_FALSE;
1613     return stack_push(ctx, &v);
1614 }
1615 
1616 static HRESULT interp_gteq(exec_ctx_t *ctx)
1617 {
1618     VARIANT v;
1619     HRESULT hres;
1620 
1621     TRACE("\n");
1622 
1623     hres = cmp_oper(ctx);
1624     if(FAILED(hres))
1625         return hres;
1626     if(hres == VARCMP_NULL)
1627         return stack_push_null(ctx);
1628 
1629     V_VT(&v) = VT_BOOL;
1630     V_BOOL(&v) = hres == VARCMP_GT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1631     return stack_push(ctx, &v);
1632 }
1633 
1634 static HRESULT interp_lt(exec_ctx_t *ctx)
1635 {
1636     VARIANT v;
1637     HRESULT hres;
1638 
1639     TRACE("\n");
1640 
1641     hres = cmp_oper(ctx);
1642     if(FAILED(hres))
1643         return hres;
1644     if(hres == VARCMP_NULL)
1645         return stack_push_null(ctx);
1646 
1647     V_VT(&v) = VT_BOOL;
1648     V_BOOL(&v) = hres == VARCMP_LT ? VARIANT_TRUE : VARIANT_FALSE;
1649     return stack_push(ctx, &v);
1650 }
1651 
1652 static HRESULT interp_lteq(exec_ctx_t *ctx)
1653 {
1654     VARIANT v;
1655     HRESULT hres;
1656 
1657     TRACE("\n");
1658 
1659     hres = cmp_oper(ctx);
1660     if(FAILED(hres))
1661         return hres;
1662     if(hres == VARCMP_NULL)
1663         return stack_push_null(ctx);
1664 
1665     V_VT(&v) = VT_BOOL;
1666     V_BOOL(&v) = hres == VARCMP_LT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1667     return stack_push(ctx, &v);
1668 }
1669 
1670 static HRESULT interp_case(exec_ctx_t *ctx)
1671 {
1672     const unsigned arg = ctx->instr->arg1.uint;
1673     variant_val_t v;
1674     HRESULT hres;
1675 
1676     TRACE("%d\n", arg);
1677 
1678     hres = stack_pop_val(ctx, &v);
1679     if(FAILED(hres))
1680         return hres;
1681 
1682     hres = var_cmp(ctx, stack_top(ctx, 0), v.v);
1683     release_val(&v);
1684     if(FAILED(hres))
1685         return hres;
1686 
1687     if(hres == VARCMP_EQ) {
1688         stack_popn(ctx, 1);
1689         instr_jmp(ctx, arg);
1690     }else {
1691         ctx->instr++;
1692     }
1693 
1694     return S_OK;
1695 }
1696 
1697 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, VARIANT_BOOL *ret)
1698 {
1699     IObjectIdentity *identity;
1700     IUnknown *unk1, *unk2;
1701     HRESULT hres;
1702 
1703     if(disp1 == disp2) {
1704         *ret = VARIANT_TRUE;
1705         return S_OK;
1706     }
1707 
1708     if(!disp1 || !disp2) {
1709         *ret = VARIANT_FALSE;
1710         return S_OK;
1711     }
1712 
1713     hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
1714     if(FAILED(hres))
1715         return hres;
1716 
1717     hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
1718     if(FAILED(hres)) {
1719         IUnknown_Release(unk1);
1720         return hres;
1721     }
1722 
1723     if(unk1 == unk2) {
1724         *ret = VARIANT_TRUE;
1725     }else {
1726         hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
1727         if(SUCCEEDED(hres)) {
1728             hres = IObjectIdentity_IsEqualObject(identity, unk2);
1729             IObjectIdentity_Release(identity);
1730             *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
1731         }else {
1732             *ret = VARIANT_FALSE;
1733         }
1734     }
1735 
1736     IUnknown_Release(unk1);
1737     IUnknown_Release(unk2);
1738     return S_OK;
1739 }
1740 
1741 static HRESULT interp_is(exec_ctx_t *ctx)
1742 {
1743     IDispatch *l, *r;
1744     VARIANT v;
1745     HRESULT hres;
1746 
1747     TRACE("\n");
1748 
1749     hres = stack_pop_disp(ctx, &r);
1750     if(FAILED(hres))
1751         return hres;
1752 
1753     hres = stack_pop_disp(ctx, &l);
1754     if(SUCCEEDED(hres)) {
1755         V_VT(&v) = VT_BOOL;
1756         hres = disp_cmp(l, r, &V_BOOL(&v));
1757         if(l)
1758             IDispatch_Release(l);
1759     }
1760     if(r)
1761         IDispatch_Release(r);
1762     if(FAILED(hres))
1763         return hres;
1764 
1765     return stack_push(ctx, &v);
1766 }
1767 
1768 static HRESULT interp_concat(exec_ctx_t *ctx)
1769 {
1770     variant_val_t r, l;
1771     VARIANT v;
1772     HRESULT hres;
1773 
1774     TRACE("\n");
1775 
1776     hres = stack_pop_val(ctx, &r);
1777     if(FAILED(hres))
1778         return hres;
1779 
1780     hres = stack_pop_val(ctx, &l);
1781     if(SUCCEEDED(hres)) {
1782         hres = VarCat(l.v, r.v, &v);
1783         release_val(&l);
1784     }
1785     release_val(&r);
1786     if(FAILED(hres))
1787         return hres;
1788 
1789     return stack_push(ctx, &v);
1790 }
1791 
1792 static HRESULT interp_add(exec_ctx_t *ctx)
1793 {
1794     variant_val_t r, l;
1795     VARIANT v;
1796     HRESULT hres;
1797 
1798     TRACE("\n");
1799 
1800     hres = stack_pop_val(ctx, &r);
1801     if(FAILED(hres))
1802         return hres;
1803 
1804     hres = stack_pop_val(ctx, &l);
1805     if(SUCCEEDED(hres)) {
1806         hres = VarAdd(l.v, r.v, &v);
1807         release_val(&l);
1808     }
1809     release_val(&r);
1810     if(FAILED(hres))
1811         return hres;
1812 
1813     return stack_push(ctx, &v);
1814 }
1815 
1816 static HRESULT interp_sub(exec_ctx_t *ctx)
1817 {
1818     variant_val_t r, l;
1819     VARIANT v;
1820     HRESULT hres;
1821 
1822     TRACE("\n");
1823 
1824     hres = stack_pop_val(ctx, &r);
1825     if(FAILED(hres))
1826         return hres;
1827 
1828     hres = stack_pop_val(ctx, &l);
1829     if(SUCCEEDED(hres)) {
1830         hres = VarSub(l.v, r.v, &v);
1831         release_val(&l);
1832     }
1833     release_val(&r);
1834     if(FAILED(hres))
1835         return hres;
1836 
1837     return stack_push(ctx, &v);
1838 }
1839 
1840 static HRESULT interp_mod(exec_ctx_t *ctx)
1841 {
1842     variant_val_t r, l;
1843     VARIANT v;
1844     HRESULT hres;
1845 
1846     TRACE("\n");
1847 
1848     hres = stack_pop_val(ctx, &r);
1849     if(FAILED(hres))
1850         return hres;
1851 
1852     hres = stack_pop_val(ctx, &l);
1853     if(SUCCEEDED(hres)) {
1854         hres = VarMod(l.v, r.v, &v);
1855         release_val(&l);
1856     }
1857     release_val(&r);
1858     if(FAILED(hres))
1859         return hres;
1860 
1861     return stack_push(ctx, &v);
1862 }
1863 
1864 static HRESULT interp_idiv(exec_ctx_t *ctx)
1865 {
1866     variant_val_t r, l;
1867     VARIANT v;
1868     HRESULT hres;
1869 
1870     TRACE("\n");
1871 
1872     hres = stack_pop_val(ctx, &r);
1873     if(FAILED(hres))
1874         return hres;
1875 
1876     hres = stack_pop_val(ctx, &l);
1877     if(SUCCEEDED(hres)) {
1878         hres = VarIdiv(l.v, r.v, &v);
1879         release_val(&l);
1880     }
1881     release_val(&r);
1882     if(FAILED(hres))
1883         return hres;
1884 
1885     return stack_push(ctx, &v);
1886 }
1887 
1888 static HRESULT interp_div(exec_ctx_t *ctx)
1889 {
1890     variant_val_t r, l;
1891     VARIANT v;
1892     HRESULT hres;
1893 
1894     TRACE("\n");
1895 
1896     hres = stack_pop_val(ctx, &r);
1897     if(FAILED(hres))
1898         return hres;
1899 
1900     hres = stack_pop_val(ctx, &l);
1901     if(SUCCEEDED(hres)) {
1902         hres = VarDiv(l.v, r.v, &v);
1903         release_val(&l);
1904     }
1905     release_val(&r);
1906     if(FAILED(hres))
1907         return hres;
1908 
1909     return stack_push(ctx, &v);
1910 }
1911 
1912 static HRESULT interp_mul(exec_ctx_t *ctx)
1913 {
1914     variant_val_t r, l;
1915     VARIANT v;
1916     HRESULT hres;
1917 
1918     TRACE("\n");
1919 
1920     hres = stack_pop_val(ctx, &r);
1921     if(FAILED(hres))
1922         return hres;
1923 
1924     hres = stack_pop_val(ctx, &l);
1925     if(SUCCEEDED(hres)) {
1926         hres = VarMul(l.v, r.v, &v);
1927         release_val(&l);
1928     }
1929     release_val(&r);
1930     if(FAILED(hres))
1931         return hres;
1932 
1933     return stack_push(ctx, &v);
1934 }
1935 
1936 static HRESULT interp_exp(exec_ctx_t *ctx)
1937 {
1938     variant_val_t r, l;
1939     VARIANT v;
1940     HRESULT hres;
1941 
1942     TRACE("\n");
1943 
1944     hres = stack_pop_val(ctx, &r);
1945     if(FAILED(hres))
1946         return hres;
1947 
1948     hres = stack_pop_val(ctx, &l);
1949     if(SUCCEEDED(hres)) {
1950         hres = VarPow(l.v, r.v, &v);
1951         release_val(&l);
1952     }
1953     release_val(&r);
1954     if(FAILED(hres))
1955         return hres;
1956 
1957     return stack_push(ctx, &v);
1958 }
1959 
1960 static HRESULT interp_neg(exec_ctx_t *ctx)
1961 {
1962     variant_val_t val;
1963     VARIANT v;
1964     HRESULT hres;
1965 
1966     hres = stack_pop_val(ctx, &val);
1967     if(FAILED(hres))
1968         return hres;
1969 
1970     hres = VarNeg(val.v, &v);
1971     release_val(&val);
1972     if(FAILED(hres))
1973         return hres;
1974 
1975     return stack_push(ctx, &v);
1976 }
1977 
1978 static HRESULT interp_incc(exec_ctx_t *ctx)
1979 {
1980     const BSTR ident = ctx->instr->arg1.bstr;
1981     VARIANT v;
1982     ref_t ref;
1983     HRESULT hres;
1984 
1985     TRACE("\n");
1986 
1987     hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref);
1988     if(FAILED(hres))
1989         return hres;
1990 
1991     if(ref.type != REF_VAR) {
1992         FIXME("ref.type is not REF_VAR\n");
1993         return E_FAIL;
1994     }
1995 
1996     hres = VarAdd(stack_top(ctx, 0), ref.u.v, &v);
1997     if(FAILED(hres))
1998         return hres;
1999 
2000     VariantClear(ref.u.v);
2001     *ref.u.v = v;
2002     return S_OK;
2003 }
2004 
2005 static HRESULT interp_catch(exec_ctx_t *ctx)
2006 {
2007     /* Nothing to do here, the OP is for unwinding only. */
2008     return S_OK;
2009 }
2010 
2011 static const instr_func_t op_funcs[] = {
2012 #define X(x,n,a,b) interp_ ## x,
2013 OP_LIST
2014 #undef X
2015 };
2016 
2017 static const unsigned op_move[] = {
2018 #define X(x,n,a,b) n,
2019 OP_LIST
2020 #undef X
2021 };
2022 
2023 void release_dynamic_vars(dynamic_var_t *var)
2024 {
2025     while(var) {
2026         VariantClear(&var->v);
2027         var = var->next;
2028     }
2029 }
2030 
2031 static void release_exec(exec_ctx_t *ctx)
2032 {
2033     unsigned i;
2034 
2035     VariantClear(&ctx->ret_val);
2036     release_dynamic_vars(ctx->dynamic_vars);
2037 
2038     if(ctx->this_obj)
2039         IDispatch_Release(ctx->this_obj);
2040 
2041     if(ctx->args) {
2042         for(i=0; i < ctx->func->arg_cnt; i++)
2043             VariantClear(ctx->args+i);
2044     }
2045 
2046     if(ctx->vars) {
2047         for(i=0; i < ctx->func->var_cnt; i++)
2048             VariantClear(ctx->vars+i);
2049     }
2050 
2051     if(ctx->arrays) {
2052         for(i=0; i < ctx->func->var_cnt; i++) {
2053             if(ctx->arrays[i])
2054                 SafeArrayDestroy(ctx->arrays[i]);
2055         }
2056         heap_free(ctx->arrays);
2057     }
2058 
2059     heap_pool_free(&ctx->heap);
2060     heap_free(ctx->args);
2061     heap_free(ctx->vars);
2062     heap_free(ctx->stack);
2063 }
2064 
2065 HRESULT exec_script(script_ctx_t *ctx, function_t *func, vbdisp_t *vbthis, DISPPARAMS *dp, VARIANT *res)
2066 {
2067     exec_ctx_t exec = {func->code_ctx};
2068     vbsop_t op;
2069     HRESULT hres = S_OK;
2070 
2071     exec.code = func->code_ctx;
2072 
2073     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
2074         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
2075         return E_FAIL;
2076     }
2077 
2078     heap_pool_init(&exec.heap);
2079 
2080     if(func->arg_cnt) {
2081         VARIANT *v;
2082         unsigned i;
2083 
2084         exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
2085         if(!exec.args) {
2086             release_exec(&exec);
2087             return E_OUTOFMEMORY;
2088         }
2089 
2090         for(i=0; i < func->arg_cnt; i++) {
2091             v = get_arg(dp, i);
2092             if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
2093                 if(func->args[i].by_ref)
2094                     exec.args[i] = *v;
2095                 else
2096                     hres = VariantCopyInd(exec.args+i, V_VARIANTREF(v));
2097             }else {
2098                 hres = VariantCopyInd(exec.args+i, v);
2099             }
2100             if(FAILED(hres)) {
2101                 release_exec(&exec);
2102                 return hres;
2103             }
2104         }
2105     }else {
2106         exec.args = NULL;
2107     }
2108 
2109     if(func->var_cnt) {
2110         exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
2111         if(!exec.vars) {
2112             release_exec(&exec);
2113             return E_OUTOFMEMORY;
2114         }
2115     }else {
2116         exec.vars = NULL;
2117     }
2118 
2119     exec.stack_size = 16;
2120     exec.top = 0;
2121     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
2122     if(!exec.stack) {
2123         release_exec(&exec);
2124         return E_OUTOFMEMORY;
2125     }
2126 
2127     if(vbthis) {
2128         exec.this_obj = (IDispatch*)&vbthis->IDispatchEx_iface;
2129         exec.vbthis = vbthis;
2130     }else if (ctx->host_global) {
2131         exec.this_obj = ctx->host_global;
2132     }else {
2133         exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface;
2134     }
2135     IDispatch_AddRef(exec.this_obj);
2136 
2137     exec.instr = exec.code->instrs + func->code_off;
2138     exec.script = ctx;
2139     exec.func = func;
2140 
2141     while(exec.instr) {
2142         op = exec.instr->op;
2143         hres = op_funcs[op](&exec);
2144         if(FAILED(hres)) {
2145             ctx->err_number = hres = map_hres(hres);
2146 
2147             if(exec.resume_next) {
2148                 unsigned stack_off;
2149 
2150                 WARN("Failed %08x in resume next mode\n", hres);
2151 
2152                 /*
2153                  * Unwinding here is simple. We need to find the next OP_catch, which contains
2154                  * information about expected stack size and jump offset on error. Generated
2155                  * bytecode needs to guarantee, that simple jump and stack adjustment will
2156                  * guarantee proper execution continuation.
2157                  */
2158                 while((++exec.instr)->op != OP_catch);
2159 
2160                 TRACE("unwind jmp %d stack_off %d\n", exec.instr->arg1.uint, exec.instr->arg2.uint);
2161 
2162                 stack_off = exec.instr->arg2.uint;
2163                 instr_jmp(&exec, exec.instr->arg1.uint);
2164 
2165                 if(exec.top > stack_off) {
2166                     stack_popn(&exec, exec.top-stack_off);
2167                 }else if(exec.top < stack_off) {
2168                     VARIANT v;
2169 
2170                     V_VT(&v) = VT_EMPTY;
2171                     while(exec.top < stack_off) {
2172                         hres = stack_push(&exec, &v);
2173                         if(FAILED(hres))
2174                             break;
2175                     }
2176                 }
2177 
2178                 continue;
2179             }else {
2180                 WARN("Failed %08x\n", hres);
2181                 stack_popn(&exec, exec.top);
2182                 break;
2183             }
2184         }
2185 
2186         exec.instr += op_move[op];
2187     }
2188 
2189     assert(!exec.top);
2190     if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)
2191         assert(V_VT(&exec.ret_val) == VT_EMPTY);
2192 
2193     if(SUCCEEDED(hres) && res) {
2194         *res = exec.ret_val;
2195         V_VT(&exec.ret_val) = VT_EMPTY;
2196     }
2197 
2198     release_exec(&exec);
2199     return hres;
2200 }
2201