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*);
64 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
67 if(!strcmpiW(var->name, name)) {
79 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, ref_t *ref)
85 if(lookup_dynamic_vars(ctx->script->global_vars, name, ref))
88 LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
89 if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
90 hres = disp_get_id(item->disp, name, &id);
93 ref->u.d.disp = item->disp;
100 if(!ctx->func->code_ctx->option_explicit)
101 FIXME("create an attempt to set\n");
103 ref->type = REF_NONE;
107 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
110 return ctx->stack + --ctx->top;
113 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
115 if(ctx->stack_size == ctx->top) {
118 new_stack = heap_realloc(ctx->stack, ctx->stack_size*2);
121 return E_OUTOFMEMORY;
124 ctx->stack = new_stack;
125 ctx->stack_size *= 2;
128 ctx->stack[ctx->top++] = *v;
132 static void stack_popn(exec_ctx_t *ctx, unsigned n)
135 VariantClear(stack_pop(ctx));
138 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *v)
142 var = stack_pop(ctx);
144 if(V_VT(var) == (VT_BYREF|VT_VARIANT)) {
146 var = V_VARIANTREF(var);
151 if(V_VT(var) == VT_DISPATCH) {
152 FIXME("got dispatch - get its default value\n");
161 static inline void release_val(variant_val_t *v)
167 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
169 VARIANT *v = stack_pop(ctx);
171 if(V_VT(v) == VT_DISPATCH) {
172 *ret = V_DISPATCH(v);
176 if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
177 FIXME("not supported type: %s\n", debugstr_variant(v));
183 if(V_VT(v) != VT_DISPATCH) {
184 FIXME("not disp %s\n", debugstr_variant(v));
189 IDispatch_AddRef(V_DISPATCH(v));
190 *ret = V_DISPATCH(v);
194 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
196 ctx->instr = ctx->code->instrs + addr;
199 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, DISPPARAMS *dp)
202 dp->rgdispidNamedArgs = NULL;
209 assert(ctx->top >= arg_cnt);
211 for(i=1; i*2 <= arg_cnt; i++) {
212 tmp = ctx->stack[ctx->top-i];
213 ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
214 ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
217 dp->rgvarg = ctx->stack + ctx->top-arg_cnt;
223 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
225 BSTR identifier = ctx->instr->arg1.bstr;
226 const unsigned arg_cnt = ctx->instr->arg2.uint;
231 hres = lookup_identifier(ctx, identifier, &ref);
235 vbstack_to_dp(ctx, arg_cnt, &dp);
240 FIXME("REF_VAR no res\n");
245 FIXME("arguments not implemented\n");
249 V_VT(res) = VT_BYREF|VT_VARIANT;
250 V_BYREF(res) = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
253 hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
258 FIXME("%s not found\n", debugstr_w(identifier));
259 return DISP_E_UNKNOWNNAME;
262 stack_popn(ctx, arg_cnt);
266 static HRESULT interp_icall(exec_ctx_t *ctx)
273 hres = do_icall(ctx, &v);
277 return stack_push(ctx, &v);
280 static HRESULT interp_icallv(exec_ctx_t *ctx)
283 return do_icall(ctx, NULL);
286 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
291 hres = lookup_identifier(ctx, name, &ref);
297 VARIANT *v = ref.u.v;
299 if(V_VT(v) == (VT_VARIANT|VT_BYREF))
307 hres = VariantCopy(v, val);
312 hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, val);
317 FIXME("%s not found\n", debugstr_w(name));
320 return DISP_E_UNKNOWNNAME;
326 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
328 const BSTR arg = ctx->instr->arg1.bstr;
332 TRACE("%s\n", debugstr_w(arg));
334 hres = stack_pop_val(ctx, &v);
338 return assign_ident(ctx, arg, v.v, v.owned);
341 static HRESULT interp_assign_member(exec_ctx_t *ctx)
343 BSTR identifier = ctx->instr->arg1.bstr;
349 TRACE("%s\n", debugstr_w(identifier));
351 hres = stack_pop_disp(ctx, &obj);
360 hres = stack_pop_val(ctx, &val);
362 IDispatch_Release(obj);
366 hres = disp_get_id(obj, identifier, &id);
368 hres = disp_propput(ctx->script, obj, id, val.v);
371 IDispatch_Release(obj);
375 static HRESULT interp_jmp(exec_ctx_t *ctx)
377 const unsigned arg = ctx->instr->arg1.uint;
385 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
387 const unsigned arg = ctx->instr->arg1.uint;
393 hres = stack_pop_val(ctx, &val);
397 if(V_VT(val.v) != VT_BOOL) {
398 FIXME("unsupported for %s\n", debugstr_variant(val.v));
406 instr_jmp(ctx, ctx->instr->arg1.uint);
410 static HRESULT interp_ret(exec_ctx_t *ctx)
418 static HRESULT interp_bool(exec_ctx_t *ctx)
420 const VARIANT_BOOL arg = ctx->instr->arg1.lng;
423 TRACE("%s\n", arg ? "true" : "false");
427 return stack_push(ctx, &v);
430 static HRESULT interp_string(exec_ctx_t *ctx)
437 V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
439 return E_OUTOFMEMORY;
441 return stack_push(ctx, &v);
444 static HRESULT interp_long(exec_ctx_t *ctx)
446 const LONG arg = ctx->instr->arg1.lng;
453 return stack_push(ctx, &v);
456 static HRESULT interp_short(exec_ctx_t *ctx)
458 const LONG arg = ctx->instr->arg1.lng;
465 return stack_push(ctx, &v);
468 static HRESULT interp_double(exec_ctx_t *ctx)
470 const DOUBLE *arg = ctx->instr->arg1.dbl;
473 TRACE("%lf\n", *arg);
477 return stack_push(ctx, &v);
480 static HRESULT interp_empty(exec_ctx_t *ctx)
487 return stack_push(ctx, &v);
490 static HRESULT interp_null(exec_ctx_t *ctx)
497 return stack_push(ctx, &v);
500 static HRESULT interp_not(exec_ctx_t *ctx)
508 hres = stack_pop_val(ctx, &val);
512 hres = VarNot(val.v, &v);
517 return stack_push(ctx, &v);
520 static HRESULT cmp_oper(exec_ctx_t *ctx)
525 hres = stack_pop_val(ctx, &r);
529 hres = stack_pop_val(ctx, &l);
530 if(SUCCEEDED(hres)) {
531 if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
532 FIXME("comparing nulls is not implemented\n");
535 hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
544 static HRESULT interp_equal(exec_ctx_t *ctx)
551 hres = cmp_oper(ctx);
556 V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
557 return stack_push(ctx, &v);
560 static HRESULT interp_nequal(exec_ctx_t *ctx)
567 hres = cmp_oper(ctx);
572 V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
573 return stack_push(ctx, &v);
576 static HRESULT interp_concat(exec_ctx_t *ctx)
584 hres = stack_pop_val(ctx, &r);
588 hres = stack_pop_val(ctx, &l);
589 if(SUCCEEDED(hres)) {
590 hres = VarCat(l.v, r.v, &v);
597 return stack_push(ctx, &v);
600 static HRESULT interp_add(exec_ctx_t *ctx)
608 hres = stack_pop_val(ctx, &r);
612 hres = stack_pop_val(ctx, &l);
613 if(SUCCEEDED(hres)) {
614 hres = VarAdd(l.v, r.v, &v);
621 return stack_push(ctx, &v);
624 static HRESULT interp_sub(exec_ctx_t *ctx)
632 hres = stack_pop_val(ctx, &r);
636 hres = stack_pop_val(ctx, &l);
637 if(SUCCEEDED(hres)) {
638 hres = VarSub(l.v, r.v, &v);
645 return stack_push(ctx, &v);
648 static HRESULT interp_mod(exec_ctx_t *ctx)
656 hres = stack_pop_val(ctx, &r);
660 hres = stack_pop_val(ctx, &l);
661 if(SUCCEEDED(hres)) {
662 hres = VarMod(l.v, r.v, &v);
669 return stack_push(ctx, &v);
672 static HRESULT interp_idiv(exec_ctx_t *ctx)
680 hres = stack_pop_val(ctx, &r);
684 hres = stack_pop_val(ctx, &l);
685 if(SUCCEEDED(hres)) {
686 hres = VarIdiv(l.v, r.v, &v);
693 return stack_push(ctx, &v);
696 static HRESULT interp_div(exec_ctx_t *ctx)
704 hres = stack_pop_val(ctx, &r);
708 hres = stack_pop_val(ctx, &l);
709 if(SUCCEEDED(hres)) {
710 hres = VarDiv(l.v, r.v, &v);
717 return stack_push(ctx, &v);
720 static HRESULT interp_mul(exec_ctx_t *ctx)
728 hres = stack_pop_val(ctx, &r);
732 hres = stack_pop_val(ctx, &l);
733 if(SUCCEEDED(hres)) {
734 hres = VarMul(l.v, r.v, &v);
741 return stack_push(ctx, &v);
744 static HRESULT interp_exp(exec_ctx_t *ctx)
752 hres = stack_pop_val(ctx, &r);
756 hres = stack_pop_val(ctx, &l);
757 if(SUCCEEDED(hres)) {
758 hres = VarPow(l.v, r.v, &v);
765 return stack_push(ctx, &v);
768 static HRESULT interp_neg(exec_ctx_t *ctx)
774 hres = stack_pop_val(ctx, &val);
778 hres = VarNeg(val.v, &v);
783 return stack_push(ctx, &v);
786 static const instr_func_t op_funcs[] = {
787 #define X(x,n,a,b) interp_ ## x,
792 static const unsigned op_move[] = {
793 #define X(x,n,a,b) n,
798 HRESULT exec_script(script_ctx_t *ctx, function_t *func)
804 exec.stack_size = 16;
806 exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
808 return E_OUTOFMEMORY;
810 exec.code = func->code_ctx;
811 exec.instr = exec.code->instrs + func->code_off;
817 hres = op_funcs[op](&exec);
819 FIXME("Failed %08x\n", hres);
820 stack_popn(&exec, exec.top);
824 exec.instr += op_move[op];
828 heap_free(exec.stack);