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;
|
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
|
#define LABEL_FLAG 0x80000000
|
||||||
|
|
||||||
static unsigned alloc_label(compile_ctx_t *ctx)
|
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)
|
static HRESULT compile_foreach_statement(compile_ctx_t *ctx, foreach_statement_t *stat)
|
||||||
{
|
{
|
||||||
FIXME("for each loop not implemented\n");
|
unsigned loop_start, loop_end;
|
||||||
return E_NOTIMPL;
|
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)
|
static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *stat)
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
|
WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
|
||||||
|
|
||||||
|
static DISPID propput_dispid = DISPID_PROPERTYPUT;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
vbscode_t *code;
|
vbscode_t *code;
|
||||||
instr_t *instr;
|
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 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->cNamedArgs = is_propput ? 1 : 0;
|
||||||
dp->cArgs = arg_cnt + dp->cNamedArgs;
|
dp->cArgs = arg_cnt + dp->cNamedArgs;
|
||||||
dp->rgdispidNamedArgs = is_propput ? &propput_dispid : NULL;
|
dp->rgdispidNamedArgs = is_propput ? &propput_dispid : NULL;
|
||||||
|
@ -901,6 +901,86 @@ static HRESULT interp_step(exec_ctx_t *ctx)
|
||||||
return S_OK;
|
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)
|
static HRESULT interp_jmp(exec_ctx_t *ctx)
|
||||||
{
|
{
|
||||||
const unsigned arg = ctx->instr->arg1.uint;
|
const unsigned arg = ctx->instr->arg1.uint;
|
||||||
|
|
|
@ -194,6 +194,7 @@ typedef enum {
|
||||||
X(div, 1, 0, 0) \
|
X(div, 1, 0, 0) \
|
||||||
X(double, 1, ARG_DOUBLE, 0) \
|
X(double, 1, ARG_DOUBLE, 0) \
|
||||||
X(empty, 1, 0, 0) \
|
X(empty, 1, 0, 0) \
|
||||||
|
X(enumnext, 0, ARG_ADDR, ARG_BSTR) \
|
||||||
X(equal, 1, 0, 0) \
|
X(equal, 1, 0, 0) \
|
||||||
X(errmode, 1, ARG_INT, 0) \
|
X(errmode, 1, ARG_INT, 0) \
|
||||||
X(eqv, 1, 0, 0) \
|
X(eqv, 1, 0, 0) \
|
||||||
|
@ -220,6 +221,7 @@ typedef enum {
|
||||||
X(neg, 1, 0, 0) \
|
X(neg, 1, 0, 0) \
|
||||||
X(nequal, 1, 0, 0) \
|
X(nequal, 1, 0, 0) \
|
||||||
X(new, 1, ARG_STR, 0) \
|
X(new, 1, ARG_STR, 0) \
|
||||||
|
X(newenum, 1, 0, 0) \
|
||||||
X(not, 1, 0, 0) \
|
X(not, 1, 0, 0) \
|
||||||
X(nothing, 1, 0, 0) \
|
X(nothing, 1, 0, 0) \
|
||||||
X(null, 1, 0, 0) \
|
X(null, 1, 0, 0) \
|
||||||
|
|
Loading…
Reference in New Issue