From 2140ce7b02559248005395802f8fe0fed5fcc931 Mon Sep 17 00:00:00 2001 From: Kevin Gibbons Date: Sat, 2 Apr 2022 20:32:25 -0700 Subject: [PATCH] Normative: allow duplicate named capture groups --- spec.html | 54 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/spec.html b/spec.html index f22bcb45d4..2605bc0e08 100644 --- a/spec.html +++ b/spec.html @@ -34639,7 +34639,7 @@

Static Semantics: Early Errors

It is a Syntax Error if CountLeftCapturingParensWithin(|Pattern|) ≥ 232 - 1.
  • - It is a Syntax Error if |Pattern| contains two or more |GroupSpecifier|s for which CapturingGroupName of |GroupSpecifier| is the same. + It is a Syntax Error if |Pattern| contains two distinct |GroupSpecifier|s _x_ and _y_ for which CapturingGroupName(_x_) is the same as CapturingGroupName(_y_) and such that CanBothParticipate(_x_, _y_) is *true*.
  • QuantifierPrefix :: `{` DecimalDigits `,` DecimalDigits `}` @@ -34758,6 +34758,22 @@

    + +

    + Static Semantics: CanBothParticipate ( + _x_: a Parse Node, + _y_: a Parse Node, + ): a Boolean +

    +
    +
    + + 1. Assert: _x_ and _y_ have the same enclosing |Pattern|. + 1. If the enclosing |Pattern| contains a Disjunction :: Alternative `|` Disjunction Parse Node such that either _x_ is contained within the |Alternative| and _y_ is contained within the derived |Disjunction|, or _x_ is contained within the derived |Disjunction| and _y_ is contained within the |Alternative|, return *false*. + 1. Return *true*. + +
    +

    Static Semantics: CapturingGroupNumber ( ): a positive integer

    @@ -35023,7 +35039,7 @@

    1. Let _pattern_ be the |Pattern| containing _thisGroupName_. 1. Let _result_ be a new empty List. 1. For each |GroupSpecifier| _gs_ that _pattern_ contains, do - 1. If the CapturingGroupName of _gs_ is the same value as _name_, then + 1. If the CapturingGroupName of _gs_ is the same value as _name_, and CanBothParticipate(_thisGroupName_, _gs_) is *true*, then 1. Append _gs_ to _result_. 1. Return _result_. @@ -35598,7 +35614,7 @@

    1. Let _n_ be the CapturingGroupNumber of |DecimalEscape|. 1. Assert: _n_ ≤ _NcapturingParens_. - 1. Return BackreferenceMatcher(_n_, _direction_). + 1. Return BackreferenceMatcher(« _n_ », _direction_).

    An escape sequence of the form `\\` followed by a non-zero decimal number _n_ matches the result of the _n_th set of capturing parentheses (). It is an error if the regular expression has fewer than _n_ capturing parentheses. If the regular expression has _n_ or more capturing parentheses but the _n_th one is *undefined* because it has not captured anything, then the backreference always succeeds.

    @@ -35618,10 +35634,11 @@

    AtomEscape :: `k` GroupName 1. Let _matchingGroupSpecifiers_ be GroupSpecifiersThatMatch(|GroupName|). - 1. Assert: _matchingGroupSpecifiers_ contains a single |GroupSpecifier|. - 1. Let _groupSpecifier_ be the sole element of _matchingGroupSpecifiers_. - 1. Let _parenIndex_ be CountLeftCapturingParensBefore(_groupSpecifier_). - 1. Return BackreferenceMatcher(_parenIndex_, _direction_). + 1. Let _parenIndices_ be a new empty List. + 1. For each |GroupSpecifier| _groupSpecifier_ of _matchingGroupSpecifiers_, do + 1. Let _parenIndex_ be CountLeftCapturingParensBefore(_groupSpecifier_). + 1. Append _parenIndex_ to _parenIndices_. + 1. Return BackreferenceMatcher(_parenIndices_, _direction_). @@ -35657,19 +35674,22 @@

    BackreferenceMatcher ( - _n_: a positive integer, + _ns_: a List of positive integers, _direction_: ~forward~ or ~backward~, ): a Matcher

    - 1. Assert: _n_ ≥ 1. - 1. Return a new Matcher with parameters (_x_, _c_) that captures _n_ and _direction_ and performs the following steps when called: + 1. Return a new Matcher with parameters (_x_, _c_) that captures _ns_ and _direction_ and performs the following steps when called: 1. Assert: _x_ is a State. 1. Assert: _c_ is a Continuation. 1. Let _cap_ be _x_'s _captures_ List. - 1. Let _r_ be _cap_[_n_]. + 1. Let _r_ be *undefined*. + 1. For each integer _n_ of _ns_, do + 1. If _cap_[_n_] is not *undefined*, then + 1. Assert: _r_ is *undefined*. + 1. Set _r_ to _cap_[_n_]. 1. If _r_ is *undefined*, return _c_(_x_). 1. Let _e_ be _x_'s _endIndex_. 1. Let _rs_ be _r_'s _startIndex_. @@ -36262,8 +36282,16 @@

    1. Perform ! CreateDataPropertyOrThrow(_A_, ! ToString(𝔽(_i_)), _capturedValue_). 1. If the _i_th capture of _R_ was defined with a |GroupName|, then 1. Let _s_ be the CapturingGroupName of that |GroupName|. - 1. Perform ! CreateDataPropertyOrThrow(_groups_, _s_, _capturedValue_). - 1. Append _s_ to _groupNames_. + 1. Let _isMatchedElsewhere_ be *false*. + 1. For each integer _j_ such that _j_ ≠ _i_, _j_ ≥ 1, and _j_ ≤ _n_, do + 1. If the _j_th capture of _R_ was defined with a |GroupName|, then + 1. Let _sj_ be the CapturingGroupName of that |GroupName|. + 1. If _sj_ equals _s_ and the _j_th capture of _R_ is not *undefined*, set _isMatchedElsewhere_ to *true*. + 1. If _isMatchedElsewhere_ is *false*, then + 1. Perform ! CreateDataPropertyOrThrow(_groups_, _s_, _capturedValue_). + 1. Append _s_ to _groupNames_. + 1. Else, + 1. Append *undefined* to _groupNames_. 1. Else, 1. Append *undefined* to _groupNames_. 1. If _hasIndices_ is *true*, then