[VBSCRIPT] Sync with Wine Staging 1.9.23. CORE-12409
[reactos.git] / reactos / dll / win32 / vbscript / interp.c
1 /*
2 * Copyright 2011 Jacek Caban for CodeWeavers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "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 cell_off = 0, dim_size = 1, i;
479 unsigned argc = arg_cnt(dp);
480 VARIANT *data;
481 LONG idx;
482 HRESULT hres;
483
484 if(!array) {
485 FIXME("NULL array\n");
486 return E_FAIL;
487 }
488
489 if(array->cDims != argc) {
490 FIXME("argc %d does not match cDims %d\n", dp->cArgs, array->cDims);
491 return E_FAIL;
492 }
493
494 for(i=0; i < argc; i++) {
495 hres = to_int(get_arg(dp, i), &idx);
496 if(FAILED(hres))
497 return hres;
498
499 idx -= array->rgsabound[i].lLbound;
500 if(idx >= array->rgsabound[i].cElements) {
501 FIXME("out of bound element %d in dim %d of size %d\n", idx, i+1, array->rgsabound[i].cElements);
502 return E_FAIL;
503 }
504
505 cell_off += idx*dim_size;
506 dim_size *= array->rgsabound[i].cElements;
507 }
508
509 hres = SafeArrayAccessData(array, (void**)&data);
510 if(FAILED(hres))
511 return hres;
512
513 *ret = data+cell_off;
514
515 SafeArrayUnaccessData(array);
516 return S_OK;
517 }
518
519 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
520 {
521 BSTR identifier = ctx->instr->arg1.bstr;
522 const unsigned arg_cnt = ctx->instr->arg2.uint;
523 DISPPARAMS dp;
524 ref_t ref;
525 HRESULT hres;
526
527 hres = lookup_identifier(ctx, identifier, VBDISP_CALLGET, &ref);
528 if(FAILED(hres))
529 return hres;
530
531 switch(ref.type) {
532 case REF_VAR:
533 case REF_CONST: {
534 VARIANT *v;
535
536 if(!res) {
537 FIXME("REF_VAR no res\n");
538 return E_NOTIMPL;
539 }
540
541 v = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
542
543 if(arg_cnt) {
544 SAFEARRAY *array = NULL;
545
546 switch(V_VT(v)) {
547 case VT_ARRAY|VT_BYREF|VT_VARIANT:
548 array = *V_ARRAYREF(ref.u.v);
549 break;
550 case VT_ARRAY|VT_VARIANT:
551 array = V_ARRAY(ref.u.v);
552 break;
553 case VT_DISPATCH:
554 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
555 hres = disp_call(ctx->script, V_DISPATCH(v), DISPID_VALUE, &dp, res);
556 if(FAILED(hres))
557 return hres;
558 break;
559 default:
560 FIXME("arguments not implemented\n");
561 return E_NOTIMPL;
562 }
563
564 if(!array)
565 break;
566
567 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
568 hres = array_access(ctx, array, &dp, &v);
569 if(FAILED(hres))
570 return hres;
571 }
572
573 V_VT(res) = VT_BYREF|VT_VARIANT;
574 V_BYREF(res) = v;
575 break;
576 }
577 case REF_DISP:
578 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
579 hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
580 if(FAILED(hres))
581 return hres;
582 break;
583 case REF_FUNC:
584 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
585 hres = exec_script(ctx->script, ref.u.f, NULL, &dp, res);
586 if(FAILED(hres))
587 return hres;
588 break;
589 case REF_OBJ:
590 if(arg_cnt) {
591 FIXME("arguments on object\n");
592 return E_NOTIMPL;
593 }
594
595 if(res) {
596 IDispatch_AddRef(ref.u.obj);
597 V_VT(res) = VT_DISPATCH;
598 V_DISPATCH(res) = ref.u.obj;
599 }
600 break;
601 case REF_NONE:
602 if(res && !ctx->func->code_ctx->option_explicit && arg_cnt == 0) {
603 VARIANT *new;
604 hres = add_dynamic_var(ctx, identifier, FALSE, &new);
605 if(FAILED(hres))
606 return hres;
607 V_VT(res) = VT_BYREF|VT_VARIANT;
608 V_BYREF(res) = new;
609 break;
610 }
611 FIXME("%s not found\n", debugstr_w(identifier));
612 return DISP_E_UNKNOWNNAME;
613 }
614
615 stack_popn(ctx, arg_cnt);
616 return S_OK;
617 }
618
619 static HRESULT interp_icall(exec_ctx_t *ctx)
620 {
621 VARIANT v;
622 HRESULT hres;
623
624 TRACE("\n");
625
626 hres = do_icall(ctx, &v);
627 if(FAILED(hres))
628 return hres;
629
630 return stack_push(ctx, &v);
631 }
632
633 static HRESULT interp_icallv(exec_ctx_t *ctx)
634 {
635 TRACE("\n");
636 return do_icall(ctx, NULL);
637 }
638
639 static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res)
640 {
641 const BSTR identifier = ctx->instr->arg1.bstr;
642 const unsigned arg_cnt = ctx->instr->arg2.uint;
643 IDispatch *obj;
644 DISPPARAMS dp;
645 DISPID id;
646 HRESULT hres;
647
648 hres = stack_pop_disp(ctx, &obj);
649 if(FAILED(hres))
650 return hres;
651
652 if(!obj) {
653 FIXME("NULL obj\n");
654 return E_FAIL;
655 }
656
657 vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
658
659 hres = disp_get_id(obj, identifier, VBDISP_CALLGET, FALSE, &id);
660 if(SUCCEEDED(hres))
661 hres = disp_call(ctx->script, obj, id, &dp, res);
662 IDispatch_Release(obj);
663 if(FAILED(hres))
664 return hres;
665
666 stack_popn(ctx, arg_cnt);
667 return S_OK;
668 }
669
670 static HRESULT interp_mcall(exec_ctx_t *ctx)
671 {
672 VARIANT res;
673 HRESULT hres;
674
675 TRACE("\n");
676
677 hres = do_mcall(ctx, &res);
678 if(FAILED(hres))
679 return hres;
680
681 return stack_push(ctx, &res);
682 }
683
684 static HRESULT interp_mcallv(exec_ctx_t *ctx)
685 {
686 TRACE("\n");
687
688 return do_mcall(ctx, NULL);
689 }
690
691 static HRESULT assign_value(exec_ctx_t *ctx, VARIANT *dst, VARIANT *src, WORD flags)
692 {
693 HRESULT hres;
694
695 hres = VariantCopyInd(dst, src);
696 if(FAILED(hres))
697 return hres;
698
699 if(V_VT(dst) == VT_DISPATCH && !(flags & DISPATCH_PROPERTYPUTREF)) {
700 VARIANT value;
701
702 hres = get_disp_value(ctx->script, V_DISPATCH(dst), &value);
703 IDispatch_Release(V_DISPATCH(dst));
704 if(FAILED(hres))
705 return hres;
706
707 *dst = value;
708 }
709
710 return S_OK;
711 }
712
713 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, WORD flags, DISPPARAMS *dp)
714 {
715 ref_t ref;
716 HRESULT hres;
717
718 hres = lookup_identifier(ctx, name, VBDISP_LET, &ref);
719 if(FAILED(hres))
720 return hres;
721
722 switch(ref.type) {
723 case REF_VAR: {
724 VARIANT *v = ref.u.v;
725
726 if(V_VT(v) == (VT_VARIANT|VT_BYREF))
727 v = V_VARIANTREF(v);
728
729 if(arg_cnt(dp)) {
730 SAFEARRAY *array;
731
732 if(!(V_VT(v) & VT_ARRAY)) {
733 FIXME("array assign on type %d\n", V_VT(v));
734 return E_FAIL;
735 }
736
737 switch(V_VT(v)) {
738 case VT_ARRAY|VT_BYREF|VT_VARIANT:
739 array = *V_ARRAYREF(v);
740 break;
741 case VT_ARRAY|VT_VARIANT:
742 array = V_ARRAY(v);
743 break;
744 default:
745 FIXME("Unsupported array type %x\n", V_VT(v));
746 return E_NOTIMPL;
747 }
748
749 if(!array) {
750 FIXME("null array\n");
751 return E_FAIL;
752 }
753
754 hres = array_access(ctx, array, dp, &v);
755 if(FAILED(hres))
756 return hres;
757 }else if(V_VT(v) == (VT_ARRAY|VT_BYREF|VT_VARIANT)) {
758 FIXME("non-array assign\n");
759 return E_NOTIMPL;
760 }
761
762 hres = assign_value(ctx, v, dp->rgvarg, flags);
763 break;
764 }
765 case REF_DISP:
766 hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, flags, dp);
767 break;
768 case REF_FUNC:
769 FIXME("functions not implemented\n");
770 return E_NOTIMPL;
771 case REF_OBJ:
772 FIXME("REF_OBJ\n");
773 return E_NOTIMPL;
774 case REF_CONST:
775 FIXME("REF_CONST\n");
776 return E_NOTIMPL;
777 case REF_NONE:
778 if(ctx->func->code_ctx->option_explicit) {
779 FIXME("throw exception\n");
780 hres = E_FAIL;
781 }else {
782 VARIANT *new_var;
783
784 if(arg_cnt(dp)) {
785 FIXME("arg_cnt %d not supported\n", arg_cnt(dp));
786 return E_NOTIMPL;
787 }
788
789 TRACE("creating variable %s\n", debugstr_w(name));
790 hres = add_dynamic_var(ctx, name, FALSE, &new_var);
791 if(SUCCEEDED(hres))
792 hres = assign_value(ctx, new_var, dp->rgvarg, flags);
793 }
794 }
795
796 return hres;
797 }
798
799 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
800 {
801 const BSTR arg = ctx->instr->arg1.bstr;
802 const unsigned arg_cnt = ctx->instr->arg2.uint;
803 DISPPARAMS dp;
804 HRESULT hres;
805
806 TRACE("%s\n", debugstr_w(arg));
807
808 vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
809 hres = assign_ident(ctx, arg, DISPATCH_PROPERTYPUT, &dp);
810 if(FAILED(hres))
811 return hres;
812
813 stack_popn(ctx, arg_cnt+1);
814 return S_OK;
815 }
816
817 static HRESULT interp_set_ident(exec_ctx_t *ctx)
818 {
819 const BSTR arg = ctx->instr->arg1.bstr;
820 const unsigned arg_cnt = ctx->instr->arg2.uint;
821 DISPPARAMS dp;
822 HRESULT hres;
823
824 TRACE("%s\n", debugstr_w(arg));
825
826 if(arg_cnt) {
827 FIXME("arguments not supported\n");
828 return E_NOTIMPL;
829 }
830
831 hres = stack_assume_disp(ctx, 0, NULL);
832 if(FAILED(hres))
833 return hres;
834
835 vbstack_to_dp(ctx, 0, TRUE, &dp);
836 hres = assign_ident(ctx, ctx->instr->arg1.bstr, DISPATCH_PROPERTYPUTREF, &dp);
837 if(FAILED(hres))
838 return hres;
839
840 stack_popn(ctx, 1);
841 return S_OK;
842 }
843
844 static HRESULT interp_assign_member(exec_ctx_t *ctx)
845 {
846 BSTR identifier = ctx->instr->arg1.bstr;
847 const unsigned arg_cnt = ctx->instr->arg2.uint;
848 IDispatch *obj;
849 DISPPARAMS dp;
850 DISPID id;
851 HRESULT hres;
852
853 TRACE("%s\n", debugstr_w(identifier));
854
855 hres = stack_assume_disp(ctx, arg_cnt+1, &obj);
856 if(FAILED(hres))
857 return hres;
858
859 if(!obj) {
860 FIXME("NULL obj\n");
861 return E_FAIL;
862 }
863
864 hres = disp_get_id(obj, identifier, VBDISP_LET, FALSE, &id);
865 if(SUCCEEDED(hres)) {
866 vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
867 hres = disp_propput(ctx->script, obj, id, DISPATCH_PROPERTYPUT, &dp);
868 }
869 if(FAILED(hres))
870 return hres;
871
872 stack_popn(ctx, arg_cnt+2);
873 return S_OK;
874 }
875
876 static HRESULT interp_set_member(exec_ctx_t *ctx)
877 {
878 BSTR identifier = ctx->instr->arg1.bstr;
879 const unsigned arg_cnt = ctx->instr->arg2.uint;
880 IDispatch *obj;
881 DISPPARAMS dp;
882 DISPID id;
883 HRESULT hres;
884
885 TRACE("%s\n", debugstr_w(identifier));
886
887 if(arg_cnt) {
888 FIXME("arguments not supported\n");
889 return E_NOTIMPL;
890 }
891
892 hres = stack_assume_disp(ctx, 1, &obj);
893 if(FAILED(hres))
894 return hres;
895
896 if(!obj) {
897 FIXME("NULL obj\n");
898 return E_FAIL;
899 }
900
901 hres = stack_assume_disp(ctx, 0, NULL);
902 if(FAILED(hres))
903 return hres;
904
905 hres = disp_get_id(obj, identifier, VBDISP_SET, FALSE, &id);
906 if(SUCCEEDED(hres)) {
907 vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
908 hres = disp_propput(ctx->script, obj, id, DISPATCH_PROPERTYPUTREF, &dp);
909 }
910 if(FAILED(hres))
911 return hres;
912
913 stack_popn(ctx, 2);
914 return S_OK;
915 }
916
917 static HRESULT interp_const(exec_ctx_t *ctx)
918 {
919 BSTR arg = ctx->instr->arg1.bstr;
920 VARIANT *v;
921 ref_t ref;
922 HRESULT hres;
923
924 TRACE("%s\n", debugstr_w(arg));
925
926 assert(ctx->func->type == FUNC_GLOBAL);
927
928 hres = lookup_identifier(ctx, arg, VBDISP_CALLGET, &ref);
929 if(FAILED(hres))
930 return hres;
931
932 if(ref.type != REF_NONE) {
933 FIXME("%s already defined\n", debugstr_w(arg));
934 return E_FAIL;
935 }
936
937 hres = stack_assume_val(ctx, 0);
938 if(FAILED(hres))
939 return hres;
940
941 hres = add_dynamic_var(ctx, arg, TRUE, &v);
942 if(FAILED(hres))
943 return hres;
944
945 *v = *stack_pop(ctx);
946 return S_OK;
947 }
948
949 static HRESULT interp_val(exec_ctx_t *ctx)
950 {
951 variant_val_t val;
952 VARIANT v;
953 HRESULT hres;
954
955 TRACE("\n");
956
957 hres = stack_pop_val(ctx, &val);
958 if(FAILED(hres))
959 return hres;
960
961 if(!val.owned) {
962 V_VT(&v) = VT_EMPTY;
963 hres = VariantCopy(&v, val.v);
964 if(FAILED(hres))
965 return hres;
966 }
967
968 return stack_push(ctx, val.owned ? val.v : &v);
969 }
970
971 static HRESULT interp_pop(exec_ctx_t *ctx)
972 {
973 const unsigned n = ctx->instr->arg1.uint;
974
975 TRACE("%u\n", n);
976
977 stack_popn(ctx, n);
978 return S_OK;
979 }
980
981 static HRESULT interp_new(exec_ctx_t *ctx)
982 {
983 const WCHAR *arg = ctx->instr->arg1.bstr;
984 class_desc_t *class_desc;
985 vbdisp_t *obj;
986 VARIANT v;
987 HRESULT hres;
988
989 static const WCHAR regexpW[] = {'r','e','g','e','x','p',0};
990
991 TRACE("%s\n", debugstr_w(arg));
992
993 if(!strcmpiW(arg, regexpW)) {
994 V_VT(&v) = VT_DISPATCH;
995 hres = create_regexp(&V_DISPATCH(&v));
996 if(FAILED(hres))
997 return hres;
998
999 return stack_push(ctx, &v);
1000 }
1001
1002 for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
1003 if(!strcmpiW(class_desc->name, arg))
1004 break;
1005 }
1006 if(!class_desc) {
1007 FIXME("Class %s not found\n", debugstr_w(arg));
1008 return E_FAIL;
1009 }
1010
1011 hres = create_vbdisp(class_desc, &obj);
1012 if(FAILED(hres))
1013 return hres;
1014
1015 V_VT(&v) = VT_DISPATCH;
1016 V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
1017 return stack_push(ctx, &v);
1018 }
1019
1020 static HRESULT interp_dim(exec_ctx_t *ctx)
1021 {
1022 const BSTR ident = ctx->instr->arg1.bstr;
1023 const unsigned array_id = ctx->instr->arg2.uint;
1024 const array_desc_t *array_desc;
1025 ref_t ref;
1026 HRESULT hres;
1027
1028 TRACE("%s\n", debugstr_w(ident));
1029
1030 assert(array_id < ctx->func->array_cnt);
1031 if(!ctx->arrays) {
1032 ctx->arrays = heap_alloc_zero(ctx->func->array_cnt * sizeof(SAFEARRAY*));
1033 if(!ctx->arrays)
1034 return E_OUTOFMEMORY;
1035 }
1036
1037 hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref);
1038 if(FAILED(hres)) {
1039 FIXME("lookup %s failed: %08x\n", debugstr_w(ident), hres);
1040 return hres;
1041 }
1042
1043 if(ref.type != REF_VAR) {
1044 FIXME("got ref.type = %d\n", ref.type);
1045 return E_FAIL;
1046 }
1047
1048 if(ctx->arrays[array_id]) {
1049 FIXME("Array already initialized\n");
1050 return E_FAIL;
1051 }
1052
1053 array_desc = ctx->func->array_descs + array_id;
1054 if(array_desc->dim_cnt) {
1055 ctx->arrays[array_id] = SafeArrayCreate(VT_VARIANT, array_desc->dim_cnt, array_desc->bounds);
1056 if(!ctx->arrays[array_id])
1057 return E_OUTOFMEMORY;
1058 }
1059
1060 V_VT(ref.u.v) = VT_ARRAY|VT_BYREF|VT_VARIANT;
1061 V_ARRAYREF(ref.u.v) = ctx->arrays+array_id;
1062 return S_OK;
1063 }
1064
1065 static HRESULT interp_step(exec_ctx_t *ctx)
1066 {
1067 const BSTR ident = ctx->instr->arg2.bstr;
1068 BOOL gteq_zero;
1069 VARIANT zero;
1070 ref_t ref;
1071 HRESULT hres;
1072
1073 TRACE("%s\n", debugstr_w(ident));
1074
1075 V_VT(&zero) = VT_I2;
1076 V_I2(&zero) = 0;
1077 hres = VarCmp(stack_top(ctx, 0), &zero, ctx->script->lcid, 0);
1078 if(FAILED(hres))
1079 return hres;
1080
1081 gteq_zero = hres == VARCMP_GT || hres == VARCMP_EQ;
1082
1083 hres = lookup_identifier(ctx, ident, VBDISP_ANY, &ref);
1084 if(FAILED(hres))
1085 return hres;
1086
1087 if(ref.type != REF_VAR) {
1088 FIXME("%s is not REF_VAR\n", debugstr_w(ident));
1089 return E_FAIL;
1090 }
1091
1092 hres = VarCmp(ref.u.v, stack_top(ctx, 1), ctx->script->lcid, 0);
1093 if(FAILED(hres))
1094 return hres;
1095
1096 if(hres == VARCMP_EQ || hres == (gteq_zero ? VARCMP_LT : VARCMP_GT)) {
1097 ctx->instr++;
1098 }else {
1099 stack_popn(ctx, 2);
1100 instr_jmp(ctx, ctx->instr->arg1.uint);
1101 }
1102 return S_OK;
1103 }
1104
1105 static HRESULT interp_newenum(exec_ctx_t *ctx)
1106 {
1107 variant_val_t v;
1108 VARIANT *r;
1109 HRESULT hres;
1110
1111 TRACE("\n");
1112
1113 stack_pop_deref(ctx, &v);
1114 assert(V_VT(stack_top(ctx, 0)) == VT_EMPTY);
1115 r = stack_top(ctx, 0);
1116
1117 switch(V_VT(v.v)) {
1118 case VT_DISPATCH|VT_BYREF:
1119 case VT_DISPATCH: {
1120 IEnumVARIANT *iter;
1121 DISPPARAMS dp = {0};
1122 VARIANT iterv;
1123
1124 hres = disp_call(ctx->script, V_ISBYREF(v.v) ? *V_DISPATCHREF(v.v) : V_DISPATCH(v.v), DISPID_NEWENUM, &dp, &iterv);
1125 release_val(&v);
1126 if(FAILED(hres))
1127 return hres;
1128
1129 if(V_VT(&iterv) != VT_UNKNOWN && V_VT(&iterv) != VT_DISPATCH) {
1130 FIXME("Unsupported iterv %s\n", debugstr_variant(&iterv));
1131 VariantClear(&iterv);
1132 return hres;
1133 }
1134
1135 hres = IUnknown_QueryInterface(V_UNKNOWN(&iterv), &IID_IEnumVARIANT, (void**)&iter);
1136 IUnknown_Release(V_UNKNOWN(&iterv));
1137 if(FAILED(hres)) {
1138 FIXME("Could not get IEnumVARIANT iface: %08x\n", hres);
1139 return hres;
1140 }
1141
1142 V_VT(r) = VT_UNKNOWN;
1143 V_UNKNOWN(r) = (IUnknown*)iter;
1144 break;
1145 }
1146 default:
1147 FIXME("Unsupported for %s\n", debugstr_variant(v.v));
1148 release_val(&v);
1149 return E_NOTIMPL;
1150 }
1151
1152 return S_OK;
1153 }
1154
1155 static HRESULT interp_enumnext(exec_ctx_t *ctx)
1156 {
1157 const unsigned loop_end = ctx->instr->arg1.uint;
1158 const BSTR ident = ctx->instr->arg2.bstr;
1159 VARIANT v;
1160 DISPPARAMS dp = {&v, &propput_dispid, 1, 1};
1161 IEnumVARIANT *iter;
1162 BOOL do_continue;
1163 HRESULT hres;
1164
1165 TRACE("\n");
1166
1167 if(V_VT(stack_top(ctx, 0)) == VT_EMPTY) {
1168 FIXME("uninitialized\n");
1169 return E_FAIL;
1170 }
1171
1172 assert(V_VT(stack_top(ctx, 0)) == VT_UNKNOWN);
1173 iter = (IEnumVARIANT*)V_UNKNOWN(stack_top(ctx, 0));
1174
1175 V_VT(&v) = VT_EMPTY;
1176 hres = IEnumVARIANT_Next(iter, 1, &v, NULL);
1177 if(FAILED(hres))
1178 return hres;
1179
1180 do_continue = hres == S_OK;
1181 hres = assign_ident(ctx, ident, DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF, &dp);
1182 VariantClear(&v);
1183 if(FAILED(hres))
1184 return hres;
1185
1186 if(do_continue) {
1187 ctx->instr++;
1188 }else {
1189 stack_pop(ctx);
1190 instr_jmp(ctx, loop_end);
1191 }
1192 return S_OK;
1193 }
1194
1195 static HRESULT interp_jmp(exec_ctx_t *ctx)
1196 {
1197 const unsigned arg = ctx->instr->arg1.uint;
1198
1199 TRACE("%u\n", arg);
1200
1201 instr_jmp(ctx, arg);
1202 return S_OK;
1203 }
1204
1205 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
1206 {
1207 const unsigned arg = ctx->instr->arg1.uint;
1208 HRESULT hres;
1209 BOOL b;
1210
1211 TRACE("%u\n", arg);
1212
1213 hres = stack_pop_bool(ctx, &b);
1214 if(FAILED(hres))
1215 return hres;
1216
1217 if(b)
1218 ctx->instr++;
1219 else
1220 instr_jmp(ctx, ctx->instr->arg1.uint);
1221 return S_OK;
1222 }
1223
1224 static HRESULT interp_jmp_true(exec_ctx_t *ctx)
1225 {
1226 const unsigned arg = ctx->instr->arg1.uint;
1227 HRESULT hres;
1228 BOOL b;
1229
1230 TRACE("%u\n", arg);
1231
1232 hres = stack_pop_bool(ctx, &b);
1233 if(FAILED(hres))
1234 return hres;
1235
1236 if(b)
1237 instr_jmp(ctx, ctx->instr->arg1.uint);
1238 else
1239 ctx->instr++;
1240 return S_OK;
1241 }
1242
1243 static HRESULT interp_ret(exec_ctx_t *ctx)
1244 {
1245 TRACE("\n");
1246
1247 ctx->instr = NULL;
1248 return S_OK;
1249 }
1250
1251 static HRESULT interp_stop(exec_ctx_t *ctx)
1252 {
1253 WARN("\n");
1254
1255 /* NOTE: this should have effect in debugging mode (that we don't support yet) */
1256 return S_OK;
1257 }
1258
1259 static HRESULT interp_me(exec_ctx_t *ctx)
1260 {
1261 VARIANT v;
1262
1263 TRACE("\n");
1264
1265 IDispatch_AddRef(ctx->this_obj);
1266 V_VT(&v) = VT_DISPATCH;
1267 V_DISPATCH(&v) = ctx->this_obj;
1268 return stack_push(ctx, &v);
1269 }
1270
1271 static HRESULT interp_bool(exec_ctx_t *ctx)
1272 {
1273 const VARIANT_BOOL arg = ctx->instr->arg1.lng;
1274 VARIANT v;
1275
1276 TRACE("%s\n", arg ? "true" : "false");
1277
1278 V_VT(&v) = VT_BOOL;
1279 V_BOOL(&v) = arg;
1280 return stack_push(ctx, &v);
1281 }
1282
1283 static HRESULT interp_errmode(exec_ctx_t *ctx)
1284 {
1285 const int err_mode = ctx->instr->arg1.uint;
1286
1287 TRACE("%d\n", err_mode);
1288
1289 ctx->resume_next = err_mode;
1290 ctx->script->err_number = S_OK;
1291 return S_OK;
1292 }
1293
1294 static HRESULT interp_string(exec_ctx_t *ctx)
1295 {
1296 VARIANT v;
1297
1298 TRACE("\n");
1299
1300 V_VT(&v) = VT_BSTR;
1301 V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
1302 if(!V_BSTR(&v))
1303 return E_OUTOFMEMORY;
1304
1305 return stack_push(ctx, &v);
1306 }
1307
1308 static HRESULT interp_long(exec_ctx_t *ctx)
1309 {
1310 const LONG arg = ctx->instr->arg1.lng;
1311 VARIANT v;
1312
1313 TRACE("%d\n", arg);
1314
1315 V_VT(&v) = VT_I4;
1316 V_I4(&v) = arg;
1317 return stack_push(ctx, &v);
1318 }
1319
1320 static HRESULT interp_short(exec_ctx_t *ctx)
1321 {
1322 const LONG arg = ctx->instr->arg1.lng;
1323 VARIANT v;
1324
1325 TRACE("%d\n", arg);
1326
1327 V_VT(&v) = VT_I2;
1328 V_I2(&v) = arg;
1329 return stack_push(ctx, &v);
1330 }
1331
1332 static HRESULT interp_double(exec_ctx_t *ctx)
1333 {
1334 const DOUBLE *arg = ctx->instr->arg1.dbl;
1335 VARIANT v;
1336
1337 TRACE("%lf\n", *arg);
1338
1339 V_VT(&v) = VT_R8;
1340 V_R8(&v) = *arg;
1341 return stack_push(ctx, &v);
1342 }
1343
1344 static HRESULT interp_empty(exec_ctx_t *ctx)
1345 {
1346 VARIANT v;
1347
1348 TRACE("\n");
1349
1350 V_VT(&v) = VT_EMPTY;
1351 return stack_push(ctx, &v);
1352 }
1353
1354 static HRESULT interp_null(exec_ctx_t *ctx)
1355 {
1356 TRACE("\n");
1357 return stack_push_null(ctx);
1358 }
1359
1360 static HRESULT interp_nothing(exec_ctx_t *ctx)
1361 {
1362 VARIANT v;
1363
1364 TRACE("\n");
1365
1366 V_VT(&v) = VT_DISPATCH;
1367 V_DISPATCH(&v) = NULL;
1368 return stack_push(ctx, &v);
1369 }
1370
1371 static HRESULT interp_hres(exec_ctx_t *ctx)
1372 {
1373 const unsigned arg = ctx->instr->arg1.uint;
1374 VARIANT v;
1375
1376 TRACE("%d\n", arg);
1377
1378 V_VT(&v) = VT_ERROR;
1379 V_ERROR(&v) = arg;
1380 return stack_push(ctx, &v);
1381 }
1382
1383 static HRESULT interp_not(exec_ctx_t *ctx)
1384 {
1385 variant_val_t val;
1386 VARIANT v;
1387 HRESULT hres;
1388
1389 TRACE("\n");
1390
1391 hres = stack_pop_val(ctx, &val);
1392 if(FAILED(hres))
1393 return hres;
1394
1395 hres = VarNot(val.v, &v);
1396 release_val(&val);
1397 if(FAILED(hres))
1398 return hres;
1399
1400 return stack_push(ctx, &v);
1401 }
1402
1403 static HRESULT interp_and(exec_ctx_t *ctx)
1404 {
1405 variant_val_t r, l;
1406 VARIANT v;
1407 HRESULT hres;
1408
1409 TRACE("\n");
1410
1411 hres = stack_pop_val(ctx, &r);
1412 if(FAILED(hres))
1413 return hres;
1414
1415 hres = stack_pop_val(ctx, &l);
1416 if(SUCCEEDED(hres)) {
1417 hres = VarAnd(l.v, r.v, &v);
1418 release_val(&l);
1419 }
1420 release_val(&r);
1421 if(FAILED(hres))
1422 return hres;
1423
1424 return stack_push(ctx, &v);
1425 }
1426
1427 static HRESULT interp_or(exec_ctx_t *ctx)
1428 {
1429 variant_val_t r, l;
1430 VARIANT v;
1431 HRESULT hres;
1432
1433 TRACE("\n");
1434
1435 hres = stack_pop_val(ctx, &r);
1436 if(FAILED(hres))
1437 return hres;
1438
1439 hres = stack_pop_val(ctx, &l);
1440 if(SUCCEEDED(hres)) {
1441 hres = VarOr(l.v, r.v, &v);
1442 release_val(&l);
1443 }
1444 release_val(&r);
1445 if(FAILED(hres))
1446 return hres;
1447
1448 return stack_push(ctx, &v);
1449 }
1450
1451 static HRESULT interp_xor(exec_ctx_t *ctx)
1452 {
1453 variant_val_t r, l;
1454 VARIANT v;
1455 HRESULT hres;
1456
1457 TRACE("\n");
1458
1459 hres = stack_pop_val(ctx, &r);
1460 if(FAILED(hres))
1461 return hres;
1462
1463 hres = stack_pop_val(ctx, &l);
1464 if(SUCCEEDED(hres)) {
1465 hres = VarXor(l.v, r.v, &v);
1466 release_val(&l);
1467 }
1468 release_val(&r);
1469 if(FAILED(hres))
1470 return hres;
1471
1472 return stack_push(ctx, &v);
1473 }
1474
1475 static HRESULT interp_eqv(exec_ctx_t *ctx)
1476 {
1477 variant_val_t r, l;
1478 VARIANT v;
1479 HRESULT hres;
1480
1481 TRACE("\n");
1482
1483 hres = stack_pop_val(ctx, &r);
1484 if(FAILED(hres))
1485 return hres;
1486
1487 hres = stack_pop_val(ctx, &l);
1488 if(SUCCEEDED(hres)) {
1489 hres = VarEqv(l.v, r.v, &v);
1490 release_val(&l);
1491 }
1492 release_val(&r);
1493 if(FAILED(hres))
1494 return hres;
1495
1496 return stack_push(ctx, &v);
1497 }
1498
1499 static HRESULT interp_imp(exec_ctx_t *ctx)
1500 {
1501 variant_val_t r, l;
1502 VARIANT v;
1503 HRESULT hres;
1504
1505 TRACE("\n");
1506
1507 hres = stack_pop_val(ctx, &r);
1508 if(FAILED(hres))
1509 return hres;
1510
1511 hres = stack_pop_val(ctx, &l);
1512 if(SUCCEEDED(hres)) {
1513 hres = VarImp(l.v, r.v, &v);
1514 release_val(&l);
1515 }
1516 release_val(&r);
1517 if(FAILED(hres))
1518 return hres;
1519
1520 return stack_push(ctx, &v);
1521 }
1522
1523 static HRESULT var_cmp(exec_ctx_t *ctx, VARIANT *l, VARIANT *r)
1524 {
1525 TRACE("%s %s\n", debugstr_variant(l), debugstr_variant(r));
1526
1527 /* FIXME: Fix comparing string to number */
1528
1529 return VarCmp(l, r, ctx->script->lcid, 0);
1530 }
1531
1532 static HRESULT cmp_oper(exec_ctx_t *ctx)
1533 {
1534 variant_val_t l, r;
1535 HRESULT hres;
1536
1537 hres = stack_pop_val(ctx, &r);
1538 if(FAILED(hres))
1539 return hres;
1540
1541 hres = stack_pop_val(ctx, &l);
1542 if(SUCCEEDED(hres)) {
1543 hres = var_cmp(ctx, l.v, r.v);
1544 release_val(&l);
1545 }
1546
1547 release_val(&r);
1548 return hres;
1549 }
1550
1551 static HRESULT interp_equal(exec_ctx_t *ctx)
1552 {
1553 VARIANT v;
1554 HRESULT hres;
1555
1556 TRACE("\n");
1557
1558 hres = cmp_oper(ctx);
1559 if(FAILED(hres))
1560 return hres;
1561 if(hres == VARCMP_NULL)
1562 return stack_push_null(ctx);
1563
1564 V_VT(&v) = VT_BOOL;
1565 V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1566 return stack_push(ctx, &v);
1567 }
1568
1569 static HRESULT interp_nequal(exec_ctx_t *ctx)
1570 {
1571 VARIANT v;
1572 HRESULT hres;
1573
1574 TRACE("\n");
1575
1576 hres = cmp_oper(ctx);
1577 if(FAILED(hres))
1578 return hres;
1579 if(hres == VARCMP_NULL)
1580 return stack_push_null(ctx);
1581
1582 V_VT(&v) = VT_BOOL;
1583 V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1584 return stack_push(ctx, &v);
1585 }
1586
1587 static HRESULT interp_gt(exec_ctx_t *ctx)
1588 {
1589 VARIANT v;
1590 HRESULT hres;
1591
1592 TRACE("\n");
1593
1594 hres = cmp_oper(ctx);
1595 if(FAILED(hres))
1596 return hres;
1597 if(hres == VARCMP_NULL)
1598 return stack_push_null(ctx);
1599
1600 V_VT(&v) = VT_BOOL;
1601 V_BOOL(&v) = hres == VARCMP_GT ? VARIANT_TRUE : VARIANT_FALSE;
1602 return stack_push(ctx, &v);
1603 }
1604
1605 static HRESULT interp_gteq(exec_ctx_t *ctx)
1606 {
1607 VARIANT v;
1608 HRESULT hres;
1609
1610 TRACE("\n");
1611
1612 hres = cmp_oper(ctx);
1613 if(FAILED(hres))
1614 return hres;
1615 if(hres == VARCMP_NULL)
1616 return stack_push_null(ctx);
1617
1618 V_VT(&v) = VT_BOOL;
1619 V_BOOL(&v) = hres == VARCMP_GT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1620 return stack_push(ctx, &v);
1621 }
1622
1623 static HRESULT interp_lt(exec_ctx_t *ctx)
1624 {
1625 VARIANT v;
1626 HRESULT hres;
1627
1628 TRACE("\n");
1629
1630 hres = cmp_oper(ctx);
1631 if(FAILED(hres))
1632 return hres;
1633 if(hres == VARCMP_NULL)
1634 return stack_push_null(ctx);
1635
1636 V_VT(&v) = VT_BOOL;
1637 V_BOOL(&v) = hres == VARCMP_LT ? VARIANT_TRUE : VARIANT_FALSE;
1638 return stack_push(ctx, &v);
1639 }
1640
1641 static HRESULT interp_lteq(exec_ctx_t *ctx)
1642 {
1643 VARIANT v;
1644 HRESULT hres;
1645
1646 TRACE("\n");
1647
1648 hres = cmp_oper(ctx);
1649 if(FAILED(hres))
1650 return hres;
1651 if(hres == VARCMP_NULL)
1652 return stack_push_null(ctx);
1653
1654 V_VT(&v) = VT_BOOL;
1655 V_BOOL(&v) = hres == VARCMP_LT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1656 return stack_push(ctx, &v);
1657 }
1658
1659 static HRESULT interp_case(exec_ctx_t *ctx)
1660 {
1661 const unsigned arg = ctx->instr->arg1.uint;
1662 variant_val_t v;
1663 HRESULT hres;
1664
1665 TRACE("%d\n", arg);
1666
1667 hres = stack_pop_val(ctx, &v);
1668 if(FAILED(hres))
1669 return hres;
1670
1671 hres = var_cmp(ctx, stack_top(ctx, 0), v.v);
1672 release_val(&v);
1673 if(FAILED(hres))
1674 return hres;
1675
1676 if(hres == VARCMP_EQ) {
1677 stack_popn(ctx, 1);
1678 instr_jmp(ctx, arg);
1679 }else {
1680 ctx->instr++;
1681 }
1682
1683 return S_OK;
1684 }
1685
1686 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, VARIANT_BOOL *ret)
1687 {
1688 IObjectIdentity *identity;
1689 IUnknown *unk1, *unk2;
1690 HRESULT hres;
1691
1692 if(disp1 == disp2) {
1693 *ret = VARIANT_TRUE;
1694 return S_OK;
1695 }
1696
1697 if(!disp1 || !disp2) {
1698 *ret = VARIANT_FALSE;
1699 return S_OK;
1700 }
1701
1702 hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
1703 if(FAILED(hres))
1704 return hres;
1705
1706 hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
1707 if(FAILED(hres)) {
1708 IUnknown_Release(unk1);
1709 return hres;
1710 }
1711
1712 if(unk1 == unk2) {
1713 *ret = VARIANT_TRUE;
1714 }else {
1715 hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
1716 if(SUCCEEDED(hres)) {
1717 hres = IObjectIdentity_IsEqualObject(identity, unk2);
1718 IObjectIdentity_Release(identity);
1719 *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
1720 }else {
1721 *ret = VARIANT_FALSE;
1722 }
1723 }
1724
1725 IUnknown_Release(unk1);
1726 IUnknown_Release(unk2);
1727 return S_OK;
1728 }
1729
1730 static HRESULT interp_is(exec_ctx_t *ctx)
1731 {
1732 IDispatch *l, *r;
1733 VARIANT v;
1734 HRESULT hres;
1735
1736 TRACE("\n");
1737
1738 hres = stack_pop_disp(ctx, &r);
1739 if(FAILED(hres))
1740 return hres;
1741
1742 hres = stack_pop_disp(ctx, &l);
1743 if(SUCCEEDED(hres)) {
1744 V_VT(&v) = VT_BOOL;
1745 hres = disp_cmp(l, r, &V_BOOL(&v));
1746 if(l)
1747 IDispatch_Release(l);
1748 }
1749 if(r)
1750 IDispatch_Release(r);
1751 if(FAILED(hres))
1752 return hres;
1753
1754 return stack_push(ctx, &v);
1755 }
1756
1757 static HRESULT interp_concat(exec_ctx_t *ctx)
1758 {
1759 variant_val_t r, l;
1760 VARIANT v;
1761 HRESULT hres;
1762
1763 TRACE("\n");
1764
1765 hres = stack_pop_val(ctx, &r);
1766 if(FAILED(hres))
1767 return hres;
1768
1769 hres = stack_pop_val(ctx, &l);
1770 if(SUCCEEDED(hres)) {
1771 hres = VarCat(l.v, r.v, &v);
1772 release_val(&l);
1773 }
1774 release_val(&r);
1775 if(FAILED(hres))
1776 return hres;
1777
1778 return stack_push(ctx, &v);
1779 }
1780
1781 static HRESULT interp_add(exec_ctx_t *ctx)
1782 {
1783 variant_val_t r, l;
1784 VARIANT v;
1785 HRESULT hres;
1786
1787 TRACE("\n");
1788
1789 hres = stack_pop_val(ctx, &r);
1790 if(FAILED(hres))
1791 return hres;
1792
1793 hres = stack_pop_val(ctx, &l);
1794 if(SUCCEEDED(hres)) {
1795 hres = VarAdd(l.v, r.v, &v);
1796 release_val(&l);
1797 }
1798 release_val(&r);
1799 if(FAILED(hres))
1800 return hres;
1801
1802 return stack_push(ctx, &v);
1803 }
1804
1805 static HRESULT interp_sub(exec_ctx_t *ctx)
1806 {
1807 variant_val_t r, l;
1808 VARIANT v;
1809 HRESULT hres;
1810
1811 TRACE("\n");
1812
1813 hres = stack_pop_val(ctx, &r);
1814 if(FAILED(hres))
1815 return hres;
1816
1817 hres = stack_pop_val(ctx, &l);
1818 if(SUCCEEDED(hres)) {
1819 hres = VarSub(l.v, r.v, &v);
1820 release_val(&l);
1821 }
1822 release_val(&r);
1823 if(FAILED(hres))
1824 return hres;
1825
1826 return stack_push(ctx, &v);
1827 }
1828
1829 static HRESULT interp_mod(exec_ctx_t *ctx)
1830 {
1831 variant_val_t r, l;
1832 VARIANT v;
1833 HRESULT hres;
1834
1835 TRACE("\n");
1836
1837 hres = stack_pop_val(ctx, &r);
1838 if(FAILED(hres))
1839 return hres;
1840
1841 hres = stack_pop_val(ctx, &l);
1842 if(SUCCEEDED(hres)) {
1843 hres = VarMod(l.v, r.v, &v);
1844 release_val(&l);
1845 }
1846 release_val(&r);
1847 if(FAILED(hres))
1848 return hres;
1849
1850 return stack_push(ctx, &v);
1851 }
1852
1853 static HRESULT interp_idiv(exec_ctx_t *ctx)
1854 {
1855 variant_val_t r, l;
1856 VARIANT v;
1857 HRESULT hres;
1858
1859 TRACE("\n");
1860
1861 hres = stack_pop_val(ctx, &r);
1862 if(FAILED(hres))
1863 return hres;
1864
1865 hres = stack_pop_val(ctx, &l);
1866 if(SUCCEEDED(hres)) {
1867 hres = VarIdiv(l.v, r.v, &v);
1868 release_val(&l);
1869 }
1870 release_val(&r);
1871 if(FAILED(hres))
1872 return hres;
1873
1874 return stack_push(ctx, &v);
1875 }
1876
1877 static HRESULT interp_div(exec_ctx_t *ctx)
1878 {
1879 variant_val_t r, l;
1880 VARIANT v;
1881 HRESULT hres;
1882
1883 TRACE("\n");
1884
1885 hres = stack_pop_val(ctx, &r);
1886 if(FAILED(hres))
1887 return hres;
1888
1889 hres = stack_pop_val(ctx, &l);
1890 if(SUCCEEDED(hres)) {
1891 hres = VarDiv(l.v, r.v, &v);
1892 release_val(&l);
1893 }
1894 release_val(&r);
1895 if(FAILED(hres))
1896 return hres;
1897
1898 return stack_push(ctx, &v);
1899 }
1900
1901 static HRESULT interp_mul(exec_ctx_t *ctx)
1902 {
1903 variant_val_t r, l;
1904 VARIANT v;
1905 HRESULT hres;
1906
1907 TRACE("\n");
1908
1909 hres = stack_pop_val(ctx, &r);
1910 if(FAILED(hres))
1911 return hres;
1912
1913 hres = stack_pop_val(ctx, &l);
1914 if(SUCCEEDED(hres)) {
1915 hres = VarMul(l.v, r.v, &v);
1916 release_val(&l);
1917 }
1918 release_val(&r);
1919 if(FAILED(hres))
1920 return hres;
1921
1922 return stack_push(ctx, &v);
1923 }
1924
1925 static HRESULT interp_exp(exec_ctx_t *ctx)
1926 {
1927 variant_val_t r, l;
1928 VARIANT v;
1929 HRESULT hres;
1930
1931 TRACE("\n");
1932
1933 hres = stack_pop_val(ctx, &r);
1934 if(FAILED(hres))
1935 return hres;
1936
1937 hres = stack_pop_val(ctx, &l);
1938 if(SUCCEEDED(hres)) {
1939 hres = VarPow(l.v, r.v, &v);
1940 release_val(&l);
1941 }
1942 release_val(&r);
1943 if(FAILED(hres))
1944 return hres;
1945
1946 return stack_push(ctx, &v);
1947 }
1948
1949 static HRESULT interp_neg(exec_ctx_t *ctx)
1950 {
1951 variant_val_t val;
1952 VARIANT v;
1953 HRESULT hres;
1954
1955 hres = stack_pop_val(ctx, &val);
1956 if(FAILED(hres))
1957 return hres;
1958
1959 hres = VarNeg(val.v, &v);
1960 release_val(&val);
1961 if(FAILED(hres))
1962 return hres;
1963
1964 return stack_push(ctx, &v);
1965 }
1966
1967 static HRESULT interp_incc(exec_ctx_t *ctx)
1968 {
1969 const BSTR ident = ctx->instr->arg1.bstr;
1970 VARIANT v;
1971 ref_t ref;
1972 HRESULT hres;
1973
1974 TRACE("\n");
1975
1976 hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref);
1977 if(FAILED(hres))
1978 return hres;
1979
1980 if(ref.type != REF_VAR) {
1981 FIXME("ref.type is not REF_VAR\n");
1982 return E_FAIL;
1983 }
1984
1985 hres = VarAdd(stack_top(ctx, 0), ref.u.v, &v);
1986 if(FAILED(hres))
1987 return hres;
1988
1989 VariantClear(ref.u.v);
1990 *ref.u.v = v;
1991 return S_OK;
1992 }
1993
1994 static HRESULT interp_catch(exec_ctx_t *ctx)
1995 {
1996 /* Nothing to do here, the OP is for unwinding only. */
1997 return S_OK;
1998 }
1999
2000 static const instr_func_t op_funcs[] = {
2001 #define X(x,n,a,b) interp_ ## x,
2002 OP_LIST
2003 #undef X
2004 };
2005
2006 static const unsigned op_move[] = {
2007 #define X(x,n,a,b) n,
2008 OP_LIST
2009 #undef X
2010 };
2011
2012 void release_dynamic_vars(dynamic_var_t *var)
2013 {
2014 while(var) {
2015 VariantClear(&var->v);
2016 var = var->next;
2017 }
2018 }
2019
2020 static void release_exec(exec_ctx_t *ctx)
2021 {
2022 unsigned i;
2023
2024 VariantClear(&ctx->ret_val);
2025 release_dynamic_vars(ctx->dynamic_vars);
2026
2027 if(ctx->this_obj)
2028 IDispatch_Release(ctx->this_obj);
2029
2030 if(ctx->args) {
2031 for(i=0; i < ctx->func->arg_cnt; i++)
2032 VariantClear(ctx->args+i);
2033 }
2034
2035 if(ctx->vars) {
2036 for(i=0; i < ctx->func->var_cnt; i++)
2037 VariantClear(ctx->vars+i);
2038 }
2039
2040 if(ctx->arrays) {
2041 for(i=0; i < ctx->func->var_cnt; i++) {
2042 if(ctx->arrays[i])
2043 SafeArrayDestroy(ctx->arrays[i]);
2044 }
2045 heap_free(ctx->arrays);
2046 }
2047
2048 heap_pool_free(&ctx->heap);
2049 heap_free(ctx->args);
2050 heap_free(ctx->vars);
2051 heap_free(ctx->stack);
2052 }
2053
2054 HRESULT exec_script(script_ctx_t *ctx, function_t *func, vbdisp_t *vbthis, DISPPARAMS *dp, VARIANT *res)
2055 {
2056 exec_ctx_t exec = {func->code_ctx};
2057 vbsop_t op;
2058 HRESULT hres = S_OK;
2059
2060 exec.code = func->code_ctx;
2061
2062 if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
2063 FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
2064 return E_FAIL;
2065 }
2066
2067 heap_pool_init(&exec.heap);
2068
2069 if(func->arg_cnt) {
2070 VARIANT *v;
2071 unsigned i;
2072
2073 exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
2074 if(!exec.args) {
2075 release_exec(&exec);
2076 return E_OUTOFMEMORY;
2077 }
2078
2079 for(i=0; i < func->arg_cnt; i++) {
2080 v = get_arg(dp, i);
2081 if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
2082 if(func->args[i].by_ref)
2083 exec.args[i] = *v;
2084 else
2085 hres = VariantCopyInd(exec.args+i, V_VARIANTREF(v));
2086 }else {
2087 hres = VariantCopyInd(exec.args+i, v);
2088 }
2089 if(FAILED(hres)) {
2090 release_exec(&exec);
2091 return hres;
2092 }
2093 }
2094 }else {
2095 exec.args = NULL;
2096 }
2097
2098 if(func->var_cnt) {
2099 exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
2100 if(!exec.vars) {
2101 release_exec(&exec);
2102 return E_OUTOFMEMORY;
2103 }
2104 }else {
2105 exec.vars = NULL;
2106 }
2107
2108 exec.stack_size = 16;
2109 exec.top = 0;
2110 exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
2111 if(!exec.stack) {
2112 release_exec(&exec);
2113 return E_OUTOFMEMORY;
2114 }
2115
2116 if(vbthis) {
2117 exec.this_obj = (IDispatch*)&vbthis->IDispatchEx_iface;
2118 exec.vbthis = vbthis;
2119 }else if (ctx->host_global) {
2120 exec.this_obj = ctx->host_global;
2121 }else {
2122 exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface;
2123 }
2124 IDispatch_AddRef(exec.this_obj);
2125
2126 exec.instr = exec.code->instrs + func->code_off;
2127 exec.script = ctx;
2128 exec.func = func;
2129
2130 while(exec.instr) {
2131 op = exec.instr->op;
2132 hres = op_funcs[op](&exec);
2133 if(FAILED(hres)) {
2134 ctx->err_number = hres = map_hres(hres);
2135
2136 if(exec.resume_next) {
2137 unsigned stack_off;
2138
2139 WARN("Failed %08x in resume next mode\n", hres);
2140
2141 /*
2142 * Unwinding here is simple. We need to find the next OP_catch, which contains
2143 * information about expected stack size and jump offset on error. Generated
2144 * bytecode needs to guarantee, that simple jump and stack adjustment will
2145 * guarantee proper execution continuation.
2146 */
2147 while((++exec.instr)->op != OP_catch);
2148
2149 TRACE("unwind jmp %d stack_off %d\n", exec.instr->arg1.uint, exec.instr->arg2.uint);
2150
2151 stack_off = exec.instr->arg2.uint;
2152 instr_jmp(&exec, exec.instr->arg1.uint);
2153
2154 if(exec.top > stack_off) {
2155 stack_popn(&exec, exec.top-stack_off);
2156 }else if(exec.top < stack_off) {
2157 VARIANT v;
2158
2159 V_VT(&v) = VT_EMPTY;
2160 while(exec.top < stack_off) {
2161 hres = stack_push(&exec, &v);
2162 if(FAILED(hres))
2163 break;
2164 }
2165 }
2166
2167 continue;
2168 }else {
2169 WARN("Failed %08x\n", hres);
2170 stack_popn(&exec, exec.top);
2171 break;
2172 }
2173 }
2174
2175 exec.instr += op_move[op];
2176 }
2177
2178 assert(!exec.top);
2179 if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)
2180 assert(V_VT(&exec.ret_val) == VT_EMPTY);
2181
2182 if(SUCCEEDED(hres) && res) {
2183 *res = exec.ret_val;
2184 V_VT(&exec.ret_val) = VT_EMPTY;
2185 }
2186
2187 release_exec(&exec);
2188 return hres;
2189 }