From 2a457fb701f3cdc22445f16b33164ca51450fb09 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Sat, 29 Aug 2009 00:01:25 +0200 Subject: [PATCH] jscript: Added 'instanceof' keyword implementation. --- dlls/jscript/engine.c | 70 ++++++++++++++++++++++++++++++++++++-- dlls/jscript/tests/api.js | 23 +++++++------ dlls/jscript/tests/lang.js | 15 ++++++++ dlls/jscript/tests/run.c | 2 ++ 4 files changed, 97 insertions(+), 13 deletions(-) diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index 8035e78ca2b..43b422c68e0 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -1954,10 +1954,74 @@ HRESULT binary_and_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD f } /* ECMA-262 3rd Edition 11.8.6 */ -HRESULT instanceof_expression_eval(exec_ctx_t *ctx, expression_t *expr, DWORD flags, jsexcept_t *ei, exprval_t *ret) +static HRESULT instanceof_eval(exec_ctx_t *ctx, VARIANT *inst, VARIANT *objv, jsexcept_t *ei, VARIANT *retv) { - FIXME("\n"); - return E_NOTIMPL; + DispatchEx *obj, *iter, *tmp = NULL; + VARIANT_BOOL ret = VARIANT_FALSE; + BOOL b; + VARIANT var; + HRESULT hres; + + static const WCHAR prototypeW[] = {'p','r','o','t','o','t', 'y', 'p','e',0}; + + if(V_VT(objv) != VT_DISPATCH) { + FIXME("throw TypeError\n"); + return E_FAIL; + } + + obj = iface_to_jsdisp((IUnknown*)V_DISPATCH(objv)); + if(!obj) { + FIXME("throw TypeError\n"); + return E_FAIL; + } + + if(is_class(obj, JSCLASS_FUNCTION)) { + hres = jsdisp_propget_name(obj, prototypeW, ctx->parser->script->lcid, &var, ei, NULL/*FIXME*/); + }else { + FIXME("throw TypeError\n"); + hres = E_FAIL; + } + jsdisp_release(obj); + if(FAILED(hres)) + return hres; + + if(V_VT(&var) == VT_DISPATCH) { + if(V_VT(inst) == VT_DISPATCH) + tmp = iface_to_jsdisp((IUnknown*)V_DISPATCH(inst)); + for(iter = tmp; iter; iter = iter->prototype) { + hres = disp_cmp(V_DISPATCH(&var), (IDispatch*)_IDispatchEx_(iter), &b); + if(FAILED(hres)) + break; + if(b) { + ret = VARIANT_TRUE; + break; + } + } + + if(tmp) + jsdisp_release(tmp); + }else { + FIXME("prototype is not an object\n"); + hres = E_FAIL; + } + + VariantClear(&var); + if(FAILED(hres)) + return hres; + + V_VT(retv) = VT_BOOL; + V_BOOL(retv) = ret; + return S_OK; +} + +/* ECMA-262 3rd Edition 11.8.6 */ +HRESULT instanceof_expression_eval(exec_ctx_t *ctx, expression_t *_expr, DWORD flags, jsexcept_t *ei, exprval_t *ret) +{ + binary_expression_t *expr = (binary_expression_t*)_expr; + + TRACE("\n"); + + return binary_expr_eval(ctx, expr, instanceof_eval, ei, ret); } /* ECMA-262 3rd Edition 11.8.7 */ diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index efc55a449d7..a77f31a9091 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -1376,7 +1376,10 @@ exception_test(function() {eval("while(")}, "SyntaxError", -2146827286); exception_test(function() {eval("if(")}, "SyntaxError", -2146827286); exception_test(function() {eval("'unterminated")}, "SyntaxError", -2146827273); -function testObjectInherit(obj, ts, tls, vo) { +function testObjectInherit(obj, constr, ts, tls, vo) { + ok(obj instanceof Object, "obj is not instance of Object"); + ok(obj instanceof constr, "obj is not instance of its constructor"); + ok(obj.hasOwnProperty === Object.prototype.hasOwnProperty, "obj.hasOwnProperty !== Object.prototype.hasOwnProprty"); ok(obj.isPrototypeOf === Object.prototype.isPrototypeOf, @@ -1409,15 +1412,15 @@ function testObjectInherit(obj, ts, tls, vo) { } Object.prototype._test = "test"; -testObjectInherit(new String("test"), false, true, false); -testObjectInherit(/test/g, false, true, true); -testObjectInherit(new Number(1), false, false, false); -testObjectInherit(new Date(), false, false, false); -testObjectInherit(new Boolean(true), false, true, false); -testObjectInherit(new Array(), false, false, true); -testObjectInherit(new Error(), false, true, true); -testObjectInherit(testObjectInherit, false, true, true); -testObjectInherit(Math, true, true, true); +testObjectInherit(new String("test"), String, false, true, false); +testObjectInherit(/test/g, RegExp, false, true, true); +testObjectInherit(new Number(1), Number, false, false, false); +testObjectInherit(new Date(), Date, false, false, false); +testObjectInherit(new Boolean(true), Boolean, false, true, false); +testObjectInherit(new Array(), Array, false, false, true); +testObjectInherit(new Error(), Error, false, true, true); +testObjectInherit(testObjectInherit, Function, false, true, true); +testObjectInherit(Math, Object, true, true, true); function testFunctions(obj, arr) { var l; diff --git a/dlls/jscript/tests/lang.js b/dlls/jscript/tests/lang.js index b0e90fc0e05..e3abe274106 100644 --- a/dlls/jscript/tests/lang.js +++ b/dlls/jscript/tests/lang.js @@ -796,6 +796,21 @@ if (true) else ok(true, "else should be associated with nearest if statement"); +function instanceOfTest() {} +tmp = new instanceOfTest(); + +ok((tmp instanceof instanceOfTest) === true, "tmp is not instance of instanceOfTest"); +ok((tmp instanceof Object) === true, "tmp is not instance of Object"); +ok((tmp instanceof String) === false, "tmp is instance of String"); + +instanceOfTest.prototype = new Object(); +ok((tmp instanceof instanceOfTest) === false, "tmp is instance of instanceOfTest"); +ok((tmp instanceof Object) === true, "tmp is not instance of Object"); + +ok((1 instanceof Object) === false, "1 is instance of Object"); +ok((false instanceof Boolean) === false, "false is instance of Boolean"); +ok(("" instanceof Object) === false, "'' is instance of Object"); + ok(isNaN(NaN) === true, "isNaN(NaN) !== true"); ok(isNaN(0.5) === false, "isNaN(0.5) !== false"); ok(isNaN(Infinity) === false, "isNaN(Infinity) !== false"); diff --git a/dlls/jscript/tests/run.c b/dlls/jscript/tests/run.c index 21eccc45972..0afb1806d38 100644 --- a/dlls/jscript/tests/run.c +++ b/dlls/jscript/tests/run.c @@ -842,6 +842,8 @@ static void run_tests(void) parse_script_a("function f() { var testPropGet; }"); + parse_script_a("ok((testObj instanceof Object) === false, 'testObj is instance of Object');"); + run_from_res("lang.js"); run_from_res("api.js"); run_from_res("regexp.js");