diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 193a5b5d71f..1c643f69c9a 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -381,6 +381,8 @@ static HRESULT fill_protrefs(DispatchEx *This) fill_protrefs(This->prototype); for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) { + if(!iter->name) + continue; hres = find_prop_name(This, iter->name, &prop); if(FAILED(hres)) return hres; diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index 0175bc78dec..520398f90e9 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -764,10 +764,102 @@ HRESULT for_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *r return S_OK; } -HRESULT forin_statement_eval(exec_ctx_t *ctx, statement_t *stat, return_type_t *rt, VARIANT *ret) +/* ECMA-262 3rd Edition 12.6.4 */ +HRESULT forin_statement_eval(exec_ctx_t *ctx, statement_t *_stat, return_type_t *rt, VARIANT *ret) { - FIXME("\n"); - return E_NOTIMPL; + forin_statement_t *stat = (forin_statement_t*)_stat; + VARIANT val, name, retv, tmp; + DISPID id = DISPID_STARTENUM; + BSTR str, identifier = NULL; + IDispatchEx *in_obj; + exprval_t exprval; + HRESULT hres; + + TRACE("\n"); + + if(stat->variable) { + hres = variable_list_eval(ctx, stat->variable, &rt->ei); + if(FAILED(hres)) + return hres; + } + + hres = expr_eval(ctx, stat->in_expr, EXPR_NEWREF, &rt->ei, &exprval); + if(FAILED(hres)) + return hres; + + hres = exprval_to_value(ctx->parser->script, &exprval, &rt->ei, &val); + exprval_release(&exprval); + if(FAILED(hres)) + return hres; + + if(V_VT(&val) != VT_DISPATCH) { + FIXME("in vt %d\n", V_VT(&val)); + VariantClear(&val); + return E_NOTIMPL; + } + + hres = IDispatch_QueryInterface(V_DISPATCH(&val), &IID_IDispatchEx, (void**)&in_obj); + IDispatch_Release(V_DISPATCH(&val)); + if(FAILED(hres)) { + FIXME("Object doesn't support IDispatchEx\n"); + return E_NOTIMPL; + } + + V_VT(&retv) = VT_EMPTY; + + if(stat->variable) + identifier = SysAllocString(stat->variable->identifier); + + while(1) { + hres = IDispatchEx_GetNextDispID(in_obj, fdexEnumDefault, id, &id); + if(FAILED(hres) || hres == S_FALSE) + break; + + hres = IDispatchEx_GetMemberName(in_obj, id, &str); + if(FAILED(hres)) + break; + + TRACE("iter %s\n", debugstr_w(str)); + + if(stat->variable) + hres = identifier_eval(ctx, identifier, 0, &exprval); + else + hres = expr_eval(ctx, stat->expr, EXPR_NEWREF, &rt->ei, &exprval); + if(SUCCEEDED(hres)) { + V_VT(&name) = VT_BSTR; + V_BSTR(&name) = str; + hres = put_value(ctx->parser->script, &exprval, &name, &rt->ei); + exprval_release(&exprval); + } + SysFreeString(str); + if(FAILED(hres)) + break; + + hres = stat_eval(ctx, stat->statement, rt, &tmp); + if(FAILED(hres)) + break; + + VariantClear(&retv); + retv = tmp; + + if(rt->type == RT_CONTINUE) + rt->type = RT_NORMAL; + else if(rt->type != RT_NORMAL) + break; + } + + SysFreeString(identifier); + IDispatchEx_Release(in_obj); + if(FAILED(hres)) { + VariantClear(&retv); + return hres; + } + + if(rt->type == RT_BREAK) + rt->type = RT_NORMAL; + + *ret = retv; + return S_OK; } /* ECMA-262 3rd Edition 12.7 */ diff --git a/dlls/jscript/tests/lang.js b/dlls/jscript/tests/lang.js index 0ea4ef54fb2..1e5fcf97413 100644 --- a/dlls/jscript/tests/lang.js +++ b/dlls/jscript/tests/lang.js @@ -617,4 +617,37 @@ ok(fi === 4, "fi !== 4"); ok((void 1) === undefined, "(void 1) !== undefined"); +var inobj = new Object(); + +for(var iter in inobj) + ok(false, "unexpected iter = " + iter); + +inobj.test = true; +tmp = 0; +for(iter in inobj) { + ok(iter == "test", "unexpected iter = " + iter); + tmp++; +} +ok(tmp === 1, "for..in tmp = " + tmp); + +function forinTestObj() {} + +forinTestObj.prototype.test3 = true; + +var arr = new Array(); +inobj = new forinTestObj(); +inobj.test1 = true; +inobj.test2 = true; + +tmp = 0; +for(iter in inobj) { + arr[iter] = true; + tmp++; +} + +ok(tmp === 3, "for..in tmp = " + tmp); +ok(arr["test1"] === true, "arr[test1] !== true"); +ok(arr["test2"] === true, "arr[test2] !== true"); +ok(arr["test3"] === true, "arr[test3] !== true"); + reportSuccess();