diff --git a/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp b/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp index 49291216f6..453cddf330 100644 --- a/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp @@ -302,7 +302,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::to_string) // 22.2.5.7 RegExp.prototype [ @@match ] ( string ), https://tc39.es/ecma262/#sec-regexp.prototype-@@match JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_match) { - auto* rx = this_object_from(vm, global_object); + auto* rx = regexp_object_from(vm, global_object); if (!rx) return {}; auto s = vm.argument(0).to_string(global_object); @@ -312,16 +312,18 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_match) if (vm.exception()) return {}; bool global = global_value.to_boolean(); - // FIXME: Implement and use RegExpExec, this does something different - https://tc39.es/ecma262/#sec-regexpexec - auto* exec = Value(rx).get_method(global_object, vm.names.exec); - if (!exec) - return js_undefined(); - // FIXME end - if (!global) - return vm.call(*exec, rx, js_string(vm, s)); + if (!global) { + auto result = regexp_exec(global_object, *rx, s); + if (vm.exception()) + return {}; + return result; + } // FIXME: This should exec the RegExp repeatedly while updating "lastIndex" - return vm.call(*exec, rx, js_string(vm, s)); + auto result = regexp_exec(global_object, *rx, s); + if (vm.exception()) + return {}; + return result; } // 22.2.5.10 RegExp.prototype [ @@replace ] ( string, replaceValue ), https://tc39.es/ecma262/#sec-regexp.prototype-@@replace diff --git a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.match.js b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.match.js index 7d5e91dfb9..0397bda964 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.match.js +++ b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.match.js @@ -4,3 +4,38 @@ test("basic functionality", () => { expect("hello friends".match(/hello/)).not.toBeNull(); expect("hello friends".match(/enemies/)).toBeNull(); }); + +test("override exec with function", () => { + let calls = 0; + + let re = /test/; + let oldExec = re.exec.bind(re); + re.exec = function (...args) { + ++calls; + return oldExec(...args); + }; + + expect("test".match(re)).not.toBeNull(); + expect(calls).toBe(1); +}); + +test("override exec with bad function", () => { + let calls = 0; + + let re = /test/; + re.exec = function (...args) { + ++calls; + return 4; + }; + + expect(() => { + "test".match(re); + }).toThrow(TypeError); + expect(calls).toBe(1); +}); + +test("override exec with non-function", () => { + let re = /test/; + re.exec = 3; + expect("test".match(re)).not.toBeNull(); +});