Jacek Caban : vbscript: Added interpreter and compiler support for for each loops.
Alexandre Julliard
julliard at winehq.org
Tue Jul 3 10:58:27 CDT 2012
Module: wine
Branch: master
Commit: 44266442ed6db3ea4ccf563e4297d0353d6f4f56
URL: http://source.winehq.org/git/wine.git/?a=commit;h=44266442ed6db3ea4ccf563e4297d0353d6f4f56
Author: Jacek Caban <jacek at 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) \
More information about the wine-cvs
mailing list