From c603fb490ab2ff22948b43f2d3c0c9e7848e0d08 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Gabriel=20Iv=C4=83ncescu?= Date: Tue, 3 May 2022 18:17:09 +0300 Subject: [PATCH] jscript: Implement Array.prototype.filter. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- dlls/jscript/array.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++ dlls/mshtml/tests/es5.js | 28 ++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c index e9a8fb5e330..fae761a71cc 100644 --- a/dlls/jscript/array.c +++ b/dlls/jscript/array.c @@ -1023,6 +1023,80 @@ static HRESULT Array_toLocaleString(script_ctx_t *ctx, jsval_t vthis, WORD flags return hres; } +static HRESULT Array_filter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + IDispatch *context_obj = NULL, *callback; + jsval_t value, args[3], res; + unsigned length, i, j = 0; + jsdisp_t *jsthis, *arr; + HRESULT hres; + BOOL boolval; + + TRACE("\n"); + + hres = get_length(ctx, vthis, &jsthis, &length); + if(FAILED(hres)) + return hres; + + /* FIXME: check IsCallable */ + if(!argc || !is_object_instance(argv[0])) { + FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined())); + hres = E_INVALIDARG; + goto done; + } + callback = get_object(argv[0]); + + if(argc > 1 && !is_undefined(argv[1])) { + if(!is_object_instance(argv[1])) { + FIXME("Unsupported context this %s\n", debugstr_jsval(argv[1])); + hres = E_NOTIMPL; + goto done; + } + context_obj = get_object(argv[1]); + } + + hres = create_array(ctx, 0, &arr); + if(FAILED(hres)) + goto done; + + for(i = 0; i < length; i++) { + hres = jsdisp_get_idx(jsthis, i, &value); + if(FAILED(hres)) { + if(hres == DISP_E_UNKNOWNNAME) { + hres = S_OK; + continue; + } + break; + } + args[0] = value; + args[1] = jsval_number(i); + args[2] = jsval_obj(jsthis); + hres = disp_call_value(ctx, callback, context_obj, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res); + if(SUCCEEDED(hres)) { + hres = to_boolean(res, &boolval); + jsval_release(res); + if(SUCCEEDED(hres) && boolval) + hres = jsdisp_propput_idx(arr, j++, value); + } + jsval_release(value); + if(FAILED(hres)) + break; + } + + if(FAILED(hres)) { + jsdisp_release(arr); + goto done; + } + set_length(arr, j); + + if(r) + *r = jsval_obj(arr); +done: + jsdisp_release(jsthis); + return hres; +} + static HRESULT Array_forEach(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { @@ -1365,6 +1439,7 @@ static void Array_on_put(jsdisp_t *dispex, const WCHAR *name) static const builtin_prop_t Array_props[] = { {L"concat", Array_concat, PROPF_METHOD|1}, + {L"filter", Array_filter, PROPF_METHOD|PROPF_ES5|1}, {L"forEach", Array_forEach, PROPF_METHOD|PROPF_ES5|1}, {L"indexOf", Array_indexOf, PROPF_METHOD|PROPF_ES5|1}, {L"join", Array_join, PROPF_METHOD|1}, diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 8b1c3071917..6bef2933d1f 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -205,6 +205,34 @@ sync_test("indexOf", function() { expect([1,2,3], [2, 1.9], 1); }); +sync_test("filter", function() { + ok(Array.prototype.filter.length === 1, "filter.length = " + Array.prototype.filter.length); + + var arr = ["a","foobar",true,"b",42,0,Math,null,undefined,[1,2,3,"4"]]; + delete arr[1]; + + function test(expect, fn, expect_this) { + var mismatch = false, r = function(v, i, a) { + ok(a === arr, "unexpected array " + arr); + ok(v === arr[i], "value = " + v + ", expected " + arr[i]); + ok(this === (expect_this ? expect_this : window), "this = " + this + ", expected " + expect_this); + return fn(v); + }; + r = expect_this ? Array.prototype.filter.call(arr, r, expect_this) : Array.prototype.filter.call(arr, r); + ok(r.length === expect.length, "filtered array length = " + r.length + ", expected " + expect.length); + for(var i = 0; i < r.length; i++) + if(r[i] !== expect[i]) + mismatch = true; + ok(!mismatch, "filtered array = " + r + ", expected " + expect); + } + + test([], function(v) { return false; }); + test(["a",true,"b",42,0,Math,null,undefined,arr[9]], function(v) { if(arr[1] === "foobar") delete arr[1]; return true; }); + test(["a","b"], function(v) { if(v === "b") delete arr[0]; return typeof v === "string"; }); + test(["b"], function(v) { if(arr[arr.length - 1] !== "c") arr.push("c"); return typeof v === "string"; }); + test([true,"b",42,Math,arr[9],"c"], function(v) { return v; }, Object); +}); + sync_test("forEach", function() { ok(Array.prototype.forEach.length === 1, "forEach.length = " + Array.prototype.forEach.length); -- 2.11.4.GIT