├── .gitattributes ├── .npmrc ├── .gitignore ├── .vscode ├── settings.json └── tasks.json ├── .github └── workflows │ ├── pr.yml │ └── build.yml ├── spec └── index.html ├── package.json ├── gulpfile.js ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | docs -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[markdown]": { 3 | "files.trimTrailingWhitespace": false 4 | } 5 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "gulp", 8 | "task": "build", 9 | "group": { 10 | "kind": "build", 11 | "isDefault": true 12 | } 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: Publish Spec to gh-pages 2 | on: 3 | push: 4 | branches: [ main ] 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - run: npm install 11 | - run: npm run build 12 | - name: Deploy 13 | uses: JamesIves/github-pages-deploy-action@4.1.4 14 | with: 15 | branch: gh-pages 16 | folder: docs 17 | clean-exclude: | 18 | pr 19 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Publish Spec to gh-pages 2 | on: 3 | push: 4 | branches: [ main ] 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - run: npm install 11 | - run: npm run build 12 | - name: Deploy 13 | uses: JamesIves/github-pages-deploy-action@4.1.4 14 | with: 15 | branch: gh-pages 16 | folder: docs 17 | clean-exclude: | 18 | pr 19 | -------------------------------------------------------------------------------- /spec/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
 7 | title: Proposal Title Goes Here
 8 | stage: -1
 9 | contributors: Your Name(s) Here
10 | 
11 | 12 | 13 |

This is an emu-clause

14 |

This is an algorithm:

15 | 16 | 1. Let _proposal_ be *undefined*. 17 | 1. If IsAccepted(_proposal_), 18 | 1. Let _stage_ be *0*. 19 | 1. Else, 20 | 1. Let _stage_ be *-1*. 21 | 1. Return ? ToString(_proposal_). 22 | 23 |
24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "proposal-regexp-features", 3 | "version": "0.0.0", 4 | "private": true, 5 | "description": "Proposal to investigate additional language features for ECMAScript Regular Expressions", 6 | "homepage": "https://github.com/rbuckton/proposal-regexp-features#readme", 7 | "author": { 8 | "name": "Ron Buckton", 9 | "email": "ron.buckton@microsoft.com" 10 | }, 11 | "keywords": [ 12 | "javascript", 13 | "ecmascript" 14 | ], 15 | "scripts": { 16 | "build": "gulp build", 17 | "start": "gulp start" 18 | }, 19 | "license": "MIT", 20 | "devDependencies": { 21 | "del": "^5.1.0", 22 | "ecmarkup": "^8.1.0", 23 | "gulp": "^4.0.2", 24 | "gulp-emu": "^2.0.0", 25 | "gulp-live-server": "0.0.31" 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/rbuckton/proposal-regexp-features.git" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const del = require("del"); 2 | const path = require("path"); 3 | const gulp = require("gulp"); 4 | const emu = require("gulp-emu"); 5 | const gls = require("gulp-live-server"); 6 | 7 | gulp.task("clean", () => del("docs/**/*")); 8 | 9 | gulp.task("build", () => gulp 10 | .src(["spec/index.html"]) 11 | .pipe(emu({ ecma262Biblio: false, js: true, css: true })) 12 | .pipe(gulp.dest("docs"))); 13 | 14 | gulp.task("watch", () => gulp 15 | .watch(["spec/**/*"], gulp.task("build"))); 16 | 17 | gulp.task("start", gulp.parallel(gulp.task("watch"), () => { 18 | const server = gls.static("docs", 8080); 19 | const promise = server.start(); 20 | (/** @type {import("chokidar").FSWatcher}*/(gulp.watch(["docs/**/*"]))) 21 | .on("change", file => { 22 | server.notify({ path: path.resolve(file) }); 23 | }); 24 | return promise; 25 | })); 26 | 27 | gulp.task("default", gulp.task("build")); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 ECMA TC39 and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # ECMAScript Regular Expression Language Features 3 | 4 | This seeks to investigate and introduce new features to the ECMAScript `RegExp` object based on features available commonly in other languages. 5 | 6 | 7 | 8 | 9 | ## Status 10 | 11 | **Stage:** 0 12 | **Champion:** Ron Buckton (@rbuckton) 13 | 14 | _For detailed status of this proposal see [TODO](#todo), below._ 15 | 16 | 17 | 18 | ## Authors 19 | 20 | * Ron Buckton ([@rbuckton](https://github.com/rbuckton)) 21 | 22 | 23 | 24 | # Motivations 25 | 26 | ECMAScript regular expressions have slowly improved over the years to adopt new functionality commonly present in other languages, including: 27 | 28 | - Unicode Support 29 | - Named Capture Groups 30 | - Match Indices 31 | 32 | However, a large majority of other languages and libraries have a common set of features that ECMAScript regular expressions currently lack. 33 | Some of these features improve performance in degenerative cases such as backtracking in complex patterns. Some of these features introduce 34 | new tools for developers to write more powerful regular expressions. 35 | 36 | As a result, ECMAScript developers wishing to leverage these capabilities are left with few options, relying on native bindings to third-party 37 | libraries in environments such as NodeJS, or server-side evaluation. 38 | 39 | There are numerous applications for extending the ECMAScript regular expression feature set, including: 40 | 41 | - In-browser support for TextMate grammars for web based editors/IDEs. 42 | - Improved performance for expressions through possessive quantifiers and backtracking control. 43 | - RegExp-based parsers that can support balanced brackets/parens. 44 | - Documenting complex patterns *in the pattern itself*. 45 | - Improved readability through the use of multi-line patterns and insignificant whitespace. 46 | 47 | 48 | 49 | 50 | 56 | 57 | 58 | 59 | # Syntax 60 | 61 | This proposal seeks to investiage multiple additions to the ECMAScript regular expression syntax based on features commonly available in 62 | other languages and engines. This work is based on the research at https://rbuckton.github.io/regexp-features/, which is an ongoing effort 63 | to document the commonalities and differences of various features in popular regular expression engines. This proposal does not seek to 64 | implement *all* of the proposed syntax, but to investigate each feature to determine its applicability to ECMAScript. Where possible, 65 | we will indicate whether the syntax described should be considered *definitive* (i.e., the specific syntax is not subject to change should 66 | the feature be adopted), or *proposed* (i.e., the specific syntax is open for debate). 67 | 68 | Definitive syntax is that which is generally-consistent with all engines that implement the functionality, 69 | such that a change to the syntax would have a net-negative effect when considering compatibility with other engines (such as would be the 70 | case with TextMate grammars, patterns commonly used in documentation to describe a valid input, etc.). 71 | 72 | Proposed syntax is that which is inconsistent between the various engines that implement similar 73 | functionality, such that a change to the syntax to fit ECMAScript requirements would not likely be a compatiblity concern. 74 | 75 | ## Flags 76 | 77 | ### Explicit capture mode (`n`) 78 | 79 | **Status:** [Definitive][] 80 | 81 | **Prior Art:** Perl, PCRE, .NET ([feature comparison](https://rbuckton.github.io/regexp-features/features/flags.html)) 82 | 83 | The explicit capture mode (`n`) flag affects capturing behavior, such that normal capture groups (i.e., `()`) are treated as non-capturing groups. Only named capture groups are returned. 84 | 85 | > NOTE: The `n`-mode flag can be used inside of a [Modifier](#modifiers). 86 | 87 | #### API 88 | 89 | - `RegExp.prototype.explicitCapture` (Boolean) — Indicates whether the `n`-mode flag is set. 90 | 91 | ### Extended mode (`x`) 92 | 93 | **Status:** [Definitive][] 94 | 95 | **Prior Art:** Perl, PCRE, Boost.Regex, .NET, Oniguruma, Hyperscan, ICU, Glib/GRegex ([feature comparison](https://rbuckton.github.io/regexp-features/features/flags.html)) 96 | 97 | The extended mode (`x`) flag treats unescaped whitespace characters as insignificant, allowing for multi-line regular expressions. It also enables [Line Comments](#line-comments). 98 | 99 | > NOTE: The `x`-mode flag can be used inside of a [Modifier](#modifiers) 100 | 101 | > NOTE: While the `x`-mode flag can be used in a _RegularExpressionLiteral_, it does not permit the use of _LineTerminator_ in _RegularExpressonLiteral_. For multi-line 102 | > regular expressions you would need to use the `RegExp` constructor. 103 | 104 | > NOTE: Perl's original `x`-mode treated whitespace as insignificant anywhere within a pattern *except* for within character classes. Perl v5.26 introduced the `xx` flag which 105 | > also ignores non-escaped SPACE and TAB characters. Should we chose to adopt the `x`-mode flag, we could opt to treat it as Perl's `xx` mode at the outset. 106 | 107 | #### API 108 | 109 | - `RegExp.prototype.extended` (Boolean) — Indicates the `x`-mode flag is set. 110 | 111 | ## Modifiers 112 | 113 | **Status:** [Definitive][] 114 | 115 | **Prior Art:** Perl, PCRE, Boost.Regex, .NET, Oniguruma, Hyperscan, ICU, Glib/GRegex ([feature comparison](https://rbuckton.github.io/regexp-features/features/modifiers.html)) 116 | 117 | Modifiers allow you to change the currently active RegExp flags within a subexpression. 118 | 119 | - `(?imnsux-imnsux)` — Sets or unsets (using `-`) the specified RegExp flags starting at the current position until the next closing `)` or the end of the pattern. 120 | - `(?imnsux-imnsux:subexpression)` — Sets or unsets (using `-`) the specified RegExp flags for the subexpression. 121 | 122 | > NOTE: Certain flags cannot be modified mid-expression. These currently include `g` (global), `y` (sticky), and `d` (hasIndices). 123 | 124 | > NOTE: This has no conflicts with existing syntax, as ECMAScript currently produces an error for this syntax in both `u` and non-`u` modes. 125 | 126 | #### Example 127 | 128 | ```js 129 | const re1 = /^(?i)[a-z](?-i)[a-z]$/; 130 | re1.test("ab"); // true 131 | re1.test("Ab"); // true 132 | re1.test("aB"); // false 133 | 134 | const re2 = /^(?i:[a-z](?-i:[a-z]))$/; 135 | re2.test("ab"); // true 136 | re2.test("Ab"); // true 137 | re2.test("aB"); // false 138 | ``` 139 | 140 | ## Comments 141 | 142 | **Status:** [Definitive][] 143 | 144 | **Prior Art:** Perl, PCRE, Boost.Regex, .NET, Oniguruma, Hyperscan, ICU, Glib/GRegex ([feature comparison](https://rbuckton.github.io/regexp-features/features/comments.html)) 145 | 146 | A comment is a sequence of characters that is ignored by pattern matching and can be used to document a pattern. 147 | 148 | - `(?#comment)` — The entire expression is removed from the pattern. The text of *comment* may not contain other `(` or `)` characters. 149 | 150 | > NOTE: This has no conflicts with existing syntax, as ECMAScript currently produces an error for this syntax in both `u` and non-`u` modes. 151 | 152 | #### Example 153 | 154 | ```js 155 | const re = /foo(?#comment)bar/; 156 | re.test("foobar"); // true 157 | ``` 158 | 159 | ## Line Comments 160 | 161 | **Status:** [Definitive][] 162 | 163 | **Prior Art:** Perl, PCRE, .NET, ICU, Glib/GRegex ([feature comparison](https://rbuckton.github.io/regexp-features/features/line-comments.html)) 164 | 165 | A Line Comment is a sequence of characters starting with `#` and ending with `\n` (or the end of the pattern) that is ignored by pattern matching and can be used to document a pattern. 166 | 167 | - `# comment` — A line comment in a multi-line RegExp 168 | 169 | > NOTE: Requires the `x`-mode [flag](#extended-mode-x). 170 | 171 | > NOTE: Inside of `x`-mode, the `#` character must be escaped (using `\#`) outside of a character class. 172 | 173 | #### Example 174 | 175 | ```js 176 | const re = new RegExp(String.raw` 177 | # match ASCII alpha-numerics 178 | [a-zA-Z0-9] 179 | `, "x"); 180 | ``` 181 | 182 | ## Buffer Boundaries 183 | 184 | **Status:** [Definitive][] 185 | 186 | **Prior Art:** Perl, PCRE, Boost.Regex, .NET, Oniguruma, Hyperscan, ICU, Glib/GRegex ([feature comparison](https://rbuckton.github.io/regexp-features/features/buffer-boundaries.html)) 187 | 188 | Buffer boundaries are similar to the `^` and `$` anchors, except that they are not affected by the `m` (multiline) flag: 189 | 190 | - `\A` — Matches the start of the input. 191 | - `\z` — Matches the end of the input. 192 | - `\Z` — A zero-width assertion consisting of an optional newline at the end of the buffer. Equivalent to (?=\n?\z). 193 | 194 | > NOTE: Requires the `u` flag, as `\A`, `\z`, and `\Z` are currently just escapes for `A`, `z` and `Z` without the `u` flag. 195 | 196 | > NOTE: Not supported inside of a character class. 197 | 198 | 199 | ## Line Endings Escape 200 | 201 | **Status:** [Definitive][] 202 | 203 | **Prior Art:** Perl, PCRE, Boost.Regex, Oniguruma, ICU, Glib/GRegex ([feature comparison](https://rbuckton.github.io/regexp-features/features/line-endings-escape.html)) 204 | 205 | - `\R` — Matches any [line ending character sequence per UTS#18](https://unicode.org/reports/tr18/#Line_Boundaries). Equivalent to: `(?>\r\n?|[\x0A-\x0C\x85\u{2028}\u{2029}])` (see [Atomic Groups](#atomic-groups)) 206 | 207 | > NOTE: Requires the `u` flag, as `\R` is currently just an escape for `R` without the `u` flag. 208 | 209 | > NOTE: Not supported inside of a character class. 210 | 211 | ## Possessive Quantifiers 212 | 213 | **Status:** [Definitive][] 214 | 215 | **Prior Art:** Perl, PCRE, Boost.Regex, Oniguruma, ICU, Glib/GRegex ([feature comparison](https://rbuckton.github.io/regexp-features/features/possessive-quantifiers.html)) 216 | 217 | Possessive quantifiers are like normal (a.k.a. "greedy") quantifiers, but do not backtrack if the rest of the pattern to the right fails to match. Possessive quantifiers are often used as a performance tweak to avoid expensive backtracking in a complex pattern. 218 | 219 | - `*+` — Match zero or more instances of the preceding atom without backtracking. 220 | - `++` — Match one or more instances of the preceding atom without backtracking. 221 | - `?+` — Match zero or one instances of the preceding atom without backtracking. 222 | - `{n,}+` — Where _n_ is an integer. Matches the preceding atom at-least _n_ times without backtracking. 223 | - `{n,m}+` — Where _n_ and _m_ are integers, and _m_ >= _n_. Matches the preceding atom at-least _n_ times and at-most _m_ times without backtracking. 224 | 225 | > NOTE: This has no conflicts with existing syntax, as ECMAScript currently produces an error for this syntax in both `u` and non-`u` modes. 226 | 227 | ## Atomic Groups 228 | 229 | **Status:** [Definitive][] 230 | 231 | **Prior Art:** Perl, PCRE, Boost.Regex, .NET, Oniguruma, ICU, Glib/GRegex ([feature comparison](https://rbuckton.github.io/regexp-features/features/non-backtracking-expressions.html)) 232 | 233 | An Atomic Group is a non-backtracking expression which is matched independent of neighboring patterns, and will not backtrack in the event of a failed match. This is often used to improve performance. 234 | 235 | - `(?>pattern)` — Matches the provided pattern, but no backtracking is performed if the match fails. 236 | 237 | > NOTE: This has no conflicts with existing syntax, as ECMAScript currently produces an error for this syntax in both `u` and non-`u` modes. 238 | 239 | #### Example 240 | 241 | ```js 242 | // NOTE: x-mode flag used to illustrate difference 243 | // without atomic groups: 244 | const re1 = /\(( [^()]+ | \([^()]*\))+ \)/x; 245 | re1.test("((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // can take several seconds to fail 246 | 247 | // with atomic groups 248 | const re2 = /\(( (?> [^()]+ ) | \([^()]*\))+ \)/x; 249 | re2.test("((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // significantly faster as less backtracking is involved 250 | ``` 251 | 252 | ## Conditional Expressions 253 | 254 | **Status:** [Definitive][]/[Proposed][] (depending on condition, see below) 255 | 256 | **Prior Art:** Perl, PCRE, Boost.Regex, .NET, Oniguruma, Glib/GRegex ([feature comparison](https://rbuckton.github.io/regexp-features/features/conditional-expressions.html)) 257 | 258 | A Conditional Expression checks a condition and evaluates its first alternative if the condition is true; otherwise, it evaluates its second alternative. 259 | 260 | - `(?(condition)yes-pattern|no-pattern)` — Matches yes-pattern if condition is true; otherwise, matches no-pattern. 261 | - `(?(condition)yes-pattern)` — Matches yes-pattern if condition is true; otherwise, matches the empty string. 262 | 263 | > NOTE: This has no conflicts with existing syntax, as ECMAScript currently produces an error for this syntax in both `u` and non-`u` modes. 264 | 265 | ### Conditions 266 | 267 | The following conditions are proposed: 268 | 269 | - `(?=test-pattern)` — Evaluates to **true** if a positive lookahead for test-pattern matches; Otherwise, evaluates to **false**. 270 | - **Status**: [Definitive][] 271 | - `(?<=test-pattern)` — Evaluates to **true** if a positive lookbehind for test-pattern matches; Otherwise, evaluates to **false**. 272 | - **Status**: [Proposed][] (backtracking not supported in all engines) 273 | - `(?!test-pattern)` — Evaluates to **true** if a negative lookahead for test-pattern matches; Otherwise, evaluates to **false**. 274 | - **Status**: [Definitive][] 275 | - `(?)` — Evaluates to **true** if the named capture group with the provided _name_ was successfully matched; Otherwise, evaluates to **false**. 280 | - **Status**: [Definitive][] 281 | - `('name')` — Evaluates to **true** if the named capture group with the provided _name_ was successfully matched; Otherwise, evaluates to **false**. 282 | - **Status**: [Definitive][] 283 | - `(R)` — Evaluates to **true** if inside a recursive expression; Otherwise, evaluates to **false**. 284 | - **Status**: [Proposed][] ([recursion](#recursion) not supported in all engines) 285 | - `(Rn)` — Evaluates to **true** if inside a recursive expression for the capture group at offset n; Otherwise, evaluates to **false**. 286 | - **Status**: [Proposed][] ([recursion](#recursion) not supported in all engines) 287 | - `(R&name)` — Evaluates to **true** if inside a recursive expression for the named capture group with the provided name; Otherwise, evaluates to **false**. 288 | - **Status**: [Proposed][] ([recursion](#recursion) not supported in all engines) 289 | - `(DEFINE)` — Always evaluates to **false**. This allows you to define Subroutines. 290 | - **Status**: [Proposed][] ([subroutines](#subroutines) not supported in all engines) 291 | 292 | #### Example 293 | 294 | ```js 295 | // conditional using lookahead: 296 | const re1 = /^(?(?=\{)\{[0-9a-f]+\}|[0-9a-f]{4})$/ 297 | re1.test("0000"); // true 298 | re1.test("{0}"); // true 299 | re1.test("{00000000}"); // true 300 | 301 | // match optional brackets 302 | const re2 = /(?\[)?(?[^\]]+)(?()\]))/; 303 | re1.test("abc"); // true 304 | re1.test("[abc]"); // true 305 | re1.test("[abc"); // false 306 | ``` 307 | 308 | ## Subroutines 309 | 310 | **Status:** [Proposed][] (some engines use differing syntax) 311 | 312 | **Prior Art:** Perl, PCRE, Boost.Regex, Oniguruma, Glib/GRegex ([feature comparison](https://rbuckton.github.io/regexp-features/features/subroutines.html)) 313 | 314 | A Subroutine is a pre-defined capture group or named capture group that can be reused in multiple places within the pattern to re-evaluate the subexpression from the referenced group. 315 | 316 | - `(?n)` — Where _n_ is an integer >= 1. Evaluates the capture group whose offset is _n_. 317 | - `(?-n)` — Where _n_ is an integer >= 1. Evaluates the capture group whose offset is the _n_th capture group declared to the left of the current atom. 318 | - `(?+n)` — Where _n_ is an integer >= 1. Evaluates the capture group whose offset is the _n_th capture group declared to the right of the current atom. 319 | - `(?&name)` — Evaluates the named capture group with the provided name. 320 | 321 | > NOTE: Subroutines also allow [Recursion](#recursion). 322 | 323 | > NOTE: This has no conflicts with existing syntax, as ECMAScript currently produces an error for this syntax in both `u` and non-`u` modes. 324 | 325 | #### Example 326 | 327 | ```js 328 | const iso8601DateRegExp = new RegExp(String.raw` 329 | (?(DEFINE) 330 | (?\d{4}|[+-]\d{5,}) 331 | (?0[1-9]|1[0-2]) 332 | (?0[1-9]|2[0-9]|3[01]) 333 | ) 334 | (?(?&Year)-(?&Month)-(?&Day)|(?&Year)(?&Month)(?&Day)) 335 | `, "x"); 336 | ``` 337 | 338 | ## Recursion 339 | 340 | **Status:** [Proposed][] (some engines use differing syntax) 341 | 342 | **Prior Art:** Perl, PCRE, Boost.Regex, Oniguruma, Glib/GRegex ([feature comparison](https://rbuckton.github.io/regexp-features/features/recursion.html)) 343 | 344 | A Recursive Expression provides a mechanism for re-evaluating a capture group inside of itself, to handle cases such as matching balanced parenthesis or brackets, etc. 345 | 346 | - `(?R)`, `(?0)` — Reevaluates the entire pattern starting at the current position. 347 | 348 | > NOTE: This has no conflicts with existing syntax, as ECMAScript currently produces an error for this syntax in both `u` and non-`u` modes. 349 | 350 | 351 | 352 | 353 | 357 | 358 | 359 | 360 | 361 | 365 | 366 | 367 | 368 | 372 | 373 | 374 | 375 | 384 | 385 | 386 | 387 | # References 388 | 389 | - [Regular Expression Feature Comparison](https://rbuckton.github.io/regexp-features/) 390 | 391 | 392 | 393 | 394 | 401 | 402 | 403 | 404 | # TODO 405 | 406 | The following is a high-level list of tasks to progress through each stage of the [TC39 proposal process](https://tc39.github.io/process-document/): 407 | 408 | ### Stage 1 Entrance Criteria 409 | 410 | * [x] Identified a "[champion][Champion]" who will advance the addition. 411 | * [ ] [Prose][Prose] outlining the problem or need and the general shape of a solution. 412 | * [x] Illustrative [examples][Examples] of usage. 413 | * [x] High-level [API][API]. 414 | 415 | ### Stage 2 Entrance Criteria 416 | 417 | * [ ] [Initial specification text][Specification]. 418 | * [ ] [Transpiler support][Transpiler] (_Optional_). 419 | 420 | ### Stage 3 Entrance Criteria 421 | 422 | * [ ] [Complete specification text][Specification]. 423 | * [ ] Designated reviewers have [signed off][Stage3ReviewerSignOff] on the current spec text. 424 | * [ ] The ECMAScript editor has [signed off][Stage3EditorSignOff] on the current spec text. 425 | 426 | ### Stage 4 Entrance Criteria 427 | 428 | * [ ] [Test262](https://github.com/tc39/test262) acceptance tests have been written for mainline usage scenarios and [merged][Test262PullRequest]. 429 | * [ ] Two compatible implementations which pass the acceptance tests: 430 | * [ ] [_Pending_][Implementation1] 431 | * [ ] [_Pending_][Implementation2] 432 | * [ ] A [pull request][Ecma262PullRequest] has been sent to tc39/ecma262 with the integrated spec text. 433 | * [ ] The ECMAScript editor has signed off on the [pull request][Ecma262PullRequest]. 434 | 435 | 436 | [Process]: https://tc39.github.io/process-document/ 437 | [Proposals]: https://github.com/tc39/proposals/ 438 | [Grammarkdown]: http://github.com/rbuckton/grammarkdown#readme 439 | [Champion]: #status 440 | [Prose]: #motivations 441 | [Examples]: #examples 442 | [API]: #api 443 | [Specification]: #todo 444 | [Transpiler]: #todo 445 | [Stage3ReviewerSignOff]: #todo 446 | [Stage3EditorSignOff]: #todo 447 | [Test262PullRequest]: #todo 448 | [Implementation1]: #todo 449 | [Implementation2]: #todo 450 | [Ecma262PullRequest]: #todo 451 | [Definitive]: #definitive-syntax 452 | [Proposed]: #proposed-syntax 453 | --------------------------------------------------------------------------------