jscript: Added bytecode version of for..in statement.
This commit is contained in:
parent
209132724a
commit
661241a392
|
@ -1097,6 +1097,72 @@ static HRESULT compile_for_statement(compiler_ctx_t *ctx, for_statement_t *stat)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
/* ECMA-262 3rd Edition 12.6.4 */
|
||||
static HRESULT compile_forin_statement(compiler_ctx_t *ctx, forin_statement_t *stat)
|
||||
{
|
||||
unsigned loop_addr, off_backup = ctx->code_off;
|
||||
BOOL prev_no_fallback;
|
||||
HRESULT hres;
|
||||
|
||||
if(stat->variable) {
|
||||
hres = compile_variable_list(ctx, stat->variable);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
|
||||
hres = compile_expression(ctx, stat->in_expr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
if(stat->variable) {
|
||||
hres = push_instr_bstr_uint(ctx, OP_identid, stat->variable->identifier, fdexNameEnsure);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}else if(is_memberid_expr(stat->expr->type)) {
|
||||
hres = compile_memberid_expression(ctx, stat->expr, fdexNameEnsure);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}else {
|
||||
hres = push_instr_uint(ctx, OP_throw, JS_E_ILLEGAL_ASSIGN);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
/* FIXME: compile statement anyways when we depend on compiler to check errors */
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
hres = push_instr_int(ctx, OP_int, DISPID_STARTENUM);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
/* FIXME: avoid */
|
||||
if(push_instr(ctx, OP_undefined) == -1)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
loop_addr = ctx->code_off;
|
||||
if(push_instr(ctx, OP_forin) == -1)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
prev_no_fallback = ctx->no_fallback;
|
||||
ctx->no_fallback = TRUE;
|
||||
hres = compile_statement(ctx, stat->statement);
|
||||
ctx->no_fallback = prev_no_fallback;
|
||||
if(hres == E_NOTIMPL) {
|
||||
ctx->code_off = off_backup;
|
||||
stat->stat.eval = forin_statement_eval;
|
||||
return compile_interp_fallback(ctx, &stat->stat);
|
||||
}
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = push_instr_uint(ctx, OP_jmp, loop_addr);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
instr_ptr(ctx, loop_addr)->arg1.uint = ctx->code_off;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* ECMA-262 3rd Edition 12.10 */
|
||||
static HRESULT compile_with_statement(compiler_ctx_t *ctx, with_statement_t *stat)
|
||||
{
|
||||
|
@ -1244,6 +1310,8 @@ static HRESULT compile_statement(compiler_ctx_t *ctx, statement_t *stat)
|
|||
return compile_expression_statement(ctx, (expression_statement_t*)stat);
|
||||
case STAT_FOR:
|
||||
return compile_for_statement(ctx, (for_statement_t*)stat);
|
||||
case STAT_FORIN:
|
||||
return compile_forin_statement(ctx, (forin_statement_t*)stat);
|
||||
case STAT_IF:
|
||||
return compile_if_statement(ctx, (if_statement_t*)stat);
|
||||
case STAT_LABEL:
|
||||
|
|
|
@ -936,6 +936,73 @@ HRESULT forin_statement_eval(script_ctx_t *ctx, statement_t *_stat, return_type_
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
/* ECMA-262 3rd Edition 12.6.4 */
|
||||
static HRESULT interp_forin(exec_ctx_t *ctx)
|
||||
{
|
||||
const HRESULT arg = ctx->parser->code->instrs[ctx->ip].arg1.uint;
|
||||
IDispatch *var_obj, *obj = NULL;
|
||||
IDispatchEx *dispex;
|
||||
DISPID id, var_id;
|
||||
BSTR name = NULL;
|
||||
VARIANT *val;
|
||||
HRESULT hres;
|
||||
|
||||
TRACE("\n");
|
||||
|
||||
val = stack_pop(ctx);
|
||||
|
||||
assert(V_VT(stack_top(ctx)) == VT_I4);
|
||||
id = V_I4(stack_top(ctx));
|
||||
|
||||
var_obj = stack_topn_objid(ctx, 1, &var_id);
|
||||
if(!var_obj) {
|
||||
FIXME("invalid ref\n");
|
||||
VariantClear(val);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if(V_VT(stack_topn(ctx, 3)) == VT_DISPATCH)
|
||||
obj = V_DISPATCH(stack_topn(ctx, 3));
|
||||
|
||||
if(obj) {
|
||||
hres = IDispatch_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
|
||||
if(SUCCEEDED(hres)) {
|
||||
hres = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, id, &id);
|
||||
if(hres == S_OK)
|
||||
hres = IDispatchEx_GetMemberName(dispex, id, &name);
|
||||
IDispatchEx_Release(dispex);
|
||||
if(FAILED(hres)) {
|
||||
VariantClear(val);
|
||||
return hres;
|
||||
}
|
||||
}else {
|
||||
TRACE("No IDispatchEx\n");
|
||||
}
|
||||
}
|
||||
|
||||
if(name) {
|
||||
VARIANT v;
|
||||
|
||||
VariantClear(val);
|
||||
|
||||
V_I4(stack_top(ctx)) = id;
|
||||
|
||||
V_VT(&v) = VT_BSTR;
|
||||
V_BSTR(&v) = name;
|
||||
hres = disp_propput(ctx->parser->script, var_obj, var_id, &v, ctx->ei, NULL/*FIXME*/);
|
||||
SysFreeString(name);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
ctx->ip++;
|
||||
}else {
|
||||
stack_popn(ctx, 4);
|
||||
ctx->ip = arg;
|
||||
return stack_push(ctx, val);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* ECMA-262 3rd Edition 12.7 */
|
||||
HRESULT continue_statement_eval(script_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
|
||||
{
|
||||
|
|
|
@ -61,6 +61,7 @@ typedef struct _func_stack {
|
|||
X(double, 1, ARG_SBL, 0) \
|
||||
X(eq, 1, 0,0) \
|
||||
X(eq2, 1, 0,0) \
|
||||
X(forin, 0, ARG_UINT, 0) \
|
||||
X(func, 1, ARG_FUNC, 0) \
|
||||
X(gt, 1, 0,0) \
|
||||
X(gteq, 1, 0,0) \
|
||||
|
|
|
@ -842,7 +842,7 @@ static const statement_eval_t stat_eval_table[] = {
|
|||
compiled_statement_eval,
|
||||
compiled_statement_eval,
|
||||
compiled_statement_eval,
|
||||
forin_statement_eval,
|
||||
compiled_statement_eval,
|
||||
compiled_statement_eval,
|
||||
compiled_statement_eval,
|
||||
return_statement_eval,
|
||||
|
|
Loading…
Reference in New Issue