vbscript: Added interpreter and compiler support for for each loops.

This commit is contained in:
Jacek Caban 2012-07-03 17:05:32 +02:00 committed by Alexandre Julliard
parent 4ca8447769
commit 44266442ed
3 changed files with 130 additions and 4 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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) \