vbscript: Added interpreter and compiler support for for each loops.
This commit is contained in:
parent
4ca8447769
commit
44266442ed
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) \
|
||||
|
|
Loading…
Reference in New Issue