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);
394 if(V_VT(val.v) != VT_BOOL) {
395 FIXME("unsupported for %s\n", debugstr_variant(val.v));
403 instr_jmp(ctx, ctx->instr->arg1.uint);
407 static HRESULT interp_ret(exec_ctx_t *ctx)
415 static HRESULT interp_bool(exec_ctx_t *ctx)
417 const VARIANT_BOOL arg = ctx->instr->arg1.lng;
420 TRACE("%s\n", arg ? "true" : "false");
424 return stack_push(ctx, &v);
427 static HRESULT interp_string(exec_ctx_t *ctx)
434 V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
436 return E_OUTOFMEMORY;
438 return stack_push(ctx, &v);
441 static HRESULT interp_long(exec_ctx_t *ctx)
443 const LONG arg = ctx->instr->arg1.lng;
450 return stack_push(ctx, &v);
453 static HRESULT interp_short(exec_ctx_t *ctx)
455 const LONG arg = ctx->instr->arg1.lng;
462 return stack_push(ctx, &v);
465 static HRESULT interp_double(exec_ctx_t *ctx)
467 const DOUBLE *arg = ctx->instr->arg1.dbl;
470 TRACE("%lf\n", *arg);
474 return stack_push(ctx, &v);
477 static HRESULT interp_empty(exec_ctx_t *ctx)
484 return stack_push(ctx, &v);
487 static HRESULT interp_null(exec_ctx_t *ctx)
494 return stack_push(ctx, &v);
497 static HRESULT interp_not(exec_ctx_t *ctx)
505 hres = stack_pop_val(ctx, &val);
509 hres = VarNot(val.v, &v);
514 return stack_push(ctx, &v);
517 static HRESULT cmp_oper(exec_ctx_t *ctx)
522 hres = stack_pop_val(ctx, &r);
526 hres = stack_pop_val(ctx, &l);
527 if(SUCCEEDED(hres)) {
528 if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
529 FIXME("comparing nulls is not implemented\n");
532 hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
541 static HRESULT interp_equal(exec_ctx_t *ctx)
548 hres = cmp_oper(ctx);
553 V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
554 return stack_push(ctx, &v);
557 static HRESULT interp_nequal(exec_ctx_t *ctx)
564 hres = cmp_oper(ctx);
569 V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
570 return stack_push(ctx, &v);
573 static HRESULT interp_concat(exec_ctx_t *ctx)
581 hres = stack_pop_val(ctx, &r);
585 hres = stack_pop_val(ctx, &l);
586 if(SUCCEEDED(hres)) {
587 hres = VarCat(l.v, r.v, &v);
594 return stack_push(ctx, &v);
597 static HRESULT interp_add(exec_ctx_t *ctx)
605 hres = stack_pop_val(ctx, &r);
609 hres = stack_pop_val(ctx, &l);
610 if(SUCCEEDED(hres)) {
611 hres = VarAdd(l.v, r.v, &v);
618 return stack_push(ctx, &v);
621 static HRESULT interp_sub(exec_ctx_t *ctx)
629 hres = stack_pop_val(ctx, &r);
633 hres = stack_pop_val(ctx, &l);
634 if(SUCCEEDED(hres)) {
635 hres = VarSub(l.v, r.v, &v);
642 return stack_push(ctx, &v);
645 static HRESULT interp_neg(exec_ctx_t *ctx)
651 hres = stack_pop_val(ctx, &val);
655 hres = VarNeg(val.v, &v);
660 return stack_push(ctx, &v);
663 static const instr_func_t op_funcs[] = {
664 #define X(x,n,a,b) interp_ ## x,
669 static const unsigned op_move[] = {
670 #define X(x,n,a,b) n,
675 HRESULT exec_script(script_ctx_t *ctx, function_t *func)
681 exec.stack_size = 16;
683 exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
685 return E_OUTOFMEMORY;
687 exec.code = func->code_ctx;
688 exec.instr = exec.code->instrs + func->code_off;
694 hres = op_funcs[op](&exec);
696 FIXME("Failed %08x\n", hres);
697 stack_popn(&exec, exec.top);
701 exec.instr += op_move[op];
705 heap_free(exec.stack);