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