From 435b9251675f2ca2d42b8482adcd1afea964c231 Mon Sep 17 00:00:00 2001 From: Mathias Bynens Date: Wed, 8 Aug 2018 17:50:02 +0200 Subject: [PATCH 1/2] Improve consistency with existing RegExp methods and subclass handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @anba outlined two separate concerns about the remaining `IsRegExp` call in `MatchAllIterator`. Quoting from https://github.com/tc39/proposal-string-matchall/issues/34#issuecomment-380829742: 1. When `MatchAllIterator` is called from `RegExp.prototype [ @@matchAll ]`, we should/have to assume the user explicitly decided to treat `R` as a RegExp object, so having an additional `IsRegExp` call to change this decision seems questionable. It’s also not consistent with how the other `RegExp.prototype` methods work. 2. When `MatchAllIterator` is called from `String.prototype.matchAll`, I’d prefer to handle it more like the other `String.prototype` methods which create RegExp objects (that means `String.prototype.match` and `String.prototype.search`), because I want to avoid adding yet another way to handle RegExp sub-classes. There are already two different RegExp sub-classing/extension interfaces: the `RegExp.prototype` methods all call `RegExpExec`, which means sub-classes, or any other classes, only need to provide their own `exec` methods when they want to reuse the other `RegExp.prototype` methods. And in addition to that, the `@@match/replace/search/split` interfaces allow sub-classes to provide their own implementations for just these methods. The `matchAll` proposal in its current form adds another dimension to this by providing different code paths depending on whether or not an object is RegExp-like (as per the `IsRegExp` abstract operation). In my opinion we should only support RegExp sub-classing in two ways: 1) Either the RegExp sub-class has `%RegExpPrototype%` on its prototype chain, or 2) the RegExp sub-class copies the relevant methods from `%RegExpPrototype%` into its prototype object. Ref. #21, #34. --- index.html | 98 ++++++++++++++++++++++-------------------------------- spec.emu | 40 +++++++--------------- 2 files changed, 52 insertions(+), 86 deletions(-) diff --git a/index.html b/index.html index f241e72..00ee184 100644 --- a/index.html +++ b/index.html @@ -29,24 +29,6 @@ "location": "", "referencingIds": [], "key": "RegExp.prototype [ @@matchAll ] ( string )" - }, { - "type": "op", - "aoid": "MatchAllIterator", - "refId": "sec-matchalliterator", - "location": "", - "referencingIds": [], - "key": "MatchAllIterator" - }, { - "type": "clause", - "id": "sec-matchalliterator", - "aoid": "MatchAllIterator", - "title": "MatchAllIterator ( R, O )", - "titleHTML": "MatchAllIterator ( R, O )", - "number": "3", - "namespace": "", - "location": "", - "referencingIds": ["_ref_8", "_ref_10"], - "key": "MatchAllIterator ( R, O )" }, { "type": "op", "aoid": "CreateRegExpStringIterator", @@ -60,10 +42,10 @@ "aoid": "CreateRegExpStringIterator", "title": "CreateRegExpStringIterator ( R, S, global, fullUnicode )", "titleHTML": "CreateRegExpStringIterator ( R, S, global, fullUnicode )", - "number": "4", + "number": "3", "namespace": "", "location": "", - "referencingIds": ["_ref_26"], + "referencingIds": ["_ref_24"], "key": "CreateRegExpStringIterator ( R, S, global, fullUnicode )" }, { "type": "clause", @@ -71,7 +53,7 @@ "aoid": null, "title": "%RegExpStringIteratorPrototype%.next ( )", "titleHTML": "%RegExpStringIteratorPrototype%.next ( )", - "number": "5.1", + "number": "4.1", "namespace": "", "location": "", "referencingIds": [], @@ -82,7 +64,7 @@ "aoid": null, "title": "%RegExpStringIteratorPrototype%[ @@toStringTag ]", "titleHTML": "%RegExpStringIteratorPrototype%[ @@toStringTag ]", - "number": "5.2", + "number": "4.2", "namespace": "", "location": "", "referencingIds": [], @@ -93,7 +75,7 @@ "aoid": null, "title": "Properties of RegExp String Iterator Instances", "titleHTML": "Properties of RegExp String Iterator Instances", - "number": "5.3", + "number": "4.3", "namespace": "", "location": "", "referencingIds": ["_ref_2"], @@ -104,7 +86,7 @@ "aoid": null, "title": "The %RegExpStringIteratorPrototype% Object", "titleHTML": "The %RegExpStringIteratorPrototype% Object", - "number": "5", + "number": "4", "namespace": "", "location": "", "referencingIds": ["_ref_0", "_ref_1", "_ref_3"], @@ -115,7 +97,7 @@ "aoid": null, "title": "Symbol.matchAll", "titleHTML": "Symbol.matchAll", - "number": "6", + "number": "5", "namespace": "", "location": "", "referencingIds": [], @@ -135,7 +117,7 @@ "aoid": null, "title": "Well-Known Symbols", "titleHTML": "Well-Known Symbols", - "number": "7", + "number": "6", "namespace": "", "location": "", "referencingIds": [], @@ -1699,6 +1681,11 @@ display: block; } + emu-rhs>ins, + emu-rhs>del { + display: inline; + } + tr.ins>td>ins { border-bottom: none; } @@ -2176,6 +2163,12 @@ text-align: right; padding-right: 5px; } + + @media print { + #menu-toggle { + display: none; + } + } @@ -2195,23 +2188,22 @@
  1. 1 String.prototype.matchAll ( regexp )
  2. 2 RegExp.prototype [ @@matchAll ] ( string )
  3. -
  4. 3 MatchAllIterator ( R, O )
  5. -
  6. 4 CreateRegExpStringIterator ( R, S, global, fullUnicode )
  7. -
  8. 5 The %RegExpStringIteratorPrototype% Object +
  9. 3 CreateRegExpStringIterator ( R, S, global, fullUnicode )
  10. +
  11. 4 The %RegExpStringIteratorPrototype% Object
      -
    1. 5.1 %RegExpStringIteratorPrototype%.next ( )
    2. -
    3. 5.2 %RegExpStringIteratorPrototype%[ @@toStringTag ]
    4. -
    5. 5.3 Properties of RegExp String Iterator Instances
    6. +
    7. 4.1 %RegExpStringIteratorPrototype%.next ( )
    8. +
    9. 4.2 %RegExpStringIteratorPrototype%[ @@toStringTag ]
    10. +
    11. 4.3 Properties of RegExp String Iterator Instances
  12. -
  13. 6 Symbol.matchAll
  14. -
  15. 7 Well-Known Symbols
  16. +
  17. 5 Symbol.matchAll
  18. +
  19. 6 Well-Known Symbols
  20. A Copyright & Software License
-

Stage 3 Draft / April 13, 2018

+

Stage 3 Draft / August 8, 2018

String.prototype.matchAll

@@ -2221,7 +2213,7 @@

1String.prototype.matchAll ( regexp )

Performs a regular expression match of the String representing the this value against regexp and returns an iterator. Each iteration result’s value is an Array object containing the results of the match, or null if the String did not match.

When the matchAll method is called, the following steps are taken:

-
  1. Let O be ? RequireObjectCoercible(this value).
  2. If regexp is neither undefined nor null, then
    1. Let matcher be ? GetMethod(regexp, @@matchAll).
    2. If matcher is not undefined, then
      1. Return ? Call(matcher, regexp, « O »).
  3. Return ? MatchAllIterator(regexp, O). +
    1. Let O be ? RequireObjectCoercible(this value).
    2. If regexp is neither undefined nor null, then
      1. Let matcher be ? GetMethod(regexp, @@matchAll).
      2. If matcher is not undefined, then
        1. Return ? Call(matcher, regexp, « O »).
    3. Let string be ? ToString(O).
    4. Let rx be ? RegExpCreate(regexp, "g").
    5. Return ? Invoke(rx, @@matchAll, « string »).
    Note 1
    The matchAll function is intentionally generic, it does not require that its this value be a String object. Therefore, it can be transferred to other kinds of objects for use as a method.
    Note 2
    Similarly to String.prototype.split, String.prototype.matchAll is designed to typically act without mutating its inputs.
    @@ -2233,52 +2225,42 @@

    1String.prototype.matchAll ( regexp )

    2RegExp.prototype [ @@matchAll ] ( string )

    When the @@matchAll method is called with argument string, the following steps are taken:

    -
    1. Let R be the this value.
    2. If Type(R) is not Object, throw a TypeError exception.
    3. Return ? MatchAllIterator(R, string). +
      1. Let R be the this value.
      2. If Type(R) is not Object, throw a TypeError exception.
      3. Let S be ? ToString(string).
      4. Let C be ? SpeciesConstructor(R, %RegExp%).
      5. Let flags be ? ToString(? Get(R, "flags")).
      6. Let matcher be ? Construct(C, « R, flags »).
      7. Let global be ? ToBoolean(? Get(matcher, "global")).
      8. Let fullUnicode be ? ToBoolean(? Get(matcher, "unicode").
      9. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
      10. Perform ? Set(matcher, "lastIndex", lastIndex, true).
      11. Return ! CreateRegExpStringIterator(matcher, S, global, fullUnicode).

      The value of the name property of this function is "[Symbol.matchAll]".

      - - - - -

      3MatchAllIterator ( R, O )

      - -

      The abstract operation MatchAllIterator performs the following steps:

      -
      1. Let S be ? ToString(O).
      2. If ? IsRegExp(R) is true, then
        1. Let C be ? SpeciesConstructor(R, %RegExp%).
        2. Let flags be ? ToString(? Get(R, "flags")).
        3. Let matcher be ? Construct(C, « R, flags »).
        4. Let global be ? ToBoolean(? Get(matcher, "global")).
        5. Let fullUnicode be ? ToBoolean(? Get(matcher, "unicode").
        6. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
        7. Perform ? Set(matcher, "lastIndex", lastIndex, true).
      3. Else,
        1. Let flags be "g".
        2. Let matcher be ? RegExpCreate(R, flags).
        3. Let global be true.
        4. Let fullUnicode be false.
        5. Assert: ! Get(matcher, "lastIndex") is 0.
      4. Return ! CreateRegExpStringIterator(matcher, S, global, fullUnicode). -
      -
      -

      4CreateRegExpStringIterator ( R, S, global, fullUnicode )

      +

      3CreateRegExpStringIterator ( R, S, global, fullUnicode )

      The abstract operation CreateRegExpStringIterator is used to create such iterator objects. It performs the following steps:

      -
      1. Assert: Type(S) is String.
      2. Assert: Type(global) is Boolean.
      3. Assert: Type(fullUnicode) is Boolean.
      4. Let iterator be ObjectCreate(%RegExpStringIteratorPrototype%, « [[IteratingRegExp]], [[IteratedString]], [[Global]], [[Unicode]], [[Done]] »).
      5. Set iterator.[[IteratingRegExp]] to R.
      6. Set iterator.[[IteratedString]] to S.
      7. Set iterator.[[Global]] to global.
      8. Set iterator.[[Unicode]] to fullUnicode.
      9. Set iterator.[[Done]] to false.
      10. Return iterator. +
        1. Assert: Type(S) is String.
        2. Assert: Type(global) is Boolean.
        3. Assert: Type(fullUnicode) is Boolean.
        4. Let iterator be ObjectCreate(%RegExpStringIteratorPrototype%, « [[IteratingRegExp]], [[IteratedString]], [[Global]], [[Unicode]], [[Done]] »).
        5. Set iterator.[[IteratingRegExp]] to R.
        6. Set iterator.[[IteratedString]] to S.
        7. Set iterator.[[Global]] to global.
        8. Set iterator.[[Unicode]] to fullUnicode.
        9. Set iterator.[[Done]] to false.
        10. Return iterator.
        -

        5The %RegExpStringIteratorPrototype% Object

        +

        4The %RegExpStringIteratorPrototype% Object

        All RegExp String Iterator Objects inherit properties from the %RegExpStringIteratorPrototype% intrinsic object. The %RegExpStringIteratorPrototype% object is an ordinary object and its [[Prototype]] internal slot is the %IteratorPrototype% intrinsic object. In addition, %RegExpStringIteratorPrototype% has the following properties:

        -

        5.1%RegExpStringIteratorPrototype%.next ( )

        -
        1. Let O be the this value.
        2. If Type(O) is not Object, throw a TypeError exception.
        3. If O does not have all of the internal slots of a RegExp String Iterator Object Instance (see 5.3), throw a TypeError exception.
        4. If O.[[Done]] is true, then
          1. Return ! CreateIterResultObject(undefined, true).
        5. Let R be O.[[IteratingRegExp]].
        6. Let S be O.[[IteratedString]].
        7. Let global be O.[[Global]].
        8. Let fullUnicode be O.[[Unicode]].
        9. Let match be ? RegExpExec(R, S).
        10. If match is null, then
          1. Set O.[[Done]] to true.
          2. Return ! CreateIterResultObject(undefined, true).
        11. Else,
          1. If global is true,
            1. Let matchStr be ? ToString(? Get(match, "0")).
            2. If matchStr is the empty string,
              1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")).
              2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex, fullUnicode).
              3. Perform ? Set(R, "lastIndex", nextIndex, true).
            3. Return ! CreateIterResultObject(match, false).
          2. Else,
            1. Set O.[[Done]] to true.
            2. Return ! CreateIterResultObject(match, false). +

              4.1%RegExpStringIteratorPrototype%.next ( )

              +
              1. Let O be the this value.
              2. If Type(O) is not Object, throw a TypeError exception.
              3. If O does not have all of the internal slots of a RegExp String Iterator Object Instance (see 4.3), throw a TypeError exception.
              4. If O.[[Done]] is true, then
                1. Return ! CreateIterResultObject(undefined, true).
              5. Let R be O.[[IteratingRegExp]].
              6. Let S be O.[[IteratedString]].
              7. Let global be O.[[Global]].
              8. Let fullUnicode be O.[[Unicode]].
              9. Let match be ? RegExpExec(R, S).
              10. If match is null, then
                1. Set O.[[Done]] to true.
                2. Return ! CreateIterResultObject(undefined, true).
              11. Else,
                1. If global is true,
                  1. Let matchStr be ? ToString(? Get(match, "0")).
                  2. If matchStr is the empty string,
                    1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")).
                    2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex, fullUnicode).
                    3. Perform ? Set(R, "lastIndex", nextIndex, true).
                  3. Return ! CreateIterResultObject(match, false).
                2. Else,
                  1. Set O.[[Done]] to true.
                  2. Return ! CreateIterResultObject(match, false).
              -

              5.2%RegExpStringIteratorPrototype%[ @@toStringTag ]

              +

              4.2%RegExpStringIteratorPrototype%[ @@toStringTag ]

              The initial value of the @@toStringTag property is the String value "RegExp String Iterator".

              This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

              -

              5.3Properties of RegExp String Iterator Instances

              +

              4.3Properties of RegExp String Iterator Instances

              RegExp String Iterator instances are ordinary objects that inherit properties from the %RegExpStringIteratorPrototype% intrinsic object. RegExp String Iterator instances are initially created with the internal slots listed in Table 1.

              Table 1 – Internal Slots of RegExp String Iterator Instances
              @@ -2290,7 +2272,7 @@

              5.3Properties of RegExp String Iterator Instance [[IteratingRegExp]] - The regular expression used for iteration. IsRegExp([[IteratingRegExp]]) is always initially true. + The regular expression used for iteration. IsRegExp([[IteratingRegExp]]) is always initially true. [[IteratedString]] @@ -2318,14 +2300,14 @@

              5.3Properties of RegExp String Iterator Instance -

              6Symbol.matchAll

              +

              5Symbol.matchAll

              The initial value of Symbol.matchAll is the well-known symbol @@matchAll (Table 1).

              This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

              -

              7Well-Known Symbols

              +

              6Well-Known Symbols

              Editor's Note
              insert after @@match; before @@replace
              @@ -2371,4 +2353,4 @@

              Software License

- + \ No newline at end of file diff --git a/spec.emu b/spec.emu index f9b2518..7d3a331 100644 --- a/spec.emu +++ b/spec.emu @@ -20,7 +20,9 @@ contributors: Jordan Harband 1. Let _matcher_ be ? GetMethod(_regexp_, @@matchAll). 1. If _matcher_ is not *undefined*, then 1. Return ? Call(_matcher_, _regexp_, « _O_ »). - 1. Return ? MatchAllIterator(_regexp_, _O_). + 1. Let _string_ be ? ToString(_O_). + 1. Let _rx_ be ? RegExpCreate(_regexp_, `"g"`). + 1. Return ? Invoke(_rx_, @@matchAll, « _string_ »). The `matchAll` function is intentionally generic, it does not require that its *this* value be a String object. Therefore, it can be transferred to other kinds of objects for use as a method. Similarly to `String.prototype.split`, `String.prototype.matchAll` is designed to typically act without mutating its inputs. @@ -35,35 +37,17 @@ contributors: Jordan Harband 1. Let _R_ be the *this* value. 1. If Type(_R_) is not Object, throw a *TypeError* exception. - 1. Return ? MatchAllIterator(_R_, _string_). - -

The value of the *name* property of this function is *"[Symbol.matchAll]"*.

- - - - - -

MatchAllIterator ( _R_, _O_ )

- -

The abstract operation _MatchAllIterator_ performs the following steps:

- - 1. Let _S_ be ? ToString(_O_). - 1. If ? IsRegExp(_R_) is `true`, then - 1. Let _C_ be ? SpeciesConstructor(_R_, %RegExp%). - 1. Let _flags_ be ? ToString(? Get(_R_, `"flags"`)). - 1. Let _matcher_ be ? Construct(_C_, « _R_, _flags_ »). - 1. Let _global_ be ? ToBoolean(? Get(_matcher_, `"global"`)). - 1. Let _fullUnicode_ be ? ToBoolean(? Get(_matcher_, `"unicode"`). - 1. Let _lastIndex_ be ? ToLength(? Get(_R_, `"lastIndex"`)). - 1. Perform ? Set(_matcher_, `"lastIndex"`, _lastIndex_, *true*). - 1. Else, - 1. Let _flags_ be `"g"`. - 1. Let _matcher_ be ? RegExpCreate(_R_, _flags_). - 1. Let _global_ be *true*. - 1. Let _fullUnicode_ be *false*. - 1. Assert: ! Get(_matcher_, `"lastIndex"`) is *0*. + 1. Let _S_ be ? ToString(_string_). + 1. Let _C_ be ? SpeciesConstructor(_R_, %RegExp%). + 1. Let _flags_ be ? ToString(? Get(_R_, `"flags"`)). + 1. Let _matcher_ be ? Construct(_C_, « _R_, _flags_ »). + 1. Let _global_ be ? ToBoolean(? Get(_matcher_, `"global"`)). + 1. Let _fullUnicode_ be ? ToBoolean(? Get(_matcher_, `"unicode"`). + 1. Let _lastIndex_ be ? ToLength(? Get(_R_, `"lastIndex"`)). + 1. Perform ? Set(_matcher_, `"lastIndex"`, _lastIndex_, *true*). 1. Return ! CreateRegExpStringIterator(_matcher_, _S_, _global_, _fullUnicode_). +

The value of the *name* property of this function is *"[Symbol.matchAll]"*.

From 5b99875c0bf02e4793ebaf15a85f6f2a28b15019 Mon Sep 17 00:00:00 2001 From: Mathias Bynens Date: Thu, 9 Aug 2018 10:52:07 +0200 Subject: [PATCH 2/2] Detect flag values by checking `flags` This follows the convention used by `RegExp.prototype[@@split]`: https://tc39.github.io/ecma262/#sec-regexp.prototype-@@split --- spec.emu | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec.emu b/spec.emu index 7d3a331..54eed82 100644 --- a/spec.emu +++ b/spec.emu @@ -41,8 +41,10 @@ contributors: Jordan Harband 1. Let _C_ be ? SpeciesConstructor(_R_, %RegExp%). 1. Let _flags_ be ? ToString(? Get(_R_, `"flags"`)). 1. Let _matcher_ be ? Construct(_C_, « _R_, _flags_ »). - 1. Let _global_ be ? ToBoolean(? Get(_matcher_, `"global"`)). - 1. Let _fullUnicode_ be ? ToBoolean(? Get(_matcher_, `"unicode"`). + 1. If _flags_ contains `"g"`, let _global_ be *true*. + 1. Else, let _global_ be *false*. + 1. If _flags_ contains `"u"`, let _fullUnicode_ be *true*. + 1. Else, let _fullUnicode_ be *false*. 1. Let _lastIndex_ be ? ToLength(? Get(_R_, `"lastIndex"`)). 1. Perform ? Set(_matcher_, `"lastIndex"`, _lastIndex_, *true*). 1. Return ! CreateRegExpStringIterator(_matcher_, _S_, _global_, _fullUnicode_).