2 * Copyright 2011 Jacek Caban for CodeWeavers
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.
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.
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
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
39 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
66 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
69 if(!strcmpiW(var->name, name)) {
81 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, ref_t *ref)
88 if(lookup_dynamic_vars(ctx->script->global_vars, name, ref))
91 for(func = ctx->script->global_funcs; func; func = func->next) {
92 if(!strcmpiW(func->name, name)) {
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;
111 if(!ctx->func->code_ctx->option_explicit)
112 FIXME("create an attempt to set\n");
114 ref->type = REF_NONE;
118 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
121 return ctx->stack + --ctx->top;
124 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
126 if(ctx->stack_size == ctx->top) {
129 new_stack = heap_realloc(ctx->stack, ctx->stack_size*2);
132 return E_OUTOFMEMORY;
135 ctx->stack = new_stack;
136 ctx->stack_size *= 2;
139 ctx->stack[ctx->top++] = *v;
143 static void stack_popn(exec_ctx_t *ctx, unsigned n)
146 VariantClear(stack_pop(ctx));
149 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *v)
153 var = stack_pop(ctx);
155 if(V_VT(var) == (VT_BYREF|VT_VARIANT)) {
157 var = V_VARIANTREF(var);
162 if(V_VT(var) == VT_DISPATCH) {
163 FIXME("got dispatch - get its default value\n");
172 static inline void release_val(variant_val_t *v)
178 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
180 VARIANT *v = stack_pop(ctx);
182 if(V_VT(v) == VT_DISPATCH) {
183 *ret = V_DISPATCH(v);
187 if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
188 FIXME("not supported type: %s\n", debugstr_variant(v));
194 if(V_VT(v) != VT_DISPATCH) {
195 FIXME("not disp %s\n", debugstr_variant(v));
200 IDispatch_AddRef(V_DISPATCH(v));
201 *ret = V_DISPATCH(v);
205 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
207 ctx->instr = ctx->code->instrs + addr;
210 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, DISPPARAMS *dp)
213 dp->rgdispidNamedArgs = NULL;
220 assert(ctx->top >= arg_cnt);
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;
228 dp->rgvarg = ctx->stack + ctx->top-arg_cnt;
234 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
236 BSTR identifier = ctx->instr->arg1.bstr;
237 const unsigned arg_cnt = ctx->instr->arg2.uint;
242 hres = lookup_identifier(ctx, identifier, &ref);
246 vbstack_to_dp(ctx, arg_cnt, &dp);
251 FIXME("REF_VAR no res\n");
256 FIXME("arguments not implemented\n");
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;
264 hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
269 FIXME("functions not implemented\n");
272 FIXME("%s not found\n", debugstr_w(identifier));
273 return DISP_E_UNKNOWNNAME;
276 stack_popn(ctx, arg_cnt);
280 static HRESULT interp_icall(exec_ctx_t *ctx)
287 hres = do_icall(ctx, &v);
291 return stack_push(ctx, &v);
294 static HRESULT interp_icallv(exec_ctx_t *ctx)
297 return do_icall(ctx, NULL);
300 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
305 hres = lookup_identifier(ctx, name, &ref);
311 VARIANT *v = ref.u.v;
313 if(V_VT(v) == (VT_VARIANT|VT_BYREF))
321 hres = VariantCopy(v, val);
326 hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, val);
331 FIXME("functions not implemented\n");
334 FIXME("%s not found\n", debugstr_w(name));
337 return DISP_E_UNKNOWNNAME;
343 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
345 const BSTR arg = ctx->instr->arg1.bstr;
349 TRACE("%s\n", debugstr_w(arg));
351 hres = stack_pop_val(ctx, &v);
355 return assign_ident(ctx, arg, v.v, v.owned);
358 static HRESULT interp_assign_member(exec_ctx_t *ctx)
360 BSTR identifier = ctx->instr->arg1.bstr;
366 TRACE("%s\n", debugstr_w(identifier));
368 hres = stack_pop_disp(ctx, &obj);
377 hres = stack_pop_val(ctx, &val);
379 IDispatch_Release(obj);
383 hres = disp_get_id(obj, identifier, &id);
385 hres = disp_propput(ctx->script, obj, id, val.v);
388 IDispatch_Release(obj);
392 static HRESULT interp_jmp(exec_ctx_t *ctx)
394 const unsigned arg = ctx->instr->arg1.uint;
402 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
404 const unsigned arg = ctx->instr->arg1.uint;
410 hres = stack_pop_val(ctx, &val);
414 if(V_VT(val.v) != VT_BOOL) {
415 FIXME("unsupported for %s\n", debugstr_variant(val.v));
423 instr_jmp(ctx, ctx->instr->arg1.uint);
427 static HRESULT interp_ret(exec_ctx_t *ctx)
435 static HRESULT interp_bool(exec_ctx_t *ctx)
437 const VARIANT_BOOL arg = ctx->instr->arg1.lng;
440 TRACE("%s\n", arg ? "true" : "false");
444 return stack_push(ctx, &v);
447 static HRESULT interp_string(exec_ctx_t *ctx)
454 V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
456 return E_OUTOFMEMORY;
458 return stack_push(ctx, &v);
461 static HRESULT interp_long(exec_ctx_t *ctx)
463 const LONG arg = ctx->instr->arg1.lng;
470 return stack_push(ctx, &v);
473 static HRESULT interp_short(exec_ctx_t *ctx)
475 const LONG arg = ctx->instr->arg1.lng;
482 return stack_push(ctx, &v);
485 static HRESULT interp_double(exec_ctx_t *ctx)
487 const DOUBLE *arg = ctx->instr->arg1.dbl;
490 TRACE("%lf\n", *arg);
494 return stack_push(ctx, &v);
497 static HRESULT interp_empty(exec_ctx_t *ctx)
504 return stack_push(ctx, &v);
507 static HRESULT interp_null(exec_ctx_t *ctx)
514 return stack_push(ctx, &v);
517 static HRESULT interp_not(exec_ctx_t *ctx)
525 hres = stack_pop_val(ctx, &val);
529 hres = VarNot(val.v, &v);
534 return stack_push(ctx, &v);
537 static HRESULT cmp_oper(exec_ctx_t *ctx)
542 hres = stack_pop_val(ctx, &r);
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");
552 hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
561 static HRESULT interp_equal(exec_ctx_t *ctx)
568 hres = cmp_oper(ctx);
573 V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
574 return stack_push(ctx, &v);
577 static HRESULT interp_nequal(exec_ctx_t *ctx)
584 hres = cmp_oper(ctx);
589 V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
590 return stack_push(ctx, &v);
593 static HRESULT interp_concat(exec_ctx_t *ctx)
601 hres = stack_pop_val(ctx, &r);
605 hres = stack_pop_val(ctx, &l);
606 if(SUCCEEDED(hres)) {
607 hres = VarCat(l.v, r.v, &v);
614 return stack_push(ctx, &v);
617 static HRESULT interp_add(exec_ctx_t *ctx)
625 hres = stack_pop_val(ctx, &r);
629 hres = stack_pop_val(ctx, &l);
630 if(SUCCEEDED(hres)) {
631 hres = VarAdd(l.v, r.v, &v);
638 return stack_push(ctx, &v);
641 static HRESULT interp_sub(exec_ctx_t *ctx)
649 hres = stack_pop_val(ctx, &r);
653 hres = stack_pop_val(ctx, &l);
654 if(SUCCEEDED(hres)) {
655 hres = VarSub(l.v, r.v, &v);
662 return stack_push(ctx, &v);
665 static HRESULT interp_mod(exec_ctx_t *ctx)
673 hres = stack_pop_val(ctx, &r);
677 hres = stack_pop_val(ctx, &l);
678 if(SUCCEEDED(hres)) {
679 hres = VarMod(l.v, r.v, &v);
686 return stack_push(ctx, &v);
689 static HRESULT interp_idiv(exec_ctx_t *ctx)
697 hres = stack_pop_val(ctx, &r);
701 hres = stack_pop_val(ctx, &l);
702 if(SUCCEEDED(hres)) {
703 hres = VarIdiv(l.v, r.v, &v);
710 return stack_push(ctx, &v);
713 static HRESULT interp_div(exec_ctx_t *ctx)
721 hres = stack_pop_val(ctx, &r);
725 hres = stack_pop_val(ctx, &l);
726 if(SUCCEEDED(hres)) {
727 hres = VarDiv(l.v, r.v, &v);
734 return stack_push(ctx, &v);
737 static HRESULT interp_mul(exec_ctx_t *ctx)
745 hres = stack_pop_val(ctx, &r);
749 hres = stack_pop_val(ctx, &l);
750 if(SUCCEEDED(hres)) {
751 hres = VarMul(l.v, r.v, &v);
758 return stack_push(ctx, &v);
761 static HRESULT interp_exp(exec_ctx_t *ctx)
769 hres = stack_pop_val(ctx, &r);
773 hres = stack_pop_val(ctx, &l);
774 if(SUCCEEDED(hres)) {
775 hres = VarPow(l.v, r.v, &v);
782 return stack_push(ctx, &v);
785 static HRESULT interp_neg(exec_ctx_t *ctx)
791 hres = stack_pop_val(ctx, &val);
795 hres = VarNeg(val.v, &v);
800 return stack_push(ctx, &v);
803 static const instr_func_t op_funcs[] = {
804 #define X(x,n,a,b) interp_ ## x,
809 static const unsigned op_move[] = {
810 #define X(x,n,a,b) n,
815 HRESULT exec_script(script_ctx_t *ctx, function_t *func)
821 exec.stack_size = 16;
823 exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
825 return E_OUTOFMEMORY;
827 exec.code = func->code_ctx;
828 exec.instr = exec.code->instrs + func->code_off;
834 hres = op_funcs[op](&exec);
836 FIXME("Failed %08x\n", hres);
837 stack_popn(&exec, exec.top);
841 exec.instr += op_move[op];
845 heap_free(exec.stack);