Skip to content

Commit

Permalink
Normative: allow duplicate named capture groups
Browse files Browse the repository at this point in the history
  • Loading branch information
bakkot committed Mar 28, 2024
1 parent 5d8f62d commit 8dd5ab0
Showing 1 changed file with 42 additions and 13 deletions.
55 changes: 42 additions & 13 deletions spec.html
Original file line number Diff line number Diff line change
Expand Up @@ -35715,7 +35715,7 @@ <h1>Static Semantics: Early Errors</h1>
It is a Syntax Error if CountLeftCapturingParensWithin(|Pattern|) ≥ 2<sup>32</sup> - 1.
</li>
<li>
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*.
</li>
</ul>
<emu-grammar>QuantifierPrefix :: `{` DecimalDigits `,` DecimalDigits `}`</emu-grammar>
Expand Down Expand Up @@ -35861,6 +35861,22 @@ <h1>
</emu-alg>
</emu-clause>

<emu-clause id="sec-patterns-static-semantics-can-both-participate" type="abstract operation">
<h1>
Static Semantics: CanBothParticipate (
_x_: a Parse Node,
_y_: a Parse Node,
): a Boolean
</h1>
<dl class="header">
</dl>
<emu-alg>
1. Assert: _x_ and _y_ have the same enclosing |Pattern|.
1. If the enclosing |Pattern| contains a <emu-grammar>Disjunction :: Alternative `|` Disjunction</emu-grammar> 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*.
</emu-alg>
</emu-clause>

<emu-clause id="sec-patterns-static-semantics-capturing-group-number" type="sdo">
<h1>Static Semantics: CapturingGroupNumber ( ): a positive integer</h1>
<dl class="header">
Expand Down Expand Up @@ -36914,7 +36930,7 @@ <h1>
<emu-alg>
1. Let _n_ be the CapturingGroupNumber of |DecimalEscape|.
1. Assert: _n_ ≤ _rer_.[[CapturingGroupsCount]].
1. Return BackreferenceMatcher(_rer_, _n_, _direction_).
1. Return BackreferenceMatcher(_rer_, « _n_ », _direction_).
</emu-alg>
<emu-note>
<p>An escape sequence of the form `\\` followed by a non-zero decimal number _n_ matches the result of the _n_<sup>th</sup> set of capturing parentheses (<emu-xref href="#sec-pattern-notation"></emu-xref>). 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_<sup>th</sup> one is *undefined* because it has not captured anything, then the backreference always succeeds.</p>
Expand Down Expand Up @@ -36950,10 +36966,11 @@ <h1>
<emu-grammar>AtomEscape :: `k` GroupName</emu-grammar>
<emu-alg>
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(_rer_, _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(_rer_, _parenIndices_, _direction_).
</emu-alg>

<emu-clause id="sec-runtime-semantics-charactersetmatcher-abstract-operation" type="abstract operation">
Expand Down Expand Up @@ -36996,20 +37013,23 @@ <h1>
<h1>
BackreferenceMatcher (
_rer_: a RegExp Record,
_n_: a positive integer,
_ns_: a List of positive integers,
_direction_: ~forward~ or ~backward~,
): a Matcher
</h1>
<dl class="header">
</dl>
<emu-alg>
1. Assert: _n_ ≥ 1.
1. Return a new Matcher with parameters (_x_, _c_) that captures _rer_, _n_, and _direction_ and performs the following steps when called:
1. Return a new Matcher with parameters (_x_, _c_) that captures _rer_, _ns_, and _direction_ and performs the following steps when called:
1. Assert: _x_ is a MatchState.
1. Assert: _c_ is a MatcherContinuation.
1. Let _Input_ be _x_.[[Input]].
1. Let _cap_ be _x_.[[Captures]].
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_.[[EndIndex]].
1. Let _rs_ be _r_.[[StartIndex]].
Expand Down Expand Up @@ -38248,6 +38268,7 @@ <h1>
1. Let _groups_ be *undefined*.
1. Let _hasGroups_ be *false*.
1. Perform ! CreateDataPropertyOrThrow(_A_, *"groups"*, _groups_).
1. Let _matchedGroupNames_ be a new empty List.
1. For each integer _i_ such that 1 ≤ _i_ ≤ _n_, in ascending order, do
1. Let _captureI_ be _i_<sup>th</sup> element of _r_.[[Captures]].
1. If _captureI_ is *undefined*, then
Expand All @@ -38265,8 +38286,14 @@ <h1>
1. Perform ! CreateDataPropertyOrThrow(_A_, ! ToString(𝔽(_i_)), _capturedValue_).
1. If the _i_<sup>th</sup> 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. If _matchedGroupNames_ contains _s_, then
1. Assert: _capturedValue_ is *undefined*.
1. Append *undefined* to _groupNames_.
1. Else,
1. If _capturedValue_ is not *undefined*, append _s_ to _matchedGroupNames_.
1. NOTE: If there are multiple groups named _s_, _groups_ may already have an _s_ property at this point. However, because _groups_ is an ordinary object whose properties are all writable data properties, the call to CreateDataPropertyOrThrow is nevertheless guaranteed to succeed.
1. Perform ! CreateDataPropertyOrThrow(_groups_, _s_, _capturedValue_).
1. Append _s_ to _groupNames_.
1. Else,
1. Append *undefined* to _groupNames_.
1. If _hasIndices_ is *true*, then
Expand Down Expand Up @@ -38407,7 +38434,9 @@ <h1>
1. Perform ! CreateDataPropertyOrThrow(_A_, ! ToString(𝔽(_i_)), _matchIndexPair_).
1. If _i_ > 0 and _groupNames_[_i_ - 1] is not *undefined*, then
1. Assert: _groups_ is not *undefined*.
1. Perform ! CreateDataPropertyOrThrow(_groups_, _groupNames_[_i_ - 1], _matchIndexPair_).
1. Let _s_ be _groupNames_[_i_ - 1].
1. NOTE: If there are multiple groups named _s_, _groups_ may already have an _s_ property at this point. However, because _groups_ is an ordinary object whose properties are all writable data properties, the call to CreateDataPropertyOrThrow is nevertheless guaranteed to succeed.
1. Perform ! CreateDataPropertyOrThrow(_groups_, _s_, _matchIndexPair_).
1. Return _A_.
</emu-alg>
</emu-clause>
Expand Down

0 comments on commit 8dd5ab0

Please sign in to comment.