Skip to content

Commit

Permalink
Support recursion with backrefs if the recursed subpattern contains n…
Browse files Browse the repository at this point in the history
…o captures
  • Loading branch information
slevithan committed Nov 27, 2024
1 parent 1c49b25 commit cf35d2d
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 11 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ Notice that nearly every feature below has at least subtle differences from Java
<td>
✔ Unescaped <code>-</code> outside of range is literal in some contexts (different than JS rules in any mode)<br>
✔ Error for unescaped <code>[</code> that doesn't form nested class<br>
✔ Allows leading unescaped <code>]</code><br>
✔ Fewer chars require escaping than JS<br>
</td>
</tr>
Expand All @@ -564,7 +565,6 @@ Notice that nearly every feature below has at least subtle differences from Java
<td align="middle">✅</td>
<td>
✔ Error<br>
✔ Doesn't allow leading unescaped <code>]</code><br>
</td>
</tr>
<tr valign="top">
Expand Down Expand Up @@ -921,7 +921,7 @@ The table above doesn't include all aspects that Oniguruma-To-ES emulates (inclu
3. With target `ES2018`, the specific POSIX classes `[:graph:]` and `[:print:]` use ASCII-based versions rather than the Unicode versions available for target `ES2024` and later, and they result in an error if using strict `accuracy`.
4. Target `ES2018` doesn't support nested *negated* character classes.
5. It's not an error for *numbered* backreferences to come before their referenced group in Oniguruma, but an error is the best path for Oniguruma-To-ES because (1) most placements are mistakes and can never match (based on the Oniguruma behavior for backreferences to nonparticipating groups), (2) erroring matches the behavior of named backreferences, and (3) the edge cases where they're matchable rely on rules for backreference resetting within quantified groups that are different in JavaScript and aren't emulatable. Note that it's not a backreference in the first place if using `\10` or higher and not as many capturing groups are defined to the left (it's an octal or identity escape).
6. The recursion depth limit is specified by option `maxRecursionDepth`. Use of backreferences with recursion isn't yet supported. Patterns that would error in Oniguruma due to triggering infinite recursion might find a match in Oniguruma-To-ES since recursion is bounded (future versions will detect this and error at transpilation time).
6. The recursion depth limit is specified by option `maxRecursionDepth`. Use of backreferences when the recursed subpattern contains captures isn't yet supported. Patterns that would error in Oniguruma due to triggering infinite recursion might find a match in Oniguruma-To-ES since recursion is bounded (future versions will detect this and error at transpilation time).

## ❌ Unsupported features

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"dependencies": {
"emoji-regex-xs": "^1.0.0",
"regex": "^5.0.2",
"regex-recursion": "^4.2.1"
"regex-recursion": "^4.3.0"
},
"devDependencies": {
"esbuild": "^0.24.0",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 9 additions & 3 deletions spec/match-recursion.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,16 @@ describe('Recursion', () => {
});

// Documenting current behavior
it('should throw if recursion used with backref', () => {
it('should throw if backref used with recursion when the recursed subpattern contains captures', () => {
expect(() => toDetails(r`(a)\1\g<0>?`)).toThrow();
expect(() => toDetails(r`(a\g<1>?)\k<1>`)).toThrow();
expect(() => toDetails(r`(?<a>a\g<a>?)(?<b>)\k<b>`)).toThrow();
expect(() => toDetails(r`((a)\g<1>?)\k<1>`)).toThrow();
expect(() => toDetails(r`((a)\g<1>?)()\k<3>`)).toThrow();
});

it('should match backref used with recursion when the recursed subpattern contains no captures', () => {
expect('aaabaaa').toExactlyMatch(r`(a\g<1>?)b\k<1>`);
expect('aaabaaa').toExactlyMatch(r`(?<a>a\g<a>?)b\k<a>`);
expect('aaabb').toExactlyMatch(r`(?<a>a\g<a>?)(?<b>b)\k<b>`);
});

describe('global', () => {
Expand Down

0 comments on commit cf35d2d

Please sign in to comment.