LibJS: Don't assume match for each capture group in RegExp.prototype.exec()

This was not implementing the following part of the spec correctly:

    27. For each integer i such that i ≥ 1 and i ≤ n, do
        a. Let captureI be ith element of r's captures List.
        b. If captureI is undefined, let capturedValue be undefined.

Expecting a capture group match to exist for each of the RegExp's
capture groups would assert in Vector's operator[] if that's not the
case, for example:

    /(foo)(bar)?/.exec("foo")

Append undefined instead.

Fixes #5256.
This commit is contained in:
Linus Groh 2021-02-07 23:07:46 +01:00 committed by Andreas Kling
parent 1d843c46eb
commit 83c29bd8d7
2 changed files with 16 additions and 2 deletions

View file

@ -190,8 +190,12 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::exec)
array->indexed_properties().put(array, 0, js_string(vm, match.view.to_string()));
for (size_t i = 0; i < result.n_capture_groups; ++i) {
auto& capture = result.capture_group_matches[0][i];
array->indexed_properties().put(array, i + 1, js_string(vm, capture.view.to_string()));
auto capture_value = js_undefined();
if (result.capture_group_matches[0].size() > i) {
auto& capture = result.capture_group_matches[0][i];
capture_value = js_string(vm, capture.view.to_string());
}
array->indexed_properties().put(array, i + 1, capture_value);
}
Value groups = js_undefined();

View file

@ -18,6 +18,16 @@ test("basic unnamed captures", () => {
expect(res[1]).toBe("ooooo");
expect(res.groups).toBe(undefined);
expect(res.index).toBe(0);
re = /(foo)(bar)?/;
res = re.exec("foo");
expect(res.length).toBe(3);
expect(res[0]).toBe("foo");
expect(res[1]).toBe("foo");
expect(res[2]).toBe(undefined);
expect(res.groups).toBe(undefined);
expect(res.index).toBe(0);
});
test("basic named captures", () => {