Module: wine Branch: master Commit: 44266442ed6db3ea4ccf563e4297d0353d6f4f56 URL: http://source.winehq.org/git/wine.git/?a=commit;h=44266442ed6db3ea4ccf563e42...
Author: Jacek Caban jacek@codeweavers.com Date: Tue Jul 3 17:05:32 2012 +0200
vbscript: Added interpreter and compiler support for for each loops.
---
dlls/vbscript/compile.c | 48 +++++++++++++++++++++++++- dlls/vbscript/interp.c | 84 ++++++++++++++++++++++++++++++++++++++++++++- dlls/vbscript/vbscript.h | 2 + 3 files changed, 130 insertions(+), 4 deletions(-)
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index a5a232e..ab76bc7 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -290,6 +290,24 @@ static HRESULT push_instr_bstr_uint(compile_ctx_t *ctx, vbsop_t op, const WCHAR return S_OK; }
+static HRESULT push_instr_uint_bstr(compile_ctx_t *ctx, vbsop_t op, unsigned arg1, const WCHAR *arg2) +{ + unsigned instr; + BSTR bstr; + + bstr = alloc_bstr_arg(ctx, arg2); + if(!bstr) + return E_OUTOFMEMORY; + + instr = push_instr(ctx, op); + if(!instr) + return E_OUTOFMEMORY; + + instr_ptr(ctx, instr)->arg1.uint = arg1; + instr_ptr(ctx, instr)->arg2.bstr = bstr; + return S_OK; +} + #define LABEL_FLAG 0x80000000
static unsigned alloc_label(compile_ctx_t *ctx) @@ -621,8 +639,34 @@ static HRESULT compile_dowhile_statement(compile_ctx_t *ctx, while_statement_t *
static HRESULT compile_foreach_statement(compile_ctx_t *ctx, foreach_statement_t *stat) { - FIXME("for each loop not implemented\n"); - return E_NOTIMPL; + unsigned loop_start, loop_end; + HRESULT hres; + + hres = compile_expression(ctx, stat->group_expr); + if(FAILED(hres)) + return hres; + + if(!push_instr(ctx, OP_newenum)) + return E_OUTOFMEMORY; + + loop_start = ctx->instr_cnt; + if(!(loop_end = alloc_label(ctx))) + return E_OUTOFMEMORY; + + hres = push_instr_uint_bstr(ctx, OP_enumnext, loop_end, stat->identifier); + if(FAILED(hres)) + return hres; + + hres = compile_statement(ctx, stat->body); + if(FAILED(hres)) + return hres; + + hres = push_instr_addr(ctx, OP_jmp, loop_start); + if(FAILED(hres)) + return hres; + + label_set_addr(ctx, loop_end); + return S_OK; }
static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *stat) diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c index 3f3e9c8..9a8f97e 100644 --- a/dlls/vbscript/interp.c +++ b/dlls/vbscript/interp.c @@ -24,6 +24,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
+static DISPID propput_dispid = DISPID_PROPERTYPUT; + typedef struct { vbscode_t *code; instr_t *instr; @@ -439,8 +441,6 @@ static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, BOOL is_propput, DISPPARAMS *dp) { - static DISPID propput_dispid = DISPID_PROPERTYPUT; - dp->cNamedArgs = is_propput ? 1 : 0; dp->cArgs = arg_cnt + dp->cNamedArgs; dp->rgdispidNamedArgs = is_propput ? &propput_dispid : NULL; @@ -901,6 +901,86 @@ static HRESULT interp_step(exec_ctx_t *ctx) return S_OK; }
+static HRESULT interp_newenum(exec_ctx_t *ctx) +{ + VARIANT *v, r; + HRESULT hres; + + TRACE("\n"); + + v = stack_pop(ctx); + switch(V_VT(v)) { + case VT_DISPATCH: { + IEnumVARIANT *iter; + DISPPARAMS dp = {0}; + VARIANT iterv; + + hres = disp_call(ctx->script, V_DISPATCH(v), DISPID_NEWENUM, &dp, &iterv); + VariantClear(v); + if(FAILED(hres)) + return hres; + + if(V_VT(&iterv) != VT_UNKNOWN && V_VT(&iterv) != VT_DISPATCH) { + FIXME("Unsupported iterv %s\n", debugstr_variant(&iterv)); + VariantClear(&iterv); + return hres; + } + + hres = IUnknown_QueryInterface(V_UNKNOWN(&iterv), &IID_IEnumVARIANT, (void**)&iter); + IUnknown_Release(V_UNKNOWN(&iterv)); + if(FAILED(hres)) { + FIXME("Could not get IEnumVARIANT iface: %08x\n", hres); + return hres; + } + + V_VT(&r) = VT_UNKNOWN; + V_UNKNOWN(&r) = (IUnknown*)iter; + break; + } + default: + FIXME("Unsupported for %s\n", debugstr_variant(v)); + VariantClear(v); + return E_NOTIMPL; + } + + return stack_push(ctx, &r); +} + +static HRESULT interp_enumnext(exec_ctx_t *ctx) +{ + const unsigned loop_end = ctx->instr->arg1.uint; + const BSTR ident = ctx->instr->arg2.bstr; + VARIANT v; + DISPPARAMS dp = {&v, &propput_dispid, 1, 1}; + IEnumVARIANT *iter; + BOOL do_continue; + HRESULT hres; + + TRACE("\n"); + + assert(V_VT(stack_top(ctx, 0)) == VT_UNKNOWN); + iter = (IEnumVARIANT*)V_UNKNOWN(stack_top(ctx, 0)); + + V_VT(&v) = VT_EMPTY; + hres = IEnumVARIANT_Next(iter, 1, &v, NULL); + if(FAILED(hres)) + return hres; + + do_continue = hres == S_OK; + hres = assign_ident(ctx, ident, &dp); + VariantClear(&v); + if(FAILED(hres)) + return hres; + + if(do_continue) { + ctx->instr++; + }else { + stack_pop(ctx); + instr_jmp(ctx, loop_end); + } + return S_OK; +} + static HRESULT interp_jmp(exec_ctx_t *ctx) { const unsigned arg = ctx->instr->arg1.uint; diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 432380d..a4ae64c 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -194,6 +194,7 @@ typedef enum { X(div, 1, 0, 0) \ X(double, 1, ARG_DOUBLE, 0) \ X(empty, 1, 0, 0) \ + X(enumnext, 0, ARG_ADDR, ARG_BSTR) \ X(equal, 1, 0, 0) \ X(errmode, 1, ARG_INT, 0) \ X(eqv, 1, 0, 0) \ @@ -220,6 +221,7 @@ typedef enum { X(neg, 1, 0, 0) \ X(nequal, 1, 0, 0) \ X(new, 1, ARG_STR, 0) \ + X(newenum, 1, 0, 0) \ X(not, 1, 0, 0) \ X(nothing, 1, 0, 0) \ X(null, 1, 0, 0) \