[PATCH v2 3/6] jscript: Implement Array.prototype.filter.

Gabriel Ivăncescu gabrielopcode at gmail.com
Wed Apr 20 11:56:36 CDT 2022


Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
 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 291f032..3923bb3 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 e6fdf03..32064d3 100644
--- a/dlls/mshtml/tests/es5.js
+++ b/dlls/mshtml/tests/es5.js
@@ -155,6 +155,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.34.1




More information about the wine-devel mailing list