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;
|
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 */
|
/* ECMA-262 3rd Edition 12.10 */
|
||||||
static HRESULT compile_with_statement(compiler_ctx_t *ctx, with_statement_t *stat)
|
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);
|
return compile_expression_statement(ctx, (expression_statement_t*)stat);
|
||||||
case STAT_FOR:
|
case STAT_FOR:
|
||||||
return compile_for_statement(ctx, (for_statement_t*)stat);
|
return compile_for_statement(ctx, (for_statement_t*)stat);
|
||||||
|
case STAT_FORIN:
|
||||||
|
return compile_forin_statement(ctx, (forin_statement_t*)stat);
|
||||||
case STAT_IF:
|
case STAT_IF:
|
||||||
return compile_if_statement(ctx, (if_statement_t*)stat);
|
return compile_if_statement(ctx, (if_statement_t*)stat);
|
||||||
case STAT_LABEL:
|
case STAT_LABEL:
|
||||||
|
|
|
@ -936,6 +936,73 @@ HRESULT forin_statement_eval(script_ctx_t *ctx, statement_t *_stat, return_type_
|
||||||
return S_OK;
|
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 */
|
/* ECMA-262 3rd Edition 12.7 */
|
||||||
HRESULT continue_statement_eval(script_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret)
|
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(double, 1, ARG_SBL, 0) \
|
||||||
X(eq, 1, 0,0) \
|
X(eq, 1, 0,0) \
|
||||||
X(eq2, 1, 0,0) \
|
X(eq2, 1, 0,0) \
|
||||||
|
X(forin, 0, ARG_UINT, 0) \
|
||||||
X(func, 1, ARG_FUNC, 0) \
|
X(func, 1, ARG_FUNC, 0) \
|
||||||
X(gt, 1, 0,0) \
|
X(gt, 1, 0,0) \
|
||||||
X(gteq, 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,
|
compiled_statement_eval,
|
||||||
compiled_statement_eval,
|
compiled_statement_eval,
|
||||||
forin_statement_eval,
|
compiled_statement_eval,
|
||||||
compiled_statement_eval,
|
compiled_statement_eval,
|
||||||
compiled_statement_eval,
|
compiled_statement_eval,
|
||||||
return_statement_eval,
|
return_statement_eval,
|
||||||
|
|
Loading…
Reference in New Issue