diff options
author | wolfbeast <mcwerewolf@wolfbeast.com> | 2019-11-26 13:37:09 +0100 |
---|---|---|
committer | wolfbeast <mcwerewolf@wolfbeast.com> | 2019-11-26 13:37:09 +0100 |
commit | 185a9a750878ed1d9705fbd162dbfe9bf2e4ea0c (patch) | |
tree | 9b83879173624e3dcb5ba6d1404fb89f2c47cb66 /js/src/builtin/RegExp.js | |
parent | e8c40b0bc2aa25b9f85ddbe3949c296311cc0f3f (diff) | |
download | uxp-185a9a750878ed1d9705fbd162dbfe9bf2e4ea0c.tar.gz |
Issue #1302 - Add self-hosted implementation for string regex .matchAll
This resolves #1302.
Diffstat (limited to 'js/src/builtin/RegExp.js')
-rw-r--r-- | js/src/builtin/RegExp.js | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/js/src/builtin/RegExp.js b/js/src/builtin/RegExp.js index 1a22765943..25827743ea 100644 --- a/js/src/builtin/RegExp.js +++ b/js/src/builtin/RegExp.js @@ -1031,3 +1031,135 @@ function RegExpSpecies() { return this; } _SetCanonicalName(RegExpSpecies, "get [Symbol.species]"); + +// String.prototype.matchAll proposal. +// +// RegExp.prototype [ @@matchAll ] ( string ) +function RegExpMatchAll(string) { + // Step 1. + var rx = this; + + // Step 2. + if (!IsObject(rx)) + ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, rx === null ? "null" : typeof rx); + + // Step 3. + var str = ToString(string); + + // Step 4. + var C = SpeciesConstructor(rx, GetBuiltinConstructor("RegExp")); + + // Step 5. + var flags = ToString(rx.flags); + + // Step 2.b.iii; located here because it needs |flags|. + if (!callFunction(std_String_includes, flags, "g")) { + ThrowTypeError(JSMSG_BAD_REGEXP_FLAG, "- matchAll requires g"); + } + + // Step 6. + var matcher = new C(rx, flags); + + // Steps 7-8. + matcher.lastIndex = ToLength(rx.lastIndex); + + // Steps 9-12. + // Note, always global because non-global throws as per + // https://github.com/tc39/ecma262/pull/1716 + var flags = REGEXP_GLOBAL_FLAG | + (callFunction(std_String_includes, flags, "u") ? REGEXP_UNICODE_FLAG : 0); + + // Step 13. + return CreateRegExpStringIterator(matcher, str, flags); +} + +// String.prototype.matchAll proposal. +// +// CreateRegExpStringIterator ( R, S, global, fullUnicode ) +function CreateRegExpStringIterator(regexp, string, flags) { + // Step 1. + assert(typeof string === "string", "|string| is a string value"); + + // Steps 2-3. + assert(typeof flags === "number", "|flags| is a number value"); + + // Steps 4-9. + var iterator = NewRegExpStringIterator(); + UnsafeSetReservedSlot(iterator, REGEXP_STRING_ITERATOR_REGEXP_SLOT, regexp); + UnsafeSetReservedSlot(iterator, REGEXP_STRING_ITERATOR_STRING_SLOT, string); + UnsafeSetReservedSlot(iterator, REGEXP_STRING_ITERATOR_FLAGS_SLOT, flags | 0); + UnsafeSetReservedSlot(iterator, REGEXP_STRING_ITERATOR_DONE_SLOT, false); + + // Step 10. + return iterator; +} + +// String.prototype.matchAll proposal. +// +// %RegExpStringIteratorPrototype%.next ( ) +function RegExpStringIteratorNext() { + // Steps 1-3. + var obj; + if (!IsObject(this) || (obj = GuardToRegExpStringIterator(this)) === null) { + return callFunction(CallRegExpStringIteratorMethodIfWrapped, this, + "RegExpStringIteratorNext"); + } + + var result = { value: undefined, done: false }; + + // Step 4. + var done = UnsafeGetReservedSlot(obj, REGEXP_STRING_ITERATOR_DONE_SLOT); + if (done) { + result.done = true; + return result; + } + + // Step 5. + var regexp = UnsafeGetObjectFromReservedSlot(obj, REGEXP_STRING_ITERATOR_REGEXP_SLOT); + + // Step 6. + var string = UnsafeGetStringFromReservedSlot(obj, REGEXP_STRING_ITERATOR_STRING_SLOT); + + // Steps 7-8. + var flags = UnsafeGetInt32FromReservedSlot(obj, REGEXP_STRING_ITERATOR_FLAGS_SLOT); + var global = !!(flags & REGEXP_GLOBAL_FLAG); + var fullUnicode = !!(flags & REGEXP_UNICODE_FLAG); + + // Step 9. + var match = RegExpExec(regexp, string, false); + + // Step 10. + if (match === null) { + // Step 10.a. + UnsafeSetReservedSlot(obj, REGEXP_STRING_ITERATOR_DONE_SLOT, true); + + // Step 10.b. + result.done = true; + return result; + } + + // Step 11.a. + if (global) { + // Step 11.a.i. + var matchStr = ToString(match[0]); + + // Step 11.a.ii. + if (matchStr.length === 0) { + // Step 11.a.ii.1. + var thisIndex = ToLength(regexp.lastIndex); + + // Step 11.a.ii.2. + var nextIndex = fullUnicode ? AdvanceStringIndex(string, thisIndex) : thisIndex + 1; + + // Step 11.a.ii.3. + regexp.lastIndex = nextIndex; + } + } else { + // Step 11.b.i. + UnsafeSetReservedSlot(obj, REGEXP_STRING_ITERATOR_DONE_SLOT, true); + } + + // Steps 11.a.iii and 11.b.ii. + result.value = match; + return result; +} |