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 void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, DISPPARAMS *dp)
197 dp->rgdispidNamedArgs = NULL;
204 assert(ctx->top >= arg_cnt);
206 for(i=1; i*2 <= arg_cnt; i++) {
207 tmp = ctx->stack[ctx->top-i];
208 ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
209 ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
212 dp->rgvarg = ctx->stack + ctx->top-arg_cnt;
218 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
220 BSTR identifier = ctx->instr->arg1.bstr;
221 const unsigned arg_cnt = ctx->instr->arg2.uint;
226 hres = lookup_identifier(ctx, identifier, &ref);
230 vbstack_to_dp(ctx, arg_cnt, &dp);
235 FIXME("REF_VAR no res\n");
240 FIXME("arguments not implemented\n");
244 V_VT(res) = VT_BYREF|VT_VARIANT;
245 V_BYREF(res) = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
248 hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
253 FIXME("%s not found\n", debugstr_w(identifier));
254 return DISP_E_UNKNOWNNAME;
257 stack_popn(ctx, arg_cnt);
261 static HRESULT interp_icall(exec_ctx_t *ctx)
268 hres = do_icall(ctx, &v);
272 return stack_push(ctx, &v);
275 static HRESULT interp_icallv(exec_ctx_t *ctx)
278 return do_icall(ctx, NULL);
281 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
286 hres = lookup_identifier(ctx, name, &ref);
292 VARIANT *v = ref.u.v;
294 if(V_VT(v) == (VT_VARIANT|VT_BYREF))
302 hres = VariantCopy(v, val);
307 hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, val);
312 FIXME("%s not found\n", debugstr_w(name));
315 return DISP_E_UNKNOWNNAME;
321 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
323 const BSTR arg = ctx->instr->arg1.bstr;
327 TRACE("%s\n", debugstr_w(arg));
329 hres = stack_pop_val(ctx, &v);
333 return assign_ident(ctx, arg, v.v, v.owned);
336 static HRESULT interp_assign_member(exec_ctx_t *ctx)
338 BSTR identifier = ctx->instr->arg1.bstr;
344 TRACE("%s\n", debugstr_w(identifier));
346 hres = stack_pop_disp(ctx, &obj);
355 hres = stack_pop_val(ctx, &val);
357 IDispatch_Release(obj);
361 hres = disp_get_id(obj, identifier, &id);
363 hres = disp_propput(ctx->script, obj, id, val.v);
366 IDispatch_Release(obj);
370 static HRESULT interp_jmp(exec_ctx_t *ctx)
376 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
382 static HRESULT interp_ret(exec_ctx_t *ctx)
390 static HRESULT interp_bool(exec_ctx_t *ctx)
392 const VARIANT_BOOL arg = ctx->instr->arg1.lng;
395 TRACE("%s\n", arg ? "true" : "false");
399 return stack_push(ctx, &v);
402 static HRESULT interp_string(exec_ctx_t *ctx)
409 V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
411 return E_OUTOFMEMORY;
413 return stack_push(ctx, &v);
416 static HRESULT interp_long(exec_ctx_t *ctx)
418 const LONG arg = ctx->instr->arg1.lng;
425 return stack_push(ctx, &v);
428 static HRESULT interp_short(exec_ctx_t *ctx)
430 const LONG arg = ctx->instr->arg1.lng;
437 return stack_push(ctx, &v);
440 static HRESULT interp_double(exec_ctx_t *ctx)
442 const DOUBLE *arg = ctx->instr->arg1.dbl;
445 TRACE("%lf\n", *arg);
449 return stack_push(ctx, &v);
452 static HRESULT interp_empty(exec_ctx_t *ctx)
459 return stack_push(ctx, &v);
462 static HRESULT interp_null(exec_ctx_t *ctx)
469 return stack_push(ctx, &v);
472 static HRESULT interp_not(exec_ctx_t *ctx)
480 hres = stack_pop_val(ctx, &val);
484 hres = VarNot(val.v, &v);
489 return stack_push(ctx, &v);
492 static HRESULT cmp_oper(exec_ctx_t *ctx)
497 hres = stack_pop_val(ctx, &r);
501 hres = stack_pop_val(ctx, &l);
502 if(SUCCEEDED(hres)) {
503 if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
504 FIXME("comparing nulls is not implemented\n");
507 hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
516 static HRESULT interp_equal(exec_ctx_t *ctx)
523 hres = cmp_oper(ctx);
528 V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
529 return stack_push(ctx, &v);
532 static HRESULT interp_nequal(exec_ctx_t *ctx)
539 hres = cmp_oper(ctx);
544 V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
545 return stack_push(ctx, &v);
548 static HRESULT interp_concat(exec_ctx_t *ctx)
556 hres = stack_pop_val(ctx, &r);
560 hres = stack_pop_val(ctx, &l);
561 if(SUCCEEDED(hres)) {
562 hres = VarCat(l.v, r.v, &v);
569 return stack_push(ctx, &v);
572 static HRESULT interp_add(exec_ctx_t *ctx)
580 hres = stack_pop_val(ctx, &r);
584 hres = stack_pop_val(ctx, &l);
585 if(SUCCEEDED(hres)) {
586 hres = VarAdd(l.v, r.v, &v);
593 return stack_push(ctx, &v);
596 static HRESULT interp_sub(exec_ctx_t *ctx)
604 hres = stack_pop_val(ctx, &r);
608 hres = stack_pop_val(ctx, &l);
609 if(SUCCEEDED(hres)) {
610 hres = VarSub(l.v, r.v, &v);
617 return stack_push(ctx, &v);
620 static HRESULT interp_neg(exec_ctx_t *ctx)
626 hres = stack_pop_val(ctx, &val);
630 hres = VarNeg(val.v, &v);
635 return stack_push(ctx, &v);
638 static const instr_func_t op_funcs[] = {
639 #define X(x,n,a,b) interp_ ## x,
644 static const unsigned op_move[] = {
645 #define X(x,n,a,b) n,
650 HRESULT exec_script(script_ctx_t *ctx, function_t *func)
656 exec.stack_size = 16;
658 exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
660 return E_OUTOFMEMORY;
662 exec.code = func->code_ctx;
663 exec.instr = exec.code->instrs + func->code_off;
669 hres = op_funcs[op](&exec);
671 FIXME("Failed %08x\n", hres);
672 stack_popn(&exec, exec.top);
676 exec.instr += op_move[op];
680 heap_free(exec.stack);