vbscript: Added functions lookup implementation.
[wine] / dlls / vbscript / interp.c
1 /*
2  * Copyright 2011 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <assert.h>
20
21 #include "vbscript.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
26
27
28 typedef struct {
29     vbscode_t *code;
30     instr_t *instr;
31     script_ctx_t *script;
32     function_t *func;
33
34     unsigned stack_size;
35     unsigned top;
36     VARIANT *stack;
37 } exec_ctx_t;
38
39 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
40
41 typedef enum {
42     REF_NONE,
43     REF_DISP,
44     REF_VAR,
45     REF_FUNC
46 } ref_type_t;
47
48 typedef struct {
49     ref_type_t type;
50     union {
51         struct {
52             IDispatch *disp;
53             DISPID id;
54         } d;
55         VARIANT *v;
56         function_t *f;
57     } u;
58 } ref_t;
59
60 typedef struct {
61     VARIANT *v;
62     VARIANT store;
63     BOOL owned;
64 } variant_val_t;
65
66 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
67 {
68     while(var) {
69         if(!strcmpiW(var->name, name)) {
70             ref->type = REF_VAR;
71             ref->u.v = &var->v;
72             return TRUE;
73         }
74
75         var = var->next;
76     }
77
78     return FALSE;
79 }
80
81 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, ref_t *ref)
82 {
83     named_item_t *item;
84     function_t *func;
85     DISPID id;
86     HRESULT hres;
87
88     if(lookup_dynamic_vars(ctx->script->global_vars, name, ref))
89         return S_OK;
90
91     for(func = ctx->script->global_funcs; func; func = func->next) {
92         if(!strcmpiW(func->name, name)) {
93             ref->type = REF_FUNC;
94             ref->u.f = func;
95             return S_OK;
96         }
97     }
98
99     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
100         if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
101             hres = disp_get_id(item->disp, name, &id);
102             if(SUCCEEDED(hres)) {
103                 ref->type = REF_DISP;
104                 ref->u.d.disp = item->disp;
105                 ref->u.d.id = id;
106                 return S_OK;
107             }
108         }
109     }
110
111     if(!ctx->func->code_ctx->option_explicit)
112         FIXME("create an attempt to set\n");
113
114     ref->type = REF_NONE;
115     return S_OK;
116 }
117
118 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
119 {
120     assert(ctx->top);
121     return ctx->stack + --ctx->top;
122 }
123
124 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
125 {
126     if(ctx->stack_size == ctx->top) {
127         VARIANT *new_stack;
128
129         new_stack = heap_realloc(ctx->stack, ctx->stack_size*2);
130         if(!new_stack) {
131             VariantClear(v);
132             return E_OUTOFMEMORY;
133         }
134
135         ctx->stack = new_stack;
136         ctx->stack_size *= 2;
137     }
138
139     ctx->stack[ctx->top++] = *v;
140     return S_OK;
141 }
142
143 static void stack_popn(exec_ctx_t *ctx, unsigned n)
144 {
145     while(n--)
146         VariantClear(stack_pop(ctx));
147 }
148
149 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *v)
150 {
151     VARIANT *var;
152
153     var = stack_pop(ctx);
154
155     if(V_VT(var) == (VT_BYREF|VT_VARIANT)) {
156         v->owned = FALSE;
157         var = V_VARIANTREF(var);
158     }else {
159         v->owned = TRUE;
160     }
161
162     if(V_VT(var) == VT_DISPATCH) {
163         FIXME("got dispatch - get its default value\n");
164         return E_NOTIMPL;
165     }else {
166         v->v = var;
167     }
168
169     return S_OK;
170 }
171
172 static inline void release_val(variant_val_t *v)
173 {
174     if(v->owned)
175         VariantClear(v->v);
176 }
177
178 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
179 {
180     VARIANT *v = stack_pop(ctx);
181
182     if(V_VT(v) == VT_DISPATCH) {
183         *ret = V_DISPATCH(v);
184         return S_OK;
185     }
186
187     if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
188         FIXME("not supported type: %s\n", debugstr_variant(v));
189         VariantClear(v);
190         return E_FAIL;
191     }
192
193     v = V_BYREF(v);
194     if(V_VT(v) != VT_DISPATCH) {
195         FIXME("not disp %s\n", debugstr_variant(v));
196         return E_FAIL;
197     }
198
199     if(V_DISPATCH(v))
200         IDispatch_AddRef(V_DISPATCH(v));
201     *ret = V_DISPATCH(v);
202     return S_OK;
203 }
204
205 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
206 {
207     ctx->instr = ctx->code->instrs + addr;
208 }
209
210 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, DISPPARAMS *dp)
211 {
212     dp->cArgs = arg_cnt;
213     dp->rgdispidNamedArgs = NULL;
214     dp->cNamedArgs = 0;
215
216     if(arg_cnt) {
217         VARIANT tmp;
218         unsigned i;
219
220         assert(ctx->top >= arg_cnt);
221
222         for(i=1; i*2 <= arg_cnt; i++) {
223             tmp = ctx->stack[ctx->top-i];
224             ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
225             ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
226         }
227
228         dp->rgvarg = ctx->stack + ctx->top-arg_cnt;
229     }else {
230         dp->rgvarg = NULL;
231     }
232 }
233
234 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
235 {
236     BSTR identifier = ctx->instr->arg1.bstr;
237     const unsigned arg_cnt = ctx->instr->arg2.uint;
238     ref_t ref = {0};
239     DISPPARAMS dp;
240     HRESULT hres;
241
242     hres = lookup_identifier(ctx, identifier, &ref);
243     if(FAILED(hres))
244         return hres;
245
246     vbstack_to_dp(ctx, arg_cnt, &dp);
247
248     switch(ref.type) {
249     case REF_VAR:
250         if(!res) {
251             FIXME("REF_VAR no res\n");
252             return E_NOTIMPL;
253         }
254
255         if(arg_cnt) {
256             FIXME("arguments not implemented\n");
257             return E_NOTIMPL;
258         }
259
260         V_VT(res) = VT_BYREF|VT_VARIANT;
261         V_BYREF(res) = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
262         break;
263     case REF_DISP:
264         hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
265         if(FAILED(hres))
266             return hres;
267         break;
268     case REF_FUNC:
269         FIXME("functions not implemented\n");
270         return E_NOTIMPL;
271     case REF_NONE:
272         FIXME("%s not found\n", debugstr_w(identifier));
273         return DISP_E_UNKNOWNNAME;
274     }
275
276     stack_popn(ctx, arg_cnt);
277     return S_OK;
278 }
279
280 static HRESULT interp_icall(exec_ctx_t *ctx)
281 {
282     VARIANT v;
283     HRESULT hres;
284
285     TRACE("\n");
286
287     hres = do_icall(ctx, &v);
288     if(FAILED(hres))
289         return hres;
290
291     return stack_push(ctx, &v);
292 }
293
294 static HRESULT interp_icallv(exec_ctx_t *ctx)
295 {
296     TRACE("\n");
297     return do_icall(ctx, NULL);
298 }
299
300 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
301 {
302     ref_t ref;
303     HRESULT hres;
304
305     hres = lookup_identifier(ctx, name, &ref);
306     if(FAILED(hres))
307         return hres;
308
309     switch(ref.type) {
310     case REF_VAR: {
311         VARIANT *v = ref.u.v;
312
313         if(V_VT(v) == (VT_VARIANT|VT_BYREF))
314             v = V_VARIANTREF(v);
315
316         if(own_val) {
317             VariantClear(v);
318             *v = *val;
319             hres = S_OK;
320         }else {
321             hres = VariantCopy(v, val);
322         }
323         break;
324     }
325     case REF_DISP:
326         hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, val);
327         if(own_val)
328             VariantClear(val);
329         break;
330     case REF_FUNC:
331         FIXME("functions not implemented\n");
332         return E_NOTIMPL;
333     case REF_NONE:
334         FIXME("%s not found\n", debugstr_w(name));
335         if(own_val)
336             VariantClear(val);
337         return DISP_E_UNKNOWNNAME;
338     }
339
340     return hres;
341 }
342
343 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
344 {
345     const BSTR arg = ctx->instr->arg1.bstr;
346     variant_val_t v;
347     HRESULT hres;
348
349     TRACE("%s\n", debugstr_w(arg));
350
351     hres = stack_pop_val(ctx, &v);
352     if(FAILED(hres))
353         return hres;
354
355     return assign_ident(ctx, arg, v.v, v.owned);
356 }
357
358 static HRESULT interp_assign_member(exec_ctx_t *ctx)
359 {
360     BSTR identifier = ctx->instr->arg1.bstr;
361     variant_val_t val;
362     IDispatch *obj;
363     DISPID id;
364     HRESULT hres;
365
366     TRACE("%s\n", debugstr_w(identifier));
367
368     hres = stack_pop_disp(ctx, &obj);
369     if(FAILED(hres))
370         return hres;
371
372     if(!obj) {
373         FIXME("NULL obj\n");
374         return E_FAIL;
375     }
376
377     hres = stack_pop_val(ctx, &val);
378     if(FAILED(hres)) {
379         IDispatch_Release(obj);
380         return hres;
381     }
382
383     hres = disp_get_id(obj, identifier, &id);
384     if(SUCCEEDED(hres))
385         hres = disp_propput(ctx->script, obj, id, val.v);
386
387     release_val(&val);
388     IDispatch_Release(obj);
389     return hres;
390 }
391
392 static HRESULT interp_jmp(exec_ctx_t *ctx)
393 {
394     const unsigned arg = ctx->instr->arg1.uint;
395
396     TRACE("%u\n", arg);
397
398     instr_jmp(ctx, arg);
399     return S_OK;
400 }
401
402 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
403 {
404     const unsigned arg = ctx->instr->arg1.uint;
405     variant_val_t val;
406     HRESULT hres;
407
408     TRACE("%u\n", arg);
409
410     hres = stack_pop_val(ctx, &val);
411     if(FAILED(hres))
412         return hres;
413
414     if(V_VT(val.v) != VT_BOOL) {
415         FIXME("unsupported for %s\n", debugstr_variant(val.v));
416         release_val(&val);
417         return E_NOTIMPL;
418     }
419
420     if(V_BOOL(val.v))
421         ctx->instr++;
422     else
423         instr_jmp(ctx, ctx->instr->arg1.uint);
424     return S_OK;
425 }
426
427 static HRESULT interp_ret(exec_ctx_t *ctx)
428 {
429     TRACE("\n");
430
431     ctx->instr = NULL;
432     return S_OK;
433 }
434
435 static HRESULT interp_bool(exec_ctx_t *ctx)
436 {
437     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
438     VARIANT v;
439
440     TRACE("%s\n", arg ? "true" : "false");
441
442     V_VT(&v) = VT_BOOL;
443     V_BOOL(&v) = arg;
444     return stack_push(ctx, &v);
445 }
446
447 static HRESULT interp_string(exec_ctx_t *ctx)
448 {
449     VARIANT v;
450
451     TRACE("\n");
452
453     V_VT(&v) = VT_BSTR;
454     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
455     if(!V_BSTR(&v))
456         return E_OUTOFMEMORY;
457
458     return stack_push(ctx, &v);
459 }
460
461 static HRESULT interp_long(exec_ctx_t *ctx)
462 {
463     const LONG arg = ctx->instr->arg1.lng;
464     VARIANT v;
465
466     TRACE("%d\n", arg);
467
468     V_VT(&v) = VT_I4;
469     V_I4(&v) = arg;
470     return stack_push(ctx, &v);
471 }
472
473 static HRESULT interp_short(exec_ctx_t *ctx)
474 {
475     const LONG arg = ctx->instr->arg1.lng;
476     VARIANT v;
477
478     TRACE("%d\n", arg);
479
480     V_VT(&v) = VT_I2;
481     V_I2(&v) = arg;
482     return stack_push(ctx, &v);
483 }
484
485 static HRESULT interp_double(exec_ctx_t *ctx)
486 {
487     const DOUBLE *arg = ctx->instr->arg1.dbl;
488     VARIANT v;
489
490     TRACE("%lf\n", *arg);
491
492     V_VT(&v) = VT_R8;
493     V_R8(&v) = *arg;
494     return stack_push(ctx, &v);
495 }
496
497 static HRESULT interp_empty(exec_ctx_t *ctx)
498 {
499     VARIANT v;
500
501     TRACE("\n");
502
503     V_VT(&v) = VT_EMPTY;
504     return stack_push(ctx, &v);
505 }
506
507 static HRESULT interp_null(exec_ctx_t *ctx)
508 {
509     VARIANT v;
510
511     TRACE("\n");
512
513     V_VT(&v) = VT_NULL;
514     return stack_push(ctx, &v);
515 }
516
517 static HRESULT interp_not(exec_ctx_t *ctx)
518 {
519     variant_val_t val;
520     VARIANT v;
521     HRESULT hres;
522
523     TRACE("\n");
524
525     hres = stack_pop_val(ctx, &val);
526     if(FAILED(hres))
527         return hres;
528
529     hres = VarNot(val.v, &v);
530     release_val(&val);
531     if(FAILED(hres))
532         return hres;
533
534     return stack_push(ctx, &v);
535 }
536
537 static HRESULT cmp_oper(exec_ctx_t *ctx)
538 {
539     variant_val_t l, r;
540     HRESULT hres;
541
542     hres = stack_pop_val(ctx, &r);
543     if(FAILED(hres))
544         return hres;
545
546     hres = stack_pop_val(ctx, &l);
547     if(SUCCEEDED(hres)) {
548         if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
549             FIXME("comparing nulls is not implemented\n");
550             hres = E_NOTIMPL;
551         }else {
552             hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
553         }
554     }
555
556     release_val(&r);
557     release_val(&l);
558     return hres;
559 }
560
561 static HRESULT interp_equal(exec_ctx_t *ctx)
562 {
563     VARIANT v;
564     HRESULT hres;
565
566     TRACE("\n");
567
568     hres = cmp_oper(ctx);
569     if(FAILED(hres))
570         return hres;
571
572     V_VT(&v) = VT_BOOL;
573     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
574     return stack_push(ctx, &v);
575 }
576
577 static HRESULT interp_nequal(exec_ctx_t *ctx)
578 {
579     VARIANT v;
580     HRESULT hres;
581
582     TRACE("\n");
583
584     hres = cmp_oper(ctx);
585     if(FAILED(hres))
586         return hres;
587
588     V_VT(&v) = VT_BOOL;
589     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
590     return stack_push(ctx, &v);
591 }
592
593 static HRESULT interp_concat(exec_ctx_t *ctx)
594 {
595     variant_val_t r, l;
596     VARIANT v;
597     HRESULT hres;
598
599     TRACE("\n");
600
601     hres = stack_pop_val(ctx, &r);
602     if(FAILED(hres))
603         return hres;
604
605     hres = stack_pop_val(ctx, &l);
606     if(SUCCEEDED(hres)) {
607         hres = VarCat(l.v, r.v, &v);
608         release_val(&l);
609     }
610     release_val(&r);
611     if(FAILED(hres))
612         return hres;
613
614     return stack_push(ctx, &v);
615 }
616
617 static HRESULT interp_add(exec_ctx_t *ctx)
618 {
619     variant_val_t r, l;
620     VARIANT v;
621     HRESULT hres;
622
623     TRACE("\n");
624
625     hres = stack_pop_val(ctx, &r);
626     if(FAILED(hres))
627         return hres;
628
629     hres = stack_pop_val(ctx, &l);
630     if(SUCCEEDED(hres)) {
631         hres = VarAdd(l.v, r.v, &v);
632         release_val(&l);
633     }
634     release_val(&r);
635     if(FAILED(hres))
636         return hres;
637
638     return stack_push(ctx, &v);
639 }
640
641 static HRESULT interp_sub(exec_ctx_t *ctx)
642 {
643     variant_val_t r, l;
644     VARIANT v;
645     HRESULT hres;
646
647     TRACE("\n");
648
649     hres = stack_pop_val(ctx, &r);
650     if(FAILED(hres))
651         return hres;
652
653     hres = stack_pop_val(ctx, &l);
654     if(SUCCEEDED(hres)) {
655         hres = VarSub(l.v, r.v, &v);
656         release_val(&l);
657     }
658     release_val(&r);
659     if(FAILED(hres))
660         return hres;
661
662     return stack_push(ctx, &v);
663 }
664
665 static HRESULT interp_mod(exec_ctx_t *ctx)
666 {
667     variant_val_t r, l;
668     VARIANT v;
669     HRESULT hres;
670
671     TRACE("\n");
672
673     hres = stack_pop_val(ctx, &r);
674     if(FAILED(hres))
675         return hres;
676
677     hres = stack_pop_val(ctx, &l);
678     if(SUCCEEDED(hres)) {
679         hres = VarMod(l.v, r.v, &v);
680         release_val(&l);
681     }
682     release_val(&r);
683     if(FAILED(hres))
684         return hres;
685
686     return stack_push(ctx, &v);
687 }
688
689 static HRESULT interp_idiv(exec_ctx_t *ctx)
690 {
691     variant_val_t r, l;
692     VARIANT v;
693     HRESULT hres;
694
695     TRACE("\n");
696
697     hres = stack_pop_val(ctx, &r);
698     if(FAILED(hres))
699         return hres;
700
701     hres = stack_pop_val(ctx, &l);
702     if(SUCCEEDED(hres)) {
703         hres = VarIdiv(l.v, r.v, &v);
704         release_val(&l);
705     }
706     release_val(&r);
707     if(FAILED(hres))
708         return hres;
709
710     return stack_push(ctx, &v);
711 }
712
713 static HRESULT interp_div(exec_ctx_t *ctx)
714 {
715     variant_val_t r, l;
716     VARIANT v;
717     HRESULT hres;
718
719     TRACE("\n");
720
721     hres = stack_pop_val(ctx, &r);
722     if(FAILED(hres))
723         return hres;
724
725     hres = stack_pop_val(ctx, &l);
726     if(SUCCEEDED(hres)) {
727         hres = VarDiv(l.v, r.v, &v);
728         release_val(&l);
729     }
730     release_val(&r);
731     if(FAILED(hres))
732         return hres;
733
734     return stack_push(ctx, &v);
735 }
736
737 static HRESULT interp_mul(exec_ctx_t *ctx)
738 {
739     variant_val_t r, l;
740     VARIANT v;
741     HRESULT hres;
742
743     TRACE("\n");
744
745     hres = stack_pop_val(ctx, &r);
746     if(FAILED(hres))
747         return hres;
748
749     hres = stack_pop_val(ctx, &l);
750     if(SUCCEEDED(hres)) {
751         hres = VarMul(l.v, r.v, &v);
752         release_val(&l);
753     }
754     release_val(&r);
755     if(FAILED(hres))
756         return hres;
757
758     return stack_push(ctx, &v);
759 }
760
761 static HRESULT interp_exp(exec_ctx_t *ctx)
762 {
763     variant_val_t r, l;
764     VARIANT v;
765     HRESULT hres;
766
767     TRACE("\n");
768
769     hres = stack_pop_val(ctx, &r);
770     if(FAILED(hres))
771         return hres;
772
773     hres = stack_pop_val(ctx, &l);
774     if(SUCCEEDED(hres)) {
775         hres = VarPow(l.v, r.v, &v);
776         release_val(&l);
777     }
778     release_val(&r);
779     if(FAILED(hres))
780         return hres;
781
782     return stack_push(ctx, &v);
783 }
784
785 static HRESULT interp_neg(exec_ctx_t *ctx)
786 {
787     variant_val_t val;
788     VARIANT v;
789     HRESULT hres;
790
791     hres = stack_pop_val(ctx, &val);
792     if(FAILED(hres))
793         return hres;
794
795     hres = VarNeg(val.v, &v);
796     release_val(&val);
797     if(FAILED(hres))
798         return hres;
799
800     return stack_push(ctx, &v);
801 }
802
803 static const instr_func_t op_funcs[] = {
804 #define X(x,n,a,b) interp_ ## x,
805 OP_LIST
806 #undef X
807 };
808
809 static const unsigned op_move[] = {
810 #define X(x,n,a,b) n,
811 OP_LIST
812 #undef X
813 };
814
815 HRESULT exec_script(script_ctx_t *ctx, function_t *func)
816 {
817     exec_ctx_t exec;
818     vbsop_t op;
819     HRESULT hres = S_OK;
820
821     exec.stack_size = 16;
822     exec.top = 0;
823     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
824     if(!exec.stack)
825         return E_OUTOFMEMORY;
826
827     exec.code = func->code_ctx;
828     exec.instr = exec.code->instrs + func->code_off;
829     exec.script = ctx;
830     exec.func = func;
831
832     while(exec.instr) {
833         op = exec.instr->op;
834         hres = op_funcs[op](&exec);
835         if(FAILED(hres)) {
836             FIXME("Failed %08x\n", hres);
837             stack_popn(&exec, exec.top);
838             break;
839         }
840
841         exec.instr += op_move[op];
842     }
843
844     assert(!exec.top);
845     heap_free(exec.stack);
846
847     return hres;
848 }